summaryrefslogtreecommitdiffstats
path: root/WebCore/websockets/WebSocketHandshake.cpp
diff options
context:
space:
mode:
authorKristian Monsen <kristianm@google.com>2010-06-28 16:42:48 +0100
committerKristian Monsen <kristianm@google.com>2010-07-02 10:29:56 +0100
commit06ea8e899e48f1f2f396b70e63fae369f2f23232 (patch)
tree20c1428cd05c76f32394ab354ea35ed99acd86d8 /WebCore/websockets/WebSocketHandshake.cpp
parent72aad67af14193199e29cdd5c4ddc095a8b9a8a8 (diff)
downloadexternal_webkit-06ea8e899e48f1f2f396b70e63fae369f2f23232.zip
external_webkit-06ea8e899e48f1f2f396b70e63fae369f2f23232.tar.gz
external_webkit-06ea8e899e48f1f2f396b70e63fae369f2f23232.tar.bz2
Merge WebKit at r61871: Initial merge by git.
Change-Id: I6cff43abca9cc4782e088a469ad4f03f166a65d5
Diffstat (limited to 'WebCore/websockets/WebSocketHandshake.cpp')
-rw-r--r--WebCore/websockets/WebSocketHandshake.cpp183
1 files changed, 110 insertions, 73 deletions
diff --git a/WebCore/websockets/WebSocketHandshake.cpp b/WebCore/websockets/WebSocketHandshake.cpp
index ea4f5e5..ba14732 100644
--- a/WebCore/websockets/WebSocketHandshake.cpp
+++ b/WebCore/websockets/WebSocketHandshake.cpp
@@ -35,6 +35,7 @@
#include "WebSocketHandshake.h"
#include "AtomicString.h"
+#include "CharacterNames.h"
#include "Cookie.h"
#include "CookieJar.h"
#include "Document.h"
@@ -56,28 +57,6 @@ namespace WebCore {
static const char randomCharacterInSecWebSocketKey[] = "!\"#$%&'()*+,-./:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
-static String extractResponseCode(const char* header, int len, size_t& lineLength)
-{
- const char* space1 = 0;
- const char* space2 = 0;
- const char* p;
- lineLength = 0;
- for (p = header; p - header < len; p++, lineLength++) {
- if (*p == ' ') {
- if (!space1)
- space1 = p;
- else if (!space2)
- space2 = p;
- } else if (*p == '\n')
- break;
- }
- if (p - header == len)
- return String();
- if (!space1 || !space2)
- return "";
- return String(space1 + 1, space2 - space1 - 1);
-}
-
static String resourceName(const KURL& url)
{
String name = url.path();
@@ -102,11 +81,12 @@ static String hostName(const KURL& url, bool secure)
return builder.toString();
}
+static const size_t maxConsoleMessageSize = 128;
static String trimConsoleMessage(const char* p, size_t len)
{
- String s = String(p, std::min<size_t>(len, 128));
- if (len > 128)
- s += "...";
+ String s = String(p, std::min<size_t>(len, maxConsoleMessageSize));
+ if (len > maxConsoleMessageSize)
+ s.append(horizontalEllipsis);
return s;
}
@@ -279,17 +259,27 @@ WebSocketHandshakeRequest WebSocketHandshake::clientHandshakeRequest() const
// Keep the following consistent with clientHandshakeMessage().
// FIXME: do we need to store m_secWebSocketKey1, m_secWebSocketKey2 and
// m_key3 in WebSocketHandshakeRequest?
- WebSocketHandshakeRequest request(m_url, clientOrigin(), m_clientProtocol);
+ WebSocketHandshakeRequest request("GET", m_url);
+ request.addHeaderField("Upgrade", "WebSocket");
+ request.addHeaderField("Connection", "Upgrade");
+ request.addHeaderField("Host", hostName(m_url, m_secure));
+ request.addHeaderField("Origin", clientOrigin());
+ if (!m_clientProtocol.isEmpty())
+ request.addHeaderField("Sec-WebSocket-Protocol:", m_clientProtocol);
KURL url = httpURLForAuthenticationAndCookies();
if (m_context->isDocument()) {
Document* document = static_cast<Document*>(m_context);
String cookie = cookieRequestHeaderFieldValue(document, url);
if (!cookie.isEmpty())
- request.addExtraHeaderField("Cookie", cookie);
+ request.addHeaderField("Cookie", cookie);
// Set "Cookie2: <cookie>" if cookies 2 exists for url?
}
+ request.addHeaderField("Sec-WebSocket-Key1", m_secWebSocketKey1);
+ request.addHeaderField("Sec-WebSocket-Key2", m_secWebSocketKey2);
+ request.setKey3(m_key3);
+
return request;
}
@@ -312,21 +302,21 @@ void WebSocketHandshake::clearScriptExecutionContext()
int WebSocketHandshake::readServerHandshake(const char* header, size_t len)
{
m_mode = Incomplete;
- size_t lineLength;
- const String& code = extractResponseCode(header, len, lineLength);
- if (code.isNull()) {
- // Just hasn't been received yet.
+ int statusCode;
+ String statusText;
+ int lineLength = readStatusLine(header, len, statusCode, statusText);
+ if (lineLength == -1)
return -1;
- }
- if (code.isEmpty()) {
+ if (statusCode == -1) {
m_mode = Failed;
- m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "No response code found: " + trimConsoleMessage(header, lineLength), 0, clientOrigin());
return len;
}
- LOG(Network, "response code: %s", code.utf8().data());
- if (code != "101") {
+ LOG(Network, "response code: %d", statusCode);
+ m_response.setStatusCode(statusCode);
+ m_response.setStatusText(statusText);
+ if (statusCode != 101) {
m_mode = Failed;
- m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Unexpected response code:" + code, 0, clientOrigin());
+ m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, String::format("Unexpected response code: %d", statusCode), 0, clientOrigin());
return len;
}
m_mode = Normal;
@@ -335,17 +325,14 @@ int WebSocketHandshake::readServerHandshake(const char* header, size_t len)
m_mode = Incomplete;
return -1;
}
- HTTPHeaderMap headers;
- const char* headerFields = strnstr(header, "\r\n", len); // skip status line
- ASSERT(headerFields);
- headerFields += 2; // skip "\r\n".
- const char* p = readHTTPHeaders(headerFields, header + len, &headers);
+ const char* p = readHTTPHeaders(header + lineLength, header + len);
if (!p) {
LOG(Network, "readHTTPHeaders failed");
m_mode = Failed;
return len;
}
- if (!processHeaders(headers) || !checkResponseHeaders()) {
+ processHeaders();
+ if (!checkResponseHeaders()) {
LOG(Network, "header process failed");
m_mode = Failed;
return p - header;
@@ -355,6 +342,7 @@ int WebSocketHandshake::readServerHandshake(const char* header, size_t len)
m_mode = Incomplete;
return -1;
}
+ m_response.setChallengeResponse(static_cast<const unsigned char*>(static_cast<const void*>(p)));
if (memcmp(p, m_expectedChallengeResponse, sizeof(m_expectedChallengeResponse))) {
m_mode = Failed;
return (p - header) + sizeof(m_expectedChallengeResponse);
@@ -418,6 +406,11 @@ void WebSocketHandshake::setServerSetCookie2(const String& setCookie2)
m_setCookie2 = setCookie2;
}
+const WebSocketHandshakeResponse& WebSocketHandshake::serverHandshakeResponse() const
+{
+ return m_response;
+}
+
KURL WebSocketHandshake::httpURLForAuthenticationAndCookies() const
{
KURL url = m_url.copy();
@@ -426,8 +419,70 @@ KURL WebSocketHandshake::httpURLForAuthenticationAndCookies() const
return url;
}
-const char* WebSocketHandshake::readHTTPHeaders(const char* start, const char* end, HTTPHeaderMap* headers)
+// Returns the header length (including "\r\n"), or -1 if we have not received enough data yet.
+// If the line is malformed or the status code is not a 3-digit number,
+// statusCode and statusText will be set to -1 and a null string, respectively.
+int WebSocketHandshake::readStatusLine(const char* header, size_t headerLength, int& statusCode, String& statusText)
{
+ statusCode = -1;
+ statusText = String();
+
+ const char* space1 = 0;
+ const char* space2 = 0;
+ const char* p;
+ size_t consumedLength;
+
+ for (p = header, consumedLength = 0; consumedLength < headerLength; p++, consumedLength++) {
+ if (*p == ' ') {
+ if (!space1)
+ space1 = p;
+ else if (!space2)
+ space2 = p;
+ } else if (*p == '\n')
+ break;
+ }
+ if (consumedLength == headerLength)
+ return -1; // We have not received '\n' yet.
+
+ const char* end = p + 1;
+ if (end - header > INT_MAX) {
+ m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Status line is too long: " + trimConsoleMessage(header, maxConsoleMessageSize + 1), 0, clientOrigin());
+ return INT_MAX;
+ }
+ int lineLength = end - header;
+
+ if (!space1 || !space2) {
+ m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "No response code found: " + trimConsoleMessage(header, lineLength - 1), 0, clientOrigin());
+ return lineLength;
+ }
+
+ // The line must end with "\r\n".
+ if (*(end - 2) != '\r') {
+ m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Status line does not end with CRLF", 0, clientOrigin());
+ return lineLength;
+ }
+
+ String statusCodeString(space1 + 1, space2 - space1 - 1);
+ if (statusCodeString.length() != 3) // Status code must consist of three digits.
+ return lineLength;
+ for (int i = 0; i < 3; ++i)
+ if (statusCodeString[i] < '0' || statusCodeString[i] > '9') {
+ m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Invalid status code: " + statusCodeString, 0, clientOrigin());
+ return lineLength;
+ }
+
+ bool ok = false;
+ statusCode = statusCodeString.toInt(&ok);
+ ASSERT(ok);
+
+ statusText = String(space2 + 1, end - space2 - 3); // Exclude "\r\n".
+ return lineLength;
+}
+
+const char* WebSocketHandshake::readHTTPHeaders(const char* start, const char* end)
+{
+ m_response.clearHeaderFields();
+
Vector<char> name;
Vector<char> value;
for (const char* p = start; p < end; p++) {
@@ -451,10 +506,7 @@ const char* WebSocketHandshake::readHTTPHeaders(const char* start, const char* e
case ':':
break;
default:
- if (*p >= 0x41 && *p <= 0x5a)
- name.append(*p + 0x20);
- else
- name.append(*p);
+ name.append(*p);
continue;
}
if (*p == ':') {
@@ -495,36 +547,21 @@ const char* WebSocketHandshake::readHTTPHeaders(const char* start, const char* e
return 0;
}
LOG(Network, "name=%s value=%s", nameStr.string().utf8().data(), valueStr.utf8().data());
- headers->add(nameStr, valueStr);
+ m_response.addHeaderField(nameStr, valueStr);
}
ASSERT_NOT_REACHED();
return 0;
}
-bool WebSocketHandshake::processHeaders(const HTTPHeaderMap& headers)
-{
- for (HTTPHeaderMap::const_iterator it = headers.begin(); it != headers.end(); ++it) {
- switch (m_mode) {
- case Normal:
- if (it->first == "sec-websocket-origin")
- m_wsOrigin = it->second;
- else if (it->first == "sec-websocket-location")
- m_wsLocation = it->second;
- else if (it->first == "sec-websocket-protocol")
- m_wsProtocol = it->second;
- else if (it->first == "set-cookie")
- m_setCookie = it->second;
- else if (it->first == "set-cookie2")
- m_setCookie2 = it->second;
- continue;
- case Incomplete:
- case Failed:
- case Connected:
- ASSERT_NOT_REACHED();
- }
- ASSERT_NOT_REACHED();
- }
- return true;
+void WebSocketHandshake::processHeaders()
+{
+ ASSERT(m_mode == Normal);
+ const HTTPHeaderMap& headers = m_response.headerFields();
+ m_wsOrigin = headers.get("sec-websocket-origin");
+ m_wsLocation = headers.get("sec-websocket-location");
+ m_wsProtocol = headers.get("sec-websocket-protocol");
+ m_setCookie = headers.get("set-cookie");
+ m_setCookie2 = headers.get("set-cookie2");
}
bool WebSocketHandshake::checkResponseHeaders()