Index: net/websockets/websocket_handshake_handler.cc |
diff --git a/net/websockets/websocket_handshake_handler.cc b/net/websockets/websocket_handshake_handler.cc |
index 7e5ec6fcdda12316c60b808e2b17fd743cf35419..647241cdcfee3460bf3b00eee790c62f90e0ecc2 100644 |
--- a/net/websockets/websocket_handshake_handler.cc |
+++ b/net/websockets/websocket_handshake_handler.cc |
@@ -94,24 +94,21 @@ std::string FilterHeaders( |
return filtered_headers; |
} |
-// Gets a key number for |key_name| in |headers| and appends the number to |
-// |challenge|. |
+// Gets a key number from |key| and appends the number to |challenge|. |
// The key number (/part_N/) is extracted as step 4.-8. in |
// 5.2. Sending the server's opening handshake of |
// http://www.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-00.txt |
-void GetKeyNumber(net::HttpRequestHeaders* headers, const char* key_name, |
- std::string* challenge) { |
- std::string key; |
- headers->GetHeader(key_name, &key); |
- headers->RemoveHeader(key_name); |
- |
+void GetKeyNumber(const std::string& key, std::string* challenge) { |
uint32 key_number = 0; |
uint32 spaces = 0; |
for (size_t i = 0; i < key.size(); ++i) { |
- if (isdigit(key[i])) |
+ if (isdigit(key[i])) { |
+ // key_number should not overflow. (it comes from |
+ // WebCore/websockets/WebSocketHandshake.cpp). |
key_number = key_number * 10 + key[i] - '0'; |
- else if (key[i] == ' ') |
+ } else if (key[i] == ' ') { |
++spaces; |
+ } |
} |
// spaces should not be zero in valid handshake request. |
if (spaces == 0) |
@@ -199,13 +196,69 @@ HttpRequestInfo WebSocketHandshakeRequestHandler::GetRequestInfo( |
request_info.extra_headers.RemoveHeader("Connection"); |
challenge->clear(); |
- GetKeyNumber(&request_info.extra_headers, "Sec-WebSocket-Key1", challenge); |
- GetKeyNumber(&request_info.extra_headers, "Sec-WebSocket-Key2", challenge); |
+ std::string key; |
+ request_info.extra_headers.GetHeader("Sec-WebSocket-Key1", &key); |
+ request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key1"); |
+ GetKeyNumber(key, challenge); |
+ |
+ request_info.extra_headers.GetHeader("Sec-WebSocket-Key2", &key); |
+ request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key2"); |
+ GetKeyNumber(key, challenge); |
+ |
challenge->append(key3_); |
return request_info; |
} |
+bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock( |
+ const GURL& url, spdy::SpdyHeaderBlock* headers, std::string* challenge) { |
+ // We don't set "method" and "version". These are fixed value in WebSocket |
+ // protocol. |
+ (*headers)["url"] = url.spec(); |
+ |
+ std::string key1; |
+ std::string key2; |
+ HttpUtil::HeadersIterator iter(headers_.begin(), headers_.end(), "\r\n"); |
+ while (iter.GetNext()) { |
+ if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
+ "connection")) { |
+ // Ignore "Connection" header. |
+ continue; |
+ } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
+ "upgrade")) { |
+ // Ignore "Upgrade" header. |
+ continue; |
+ } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
+ "sec-websocket-key1")) { |
+ // Use only for generating challenge. |
+ key1 = iter.values(); |
+ continue; |
+ } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), |
+ "sec-websocket-key2")) { |
+ // Use only for generating challenge. |
+ key2 = iter.values(); |
+ continue; |
+ } |
+ // Others should be sent out to |headers|. |
+ std::string name = StringToLowerASCII(iter.name()); |
+ spdy::SpdyHeaderBlock::iterator found = headers->find(name); |
+ if (found == headers->end()) { |
+ (*headers)[name] = iter.values(); |
+ } else { |
+ // For now, websocket doesn't use multiple headers, but follows to http. |
+ found->second.append(1, '\0'); // +=() doesn't append 0's |
+ found->second.append(iter.values()); |
+ } |
+ } |
+ |
+ challenge->clear(); |
+ GetKeyNumber(key1, challenge); |
+ GetKeyNumber(key2, challenge); |
+ challenge->append(key3_); |
+ |
+ return true; |
+} |
+ |
std::string WebSocketHandshakeRequestHandler::GetRawRequest() { |
DCHECK(status_line_.size() > 0); |
DCHECK(headers_.size() > 0); |
@@ -287,6 +340,45 @@ bool WebSocketHandshakeResponseHandler::ParseResponseInfo( |
response_message.size()) == response_message.size(); |
} |
+bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( |
+ const spdy::SpdyHeaderBlock& headers, |
+ const std::string& challenge) { |
+ std::string response_message; |
+ response_message = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"; |
+ response_message += "Upgrade: WebSocket\r\n"; |
+ response_message += "Connection: Upgrade\r\n"; |
+ for (spdy::SpdyHeaderBlock::const_iterator iter = headers.begin(); |
+ iter != headers.end(); |
+ ++iter) { |
+ // For each value, if the server sends a NUL-separated list of values, |
+ // we separate that back out into individual headers for each value |
+ // in the list. |
+ const std::string& value = iter->second; |
+ size_t start = 0; |
+ size_t end = 0; |
+ do { |
+ end = value.find('\0', start); |
+ std::string tval; |
+ if (end != std::string::npos) |
+ tval = value.substr(start, (end - start)); |
+ else |
+ tval = value.substr(start); |
+ response_message += iter->first + ": " + tval + "\r\n"; |
+ start = end + 1; |
+ } while (end != std::string::npos); |
+ } |
+ response_message += "\r\n"; |
+ |
+ MD5Digest digest; |
+ MD5Sum(challenge.data(), challenge.size(), &digest); |
+ |
+ const char* digest_data = reinterpret_cast<char*>(digest.a); |
+ response_message.append(digest_data, sizeof(digest.a)); |
+ |
+ return ParseRawResponse(response_message.data(), |
+ response_message.size()) == response_message.size(); |
+} |
+ |
void WebSocketHandshakeResponseHandler::GetHeaders( |
const char* const headers_to_get[], |
size_t headers_to_get_len, |