diff options
author | ukai@chromium.org <ukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-08 02:11:56 +0000 |
---|---|---|
committer | ukai@chromium.org <ukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-08 02:11:56 +0000 |
commit | 32bf3c4f2ab152883dfa86ca3597f557af84d289 (patch) | |
tree | a1248d4be2c8001853c35f975194543c96045d2a /net/websockets/websocket_handshake_handler.cc | |
parent | 95def6d076e66115ede482dc5926ed90a391d3d2 (diff) | |
download | chromium_src-32bf3c4f2ab152883dfa86ca3597f557af84d289.zip chromium_src-32bf3c4f2ab152883dfa86ca3597f557af84d289.tar.gz chromium_src-32bf3c4f2ab152883dfa86ca3597f557af84d289.tar.bz2 |
Implement WebSocketHandshake*Handler to support Http{Request,Response}Info.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/2579002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@49137 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/websockets/websocket_handshake_handler.cc')
-rw-r--r-- | net/websockets/websocket_handshake_handler.cc | 103 |
1 files changed, 74 insertions, 29 deletions
diff --git a/net/websockets/websocket_handshake_handler.cc b/net/websockets/websocket_handshake_handler.cc index 8b1e071..7e5ec6f 100644 --- a/net/websockets/websocket_handshake_handler.cc +++ b/net/websockets/websocket_handshake_handler.cc @@ -4,6 +4,8 @@ #include "net/websockets/websocket_handshake_handler.h" +#include "base/md5.h" +#include "base/string_piece.h" #include "base/string_util.h" #include "googleurl/src/gurl.h" #include "net/http/http_util.h" @@ -23,8 +25,11 @@ void ParseHandshakeHeader( *headers = ""; return; } + // |status_line| includes \r\n. *status_line = std::string(handshake_message, i + 2); - *headers = std::string(handshake_message + i + 2, len - i - 2); + // |handshake_message| includes tailing \r\n\r\n. + // |headers| doesn't include 2nd \r\n. + *headers = std::string(handshake_message + i + 2, len - (i + 2) - 2); } void FetchHeaders(const std::string& headers, @@ -89,6 +94,38 @@ std::string FilterHeaders( return filtered_headers; } +// Gets a key number for |key_name| in |headers| 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); + + uint32 key_number = 0; + uint32 spaces = 0; + for (size_t i = 0; i < key.size(); ++i) { + if (isdigit(key[i])) + key_number = key_number * 10 + key[i] - '0'; + else if (key[i] == ' ') + ++spaces; + } + // spaces should not be zero in valid handshake request. + if (spaces == 0) + return; + key_number /= spaces; + + char part[4]; + for (int i = 0; i < 4; i++) { + part[3 - i] = key_number & 0xFF; + key_number >>= 8; + } + challenge->append(part, 4); +} + } // anonymous namespace namespace net { @@ -145,19 +182,28 @@ void WebSocketHandshakeRequestHandler::RemoveHeaders( headers_, headers_to_remove, headers_to_remove_len); } -const HttpRequestInfo& WebSocketHandshakeRequestHandler::GetRequestInfo( - const GURL& url) { - NOTIMPLEMENTED(); - // TODO(ukai): implement for Spdy support. Rest is incomplete. - request_info_.url = url; - // TODO(ukai): method should be built from |request_status_line_|. - request_info_.method = "GET"; - - request_info_.extra_headers.Clear(); - request_info_.extra_headers.AddHeadersFromString(headers_); - // TODO(ukai): eliminate unnecessary headers, such as Sec-WebSocket-Key1 - // and Sec-WebSocket-Key2. - return request_info_; +HttpRequestInfo WebSocketHandshakeRequestHandler::GetRequestInfo( + const GURL& url, std::string* challenge) { + HttpRequestInfo request_info; + request_info.url = url; + base::StringPiece method = status_line_.data(); + size_t method_end = base::StringPiece( + status_line_.data(), status_line_.size()).find_first_of(" "); + if (method_end != base::StringPiece::npos) + request_info.method = std::string(status_line_.data(), method_end); + + request_info.extra_headers.Clear(); + request_info.extra_headers.AddHeadersFromString(headers_); + + request_info.extra_headers.RemoveHeader("Upgrade"); + 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); + challenge->append(key3_); + + return request_info; } std::string WebSocketHandshakeRequestHandler::GetRawRequest() { @@ -174,11 +220,6 @@ size_t WebSocketHandshakeRequestHandler::raw_length() const { return raw_length_; } -std::string WebSocketHandshakeRequestHandler::GetChallenge() const { - NOTIMPLEMENTED(); - return ""; -} - WebSocketHandshakeResponseHandler::WebSocketHandshakeResponseHandler() : original_header_length_(0) { } @@ -219,25 +260,29 @@ bool WebSocketHandshakeResponseHandler::HasResponse() const { bool WebSocketHandshakeResponseHandler::ParseResponseInfo( const HttpResponseInfo& response_info, - WebSocketHandshakeRequestHandler* request_handler) { - NOTIMPLEMENTED(); - // TODO(ukai): implement for Spdy support. Rest is incomplete. - response_info_ = response_info; - - if (!response_info_.headers.get()) + const std::string& challenge) { + if (!response_info.headers.get()) return false; std::string response_message; - response_message = response_info_.headers->GetStatusLine(); + response_message = response_info.headers->GetStatusLine(); response_message += "\r\n"; + response_message += "Upgrade: WebSocket\r\n"; + response_message += "Connection: Upgrade\r\n"; void* iter = NULL; std::string name; std::string value; - while (response_info_.headers->EnumerateHeaderLines(&iter, &name, &value)) { + while (response_info.headers->EnumerateHeaderLines(&iter, &name, &value)) { response_message += name + ": " + value + "\r\n"; } - // TODO(ukai): generate response key from request_handler->GetChallenge() - // and add it to |response_message|. + 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(); } |