diff options
author | toyoshim@chromium.org <toyoshim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-14 10:32:22 +0000 |
---|---|---|
committer | toyoshim@chromium.org <toyoshim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-14 10:32:22 +0000 |
commit | 541c0e734064af21624ae5504ed943a24f69a53c (patch) | |
tree | eec1b19322953072319f6440dfbbcff3b13b1518 /net | |
parent | 2194597d984818b434888121149f0c2fef9fec65 (diff) | |
download | chromium_src-541c0e734064af21624ae5504ed943a24f69a53c.zip chromium_src-541c0e734064af21624ae5504ed943a24f69a53c.tar.gz chromium_src-541c0e734064af21624ae5504ed943a24f69a53c.tar.bz2 |
WebSocket over SPDY: handshake support for both of SPDY/2 and SPDY/3
If negotiated protocol is SPDY/3 or later, well defined name of SYN_STREAM and
SYN_REPLY must be colon prefixed name.
BUG=42320
TEST=net_uinttests
Review URL: https://chromiumcodereview.appspot.com/10843050
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151453 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/net.gyp | 2 | ||||
-rw-r--r-- | net/websockets/websocket_handshake_handler.cc | 64 | ||||
-rw-r--r-- | net/websockets/websocket_handshake_handler.h | 6 | ||||
-rw-r--r-- | net/websockets/websocket_handshake_handler_spdy2_unittest.cc | 182 | ||||
-rw-r--r-- | net/websockets/websocket_handshake_handler_spdy3_unittest.cc | 189 | ||||
-rw-r--r-- | net/websockets/websocket_handshake_handler_unittest.cc | 147 | ||||
-rw-r--r-- | net/websockets/websocket_job.cc | 8 | ||||
-rw-r--r-- | net/websockets/websocket_job.h | 1 | ||||
-rw-r--r-- | net/websockets/websocket_job_spdy3_unittest.cc | 16 |
9 files changed, 445 insertions, 170 deletions
diff --git a/net/net.gyp b/net/net.gyp index 6ed9798..e412ac6 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -1352,6 +1352,8 @@ 'websockets/websocket_frame_parser_unittest.cc', 'websockets/websocket_frame_unittest.cc', 'websockets/websocket_handshake_handler_unittest.cc', + 'websockets/websocket_handshake_handler_spdy2_unittest.cc', + 'websockets/websocket_handshake_handler_spdy3_unittest.cc', 'websockets/websocket_job_spdy2_unittest.cc', 'websockets/websocket_job_spdy3_unittest.cc', 'websockets/websocket_net_log_params_unittest.cc', diff --git a/net/websockets/websocket_handshake_handler.cc b/net/websockets/websocket_handshake_handler.cc index 507b53a..991ea31 100644 --- a/net/websockets/websocket_handshake_handler.cc +++ b/net/websockets/websocket_handshake_handler.cc @@ -266,13 +266,23 @@ HttpRequestInfo WebSocketHandshakeRequestHandler::GetRequestInfo( } bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock( - const GURL& url, SpdyHeaderBlock* headers, std::string* challenge) { + const GURL& url, + SpdyHeaderBlock* headers, + std::string* challenge, + int spdy_protocol_version) { // Construct opening handshake request headers as a SPDY header block. // For details, see WebSocket Layering over SPDY/3 Draft 8. - (*headers)["path"] = url.path(); - (*headers)["version"] = + if (spdy_protocol_version <= 2) { + (*headers)["path"] = url.path(); + (*headers)["version"] = base::StringPrintf("%s%d", "WebSocket/", protocol_version_); - (*headers)["scheme"] = url.scheme(); + (*headers)["scheme"] = url.scheme(); + } else { + (*headers)[":path"] = url.path(); + (*headers)[":version"] = + base::StringPrintf("%s%d", "WebSocket/", protocol_version_); + (*headers)[":scheme"] = url.scheme(); + } HttpUtil::HeadersIterator iter(headers_.begin(), headers_.end(), "\r\n"); while (iter.GetNext()) { @@ -291,10 +301,29 @@ bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock( *challenge = iter.values(); // Sec-WebSocket-Key is not sent to a server. continue; + } else if (LowerCaseEqualsASCII(iter.name_begin(), + iter.name_end(), + "host") || + LowerCaseEqualsASCII(iter.name_begin(), + iter.name_end(), + "origin") || + LowerCaseEqualsASCII(iter.name_begin(), + iter.name_end(), + "sec-websocket-protocol") || + LowerCaseEqualsASCII(iter.name_begin(), + iter.name_end(), + "sec-websocket-extensions")) { + // TODO(toyoshim): Some WebSocket extensions may not be compatible with + // SPDY. We should omit them from a Sec-WebSocket-Extension header. + std::string name; + if (spdy_protocol_version <= 2) + name = StringToLowerASCII(iter.name()); + else + name = ":" + StringToLowerASCII(iter.name()); + (*headers)[name] = iter.values(); + continue; } // Others should be sent out to |headers|. - // TODO(toyoshim): Some WebSocket extensions are not compatible with SPDY. - // We should remove them from a Sec-WebSocket-Extension header. std::string name = StringToLowerASCII(iter.name()); SpdyHeaderBlock::iterator found = headers->find(name); if (found == headers->end()) { @@ -427,11 +456,16 @@ bool WebSocketHandshakeResponseHandler::ParseResponseInfo( bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( const SpdyHeaderBlock& headers, - const std::string& challenge) { - std::string response_message; - SpdyHeaderBlock::const_iterator status = headers.find("status"); + const std::string& challenge, + int spdy_protocol_version) { + SpdyHeaderBlock::const_iterator status; + if (spdy_protocol_version <= 2) + status = headers.find("status"); + else + status = headers.find(":status"); if (status == headers.end()) return false; + std::string response_message; response_message = base::StringPrintf("%s%s\r\n", "HTTP/1.1 ", status->second.c_str()); response_message += "Upgrade: websocket\r\n"; @@ -449,7 +483,10 @@ bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( // 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. - if (LowerCaseEqualsASCII(iter->first, "status")) { + if ((spdy_protocol_version <= 2 && + LowerCaseEqualsASCII(iter->first, "status")) || + (spdy_protocol_version >= 3 && + LowerCaseEqualsASCII(iter->first, ":status"))) { // The status value is already handled as the first line of // |response_message|. Just skip here. continue; @@ -464,7 +501,12 @@ bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( tval = value.substr(start, (end - start)); else tval = value.substr(start); - response_message += iter->first + ": " + tval + "\r\n"; + if (spdy_protocol_version >= 3 && + (LowerCaseEqualsASCII(iter->first, ":sec-websocket-protocol") || + LowerCaseEqualsASCII(iter->first, ":sec-websocket-extensions"))) + response_message += iter->first.substr(1) + ": " + tval + "\r\n"; + else + response_message += iter->first + ": " + tval + "\r\n"; start = end + 1; } while (end != std::string::npos); } diff --git a/net/websockets/websocket_handshake_handler.h b/net/websockets/websocket_handshake_handler.h index 2093adb..9ac142b 100644 --- a/net/websockets/websocket_handshake_handler.h +++ b/net/websockets/websocket_handshake_handler.h @@ -68,7 +68,8 @@ class NET_EXPORT_PRIVATE WebSocketHandshakeRequestHandler { // Also, fills challenge data in |challenge|. bool GetRequestHeaderBlock(const GURL& url, SpdyHeaderBlock* headers, - std::string* challenge); + std::string* challenge, + int spdy_protocol_version); // Gets WebSocket handshake raw request message to open WebSocket // connection. std::string GetRawRequest(); @@ -117,7 +118,8 @@ class NET_EXPORT_PRIVATE WebSocketHandshakeResponseHandler { const std::string& challenge); // Parses WebSocket handshake response as SpdyHeaderBlock. bool ParseResponseHeaderBlock(const SpdyHeaderBlock& headers, - const std::string& challenge); + const std::string& challenge, + int spdy_protocol_version); // Gets the headers value. void GetHeaders(const char* const headers_to_get[], diff --git a/net/websockets/websocket_handshake_handler_spdy2_unittest.cc b/net/websockets/websocket_handshake_handler_spdy2_unittest.cc new file mode 100644 index 0000000..975b366 --- /dev/null +++ b/net/websockets/websocket_handshake_handler_spdy2_unittest.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/websockets/websocket_handshake_handler.h" + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/string_util.h" +#include "googleurl/src/gurl.h" +#include "net/http/http_response_headers.h" +#include "net/http/http_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +namespace net { + +namespace { + +TEST(WebSocketHandshakeHandlerSpdy2Test, RequestResponse) { + WebSocketHandshakeRequestHandler request_handler; + + static const char kHandshakeRequestMessage[] = + "GET /demo HTTP/1.1\r\n" + "Host: example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: sample\r\n" + "Sec-WebSocket-Extensions: foo\r\n" + "Sec-WebSocket-Version: 13\r\n" + "\r\n"; + + EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage, + strlen(kHandshakeRequestMessage))); + EXPECT_EQ(13, request_handler.protocol_version()); + + GURL url("ws://example.com/demo"); + std::string challenge; + SpdyHeaderBlock headers; + ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url, + &headers, + &challenge, + 2)); + + EXPECT_EQ(url.path(), headers["path"]); + EXPECT_TRUE(headers.find("upgrade") == headers.end()); + EXPECT_TRUE(headers.find("Upgrade") == headers.end()); + EXPECT_TRUE(headers.find("connection") == headers.end()); + EXPECT_TRUE(headers.find("Connection") == headers.end()); + EXPECT_TRUE(headers.find("Sec-WebSocket-Key") == headers.end()); + EXPECT_TRUE(headers.find("sec-websocket-key") == headers.end()); + EXPECT_TRUE(headers.find("Sec-WebSocket-Version") == headers.end()); + EXPECT_TRUE(headers.find("sec-webSocket-version") == headers.end()); + EXPECT_EQ("example.com", headers["host"]); + EXPECT_EQ("http://example.com", headers["origin"]); + EXPECT_EQ("sample", headers["sec-websocket-protocol"]); + EXPECT_EQ("foo", headers["sec-websocket-extensions"]); + EXPECT_EQ("ws", headers["scheme"]); + EXPECT_EQ("WebSocket/13", headers["version"]); + + static const char expected_challenge[] = "dGhlIHNhbXBsZSBub25jZQ=="; + + EXPECT_EQ(expected_challenge, challenge); + + headers.clear(); + + headers["status"] = "101 Switching Protocols"; + headers["sec-websocket-protocol"] = "sample"; + headers["sec-websocket-extensions"] = "foo"; + + WebSocketHandshakeResponseHandler response_handler; + response_handler.set_protocol_version(13); + EXPECT_TRUE(response_handler.ParseResponseHeaderBlock(headers, + challenge, + 2)); + EXPECT_TRUE(response_handler.HasResponse()); + + // Note that order of sec-websocket-* is sensitive with hash_map order. + static const char kHandshakeResponseExpectedMessage[] = + "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" + "sec-websocket-extensions: foo\r\n" + "sec-websocket-protocol: sample\r\n" + "\r\n"; + + EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse()); +} + +TEST(WebSocketHandshakeHandlerSpdy2Test, RequestResponseWithCookies) { + WebSocketHandshakeRequestHandler request_handler; + + // Note that websocket won't use multiple headers in request now. + static const char kHandshakeRequestMessage[] = + "GET /demo HTTP/1.1\r\n" + "Host: example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: sample\r\n" + "Sec-WebSocket-Extensions: foo\r\n" + "Sec-WebSocket-Version: 13\r\n" + "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n" + "\r\n"; + + EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage, + strlen(kHandshakeRequestMessage))); + EXPECT_EQ(13, request_handler.protocol_version()); + + GURL url("ws://example.com/demo"); + std::string challenge; + SpdyHeaderBlock headers; + ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url, + &headers, + &challenge, + 2)); + + EXPECT_EQ(url.path(), headers["path"]); + EXPECT_TRUE(headers.find("upgrade") == headers.end()); + EXPECT_TRUE(headers.find("Upgrade") == headers.end()); + EXPECT_TRUE(headers.find("connection") == headers.end()); + EXPECT_TRUE(headers.find("Connection") == headers.end()); + EXPECT_TRUE(headers.find("Sec-WebSocket-Key") == headers.end()); + EXPECT_TRUE(headers.find("sec-websocket-key") == headers.end()); + EXPECT_TRUE(headers.find("Sec-WebSocket-Version") == headers.end()); + EXPECT_TRUE(headers.find("sec-webSocket-version") == headers.end()); + EXPECT_EQ("example.com", headers["host"]); + EXPECT_EQ("http://example.com", headers["origin"]); + EXPECT_EQ("sample", headers["sec-websocket-protocol"]); + EXPECT_EQ("foo", headers["sec-websocket-extensions"]); + EXPECT_EQ("ws", headers["scheme"]); + EXPECT_EQ("WebSocket/13", headers["version"]); + EXPECT_EQ("WK-websocket-test=1; WK-websocket-test-httponly=1", + headers["cookie"]); + + const char expected_challenge[] = "dGhlIHNhbXBsZSBub25jZQ=="; + + EXPECT_EQ(expected_challenge, challenge); + + headers.clear(); + + headers["status"] = "101 Switching Protocols"; + headers["sec-websocket-protocol"] = "sample"; + headers["sec-websocket-extensions"] = "foo"; + std::string cookie = "WK-websocket-test=1"; + cookie.append(1, '\0'); + cookie += "WK-websocket-test-httponly=1; HttpOnly"; + headers["set-cookie"] = cookie; + + + WebSocketHandshakeResponseHandler response_handler; + response_handler.set_protocol_version(13); + EXPECT_TRUE(response_handler.ParseResponseHeaderBlock(headers, + challenge, + 2)); + EXPECT_TRUE(response_handler.HasResponse()); + + // Note that order of sec-websocket-* is sensitive with hash_map order. + static const char kHandshakeResponseExpectedMessage[] = + "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" + "sec-websocket-extensions: foo\r\n" + "sec-websocket-protocol: sample\r\n" + "set-cookie: WK-websocket-test=1\r\n" + "set-cookie: WK-websocket-test-httponly=1; HttpOnly\r\n" + "\r\n"; + + EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse()); +} + +} // namespace + +} // namespace net diff --git a/net/websockets/websocket_handshake_handler_spdy3_unittest.cc b/net/websockets/websocket_handshake_handler_spdy3_unittest.cc new file mode 100644 index 0000000..3baa12b --- /dev/null +++ b/net/websockets/websocket_handshake_handler_spdy3_unittest.cc @@ -0,0 +1,189 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/websockets/websocket_handshake_handler.h" + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/string_util.h" +#include "googleurl/src/gurl.h" +#include "net/http/http_response_headers.h" +#include "net/http/http_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +namespace net { + +namespace { + +TEST(WebSocketHandshakeHandlerSpdy3Test, RequestResponse) { + WebSocketHandshakeRequestHandler request_handler; + + static const char kHandshakeRequestMessage[] = + "GET /demo HTTP/1.1\r\n" + "Host: example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: sample\r\n" + "Sec-WebSocket-Extensions: foo\r\n" + "Sec-WebSocket-Version: 13\r\n" + "X-Foo: foo\r\n" + "\r\n"; + + EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage, + strlen(kHandshakeRequestMessage))); + EXPECT_EQ(13, request_handler.protocol_version()); + + GURL url("ws://example.com/demo"); + std::string challenge; + SpdyHeaderBlock headers; + ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url, + &headers, + &challenge, + 3)); + + EXPECT_EQ(url.path(), headers[":path"]); + EXPECT_TRUE(headers.find(":upgrade") == headers.end()); + EXPECT_TRUE(headers.find(":Upgrade") == headers.end()); + EXPECT_TRUE(headers.find(":connection") == headers.end()); + EXPECT_TRUE(headers.find(":Connection") == headers.end()); + EXPECT_TRUE(headers.find(":Sec-WebSocket-Key") == headers.end()); + EXPECT_TRUE(headers.find(":sec-websocket-key") == headers.end()); + EXPECT_TRUE(headers.find(":Sec-WebSocket-Version") == headers.end()); + EXPECT_TRUE(headers.find(":sec-webSocket-version") == headers.end()); + EXPECT_TRUE(headers.find(":x-foo") == headers.end()); + EXPECT_EQ("example.com", headers[":host"]); + EXPECT_EQ("http://example.com", headers[":origin"]); + EXPECT_EQ("sample", headers[":sec-websocket-protocol"]); + EXPECT_EQ("foo", headers[":sec-websocket-extensions"]); + EXPECT_EQ("ws", headers[":scheme"]); + EXPECT_EQ("WebSocket/13", headers[":version"]); + EXPECT_EQ("foo", headers["x-foo"]); + + static const char expected_challenge[] = "dGhlIHNhbXBsZSBub25jZQ=="; + + EXPECT_EQ(expected_challenge, challenge); + + headers.clear(); + + headers[":status"] = "101 Switching Protocols"; + headers[":sec-websocket-protocol"] = "sample"; + headers[":sec-websocket-extensions"] = "foo"; + headers["x-bar"] = "bar"; + + WebSocketHandshakeResponseHandler response_handler; + response_handler.set_protocol_version(13); + EXPECT_TRUE(response_handler.ParseResponseHeaderBlock(headers, + challenge, + 3)); + EXPECT_TRUE(response_handler.HasResponse()); + + // Note that order of sec-websocket-* is sensitive with hash_map order. + static const char kHandshakeResponseExpectedMessage[] = + "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" + "sec-websocket-extensions: foo\r\n" + "sec-websocket-protocol: sample\r\n" + "x-bar: bar\r\n" + "\r\n"; + + EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse()); +} + +TEST(WebSocketHandshakeHandlerSpdy3Test, RequestResponseWithCookies) { + WebSocketHandshakeRequestHandler request_handler; + + // Note that websocket won't use multiple headers in request now. + static const char kHandshakeRequestMessage[] = + "GET /demo HTTP/1.1\r\n" + "Host: example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: sample\r\n" + "Sec-WebSocket-Extensions: foo\r\n" + "Sec-WebSocket-Version: 13\r\n" + "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n" + "\r\n"; + + EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage, + strlen(kHandshakeRequestMessage))); + EXPECT_EQ(13, request_handler.protocol_version()); + + GURL url("ws://example.com/demo"); + std::string challenge; + SpdyHeaderBlock headers; + ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url, + &headers, + &challenge, + 3)); + + EXPECT_EQ(url.path(), headers[":path"]); + EXPECT_TRUE(headers.find(":upgrade") == headers.end()); + EXPECT_TRUE(headers.find(":Upgrade") == headers.end()); + EXPECT_TRUE(headers.find(":connection") == headers.end()); + EXPECT_TRUE(headers.find(":Connection") == headers.end()); + EXPECT_TRUE(headers.find(":Sec-WebSocket-Key") == headers.end()); + EXPECT_TRUE(headers.find(":sec-websocket-key") == headers.end()); + EXPECT_TRUE(headers.find(":Sec-WebSocket-Version") == headers.end()); + EXPECT_TRUE(headers.find(":sec-webSocket-version") == headers.end()); + EXPECT_TRUE(headers.find(":Cookie") == headers.end()); + EXPECT_TRUE(headers.find(":cookie") == headers.end()); + EXPECT_EQ("example.com", headers[":host"]); + EXPECT_EQ("http://example.com", headers[":origin"]); + EXPECT_EQ("sample", headers[":sec-websocket-protocol"]); + EXPECT_EQ("foo", headers[":sec-websocket-extensions"]); + EXPECT_EQ("ws", headers[":scheme"]); + EXPECT_EQ("WebSocket/13", headers[":version"]); + EXPECT_EQ("WK-websocket-test=1; WK-websocket-test-httponly=1", + headers["cookie"]); + + const char expected_challenge[] = "dGhlIHNhbXBsZSBub25jZQ=="; + + EXPECT_EQ(expected_challenge, challenge); + + headers.clear(); + + headers[":status"] = "101 Switching Protocols"; + headers[":sec-websocket-protocol"] = "sample"; + headers[":sec-websocket-extensions"] = "foo"; + std::string cookie = "WK-websocket-test=1"; + cookie.append(1, '\0'); + cookie += "WK-websocket-test-httponly=1; HttpOnly"; + headers["set-cookie"] = cookie; + + + WebSocketHandshakeResponseHandler response_handler; + response_handler.set_protocol_version(13); + EXPECT_TRUE(response_handler.ParseResponseHeaderBlock(headers, + challenge, + 3)); + EXPECT_TRUE(response_handler.HasResponse()); + + // Note that order of sec-websocket-* is sensitive with hash_map order. + static const char kHandshakeResponseExpectedMessage[] = + "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" + "sec-websocket-extensions: foo\r\n" + "sec-websocket-protocol: sample\r\n" + "set-cookie: WK-websocket-test=1\r\n" + "set-cookie: WK-websocket-test-httponly=1; HttpOnly\r\n" + "\r\n"; + + EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse()); +} + +} // namespace + +} // namespace net diff --git a/net/websockets/websocket_handshake_handler_unittest.cc b/net/websockets/websocket_handshake_handler_unittest.cc index 4888401..80a0d76 100644 --- a/net/websockets/websocket_handshake_handler_unittest.cc +++ b/net/websockets/websocket_handshake_handler_unittest.cc @@ -466,151 +466,4 @@ TEST(WebSocketHandshakeHandlerTest, HttpRequestResponseHybi06Handshake) { EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse()); } -TEST(WebSocketHandshakeHandlerTest, SpdyRequestResponse) { - WebSocketHandshakeRequestHandler request_handler; - - static const char kHandshakeRequestMessage[] = - "GET /demo HTTP/1.1\r\n" - "Host: example.com\r\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" - "Origin: http://example.com\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "Sec-WebSocket-Extensions: foo\r\n" - "Sec-WebSocket-Version: 13\r\n" - "\r\n"; - - EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage, - strlen(kHandshakeRequestMessage))); - EXPECT_EQ(13, request_handler.protocol_version()); - - GURL url("ws://example.com/demo"); - std::string challenge; - SpdyHeaderBlock headers; - ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url, &headers, &challenge)); - - EXPECT_EQ(url.path(), headers["path"]); - EXPECT_TRUE(headers.find("upgrade") == headers.end()); - EXPECT_TRUE(headers.find("Upgrade") == headers.end()); - EXPECT_TRUE(headers.find("connection") == headers.end()); - EXPECT_TRUE(headers.find("Connection") == headers.end()); - EXPECT_TRUE(headers.find("Sec-WebSocket-Key") == headers.end()); - EXPECT_TRUE(headers.find("sec-websocket-key") == headers.end()); - EXPECT_TRUE(headers.find("Sec-WebSocket-Version") == headers.end()); - EXPECT_TRUE(headers.find("sec-webSocket-version") == headers.end()); - EXPECT_EQ("example.com", headers["host"]); - EXPECT_EQ("http://example.com", headers["origin"]); - EXPECT_EQ("sample", headers["sec-websocket-protocol"]); - EXPECT_EQ("foo", headers["sec-websocket-extensions"]); - EXPECT_EQ("ws", headers["scheme"]); - EXPECT_EQ("WebSocket/13", headers["version"]); - - const char expected_challenge[] = "dGhlIHNhbXBsZSBub25jZQ=="; - - EXPECT_EQ(expected_challenge, challenge); - - headers.clear(); - - headers["status"] = "101 Switching Protocols"; - headers["sec-websocket-protocol"] = "sample"; - headers["sec-websocket-extensions"] = "foo"; - - WebSocketHandshakeResponseHandler response_handler; - response_handler.set_protocol_version(13); - EXPECT_TRUE(response_handler.ParseResponseHeaderBlock(headers, challenge)); - EXPECT_TRUE(response_handler.HasResponse()); - - // Note that order of sec-websocket-* is sensitive with hash_map order. - static const char kHandshakeResponseExpectedMessage[] = - "HTTP/1.1 101 Switching Protocols\r\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" - "sec-websocket-extensions: foo\r\n" - "sec-websocket-protocol: sample\r\n" - "\r\n"; - - EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse()); -} - -TEST(WebSocketHandshakeHandlerTest, SpdyRequestResponseWithCookies) { - WebSocketHandshakeRequestHandler request_handler; - - // Note that websocket won't use multiple headers in request now. - static const char kHandshakeRequestMessage[] = - "GET /demo HTTP/1.1\r\n" - "Host: example.com\r\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" - "Origin: http://example.com\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "Sec-WebSocket-Extensions: foo\r\n" - "Sec-WebSocket-Version: 13\r\n" - "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n" - "\r\n"; - - EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage, - strlen(kHandshakeRequestMessage))); - EXPECT_EQ(13, request_handler.protocol_version()); - - GURL url("ws://example.com/demo"); - std::string challenge; - SpdyHeaderBlock headers; - ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url, &headers, &challenge)); - - EXPECT_EQ(url.path(), headers["path"]); - EXPECT_TRUE(headers.find("upgrade") == headers.end()); - EXPECT_TRUE(headers.find("Upgrade") == headers.end()); - EXPECT_TRUE(headers.find("connection") == headers.end()); - EXPECT_TRUE(headers.find("Connection") == headers.end()); - EXPECT_TRUE(headers.find("Sec-WebSocket-Key") == headers.end()); - EXPECT_TRUE(headers.find("sec-websocket-key") == headers.end()); - EXPECT_TRUE(headers.find("Sec-WebSocket-Version") == headers.end()); - EXPECT_TRUE(headers.find("sec-webSocket-version") == headers.end()); - EXPECT_EQ("example.com", headers["host"]); - EXPECT_EQ("http://example.com", headers["origin"]); - EXPECT_EQ("sample", headers["sec-websocket-protocol"]); - EXPECT_EQ("foo", headers["sec-websocket-extensions"]); - EXPECT_EQ("ws", headers["scheme"]); - EXPECT_EQ("WebSocket/13", headers["version"]); - EXPECT_EQ("WK-websocket-test=1; WK-websocket-test-httponly=1", - headers["cookie"]); - - const char expected_challenge[] = "dGhlIHNhbXBsZSBub25jZQ=="; - - EXPECT_EQ(expected_challenge, challenge); - - headers.clear(); - - headers["status"] = "101 Switching Protocols"; - headers["sec-websocket-protocol"] = "sample"; - headers["sec-websocket-extensions"] = "foo"; - std::string cookie = "WK-websocket-test=1"; - cookie.append(1, '\0'); - cookie += "WK-websocket-test-httponly=1; HttpOnly"; - headers["set-cookie"] = cookie; - - - WebSocketHandshakeResponseHandler response_handler; - response_handler.set_protocol_version(13); - EXPECT_TRUE(response_handler.ParseResponseHeaderBlock(headers, challenge)); - EXPECT_TRUE(response_handler.HasResponse()); - - // Note that order of sec-websocket-* is sensitive with hash_map order. - static const char kHandshakeResponseExpectedMessage[] = - "HTTP/1.1 101 Switching Protocols\r\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" - "sec-websocket-extensions: foo\r\n" - "sec-websocket-protocol: sample\r\n" - "set-cookie: WK-websocket-test=1\r\n" - "set-cookie: WK-websocket-test-httponly=1; HttpOnly\r\n" - "\r\n"; - - EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse()); -} - } // namespace net diff --git a/net/websockets/websocket_job.cc b/net/websockets/websocket_job.cc index 56faefb..ff60ebe 100644 --- a/net/websockets/websocket_job.cc +++ b/net/websockets/websocket_job.cc @@ -80,6 +80,7 @@ WebSocketJob::WebSocketJob(SocketStream::Delegate* delegate) started_to_send_handshake_request_(false), handshake_request_sent_(0), response_cookies_save_index_(0), + spdy_protocol_version_(0), ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_for_send_pending_(this)) { } @@ -312,7 +313,9 @@ int WebSocketJob::OnReceivedSpdyResponseHeader( if (status != OK) return status; // TODO(toyoshim): Fallback to non-spdy connection? - handshake_response_->ParseResponseHeaderBlock(headers, challenge_); + handshake_response_->ParseResponseHeaderBlock(headers, + challenge_, + spdy_protocol_version_); SaveCookiesAndNotifyHeaderComplete(); return OK; @@ -389,7 +392,7 @@ void WebSocketJob::DoSendData() { if (spdy_websocket_stream_.get()) { scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock); handshake_request_->GetRequestHeaderBlock( - socket_->url(), headers.get(), &challenge_); + socket_->url(), headers.get(), &challenge_, spdy_protocol_version_); spdy_websocket_stream_->SendRequest(headers.Pass()); } else { const std::string& handshake_request = @@ -567,6 +570,7 @@ int WebSocketJob::TrySpdyStream() { return OK; // Create SpdyWebSocketStream. + spdy_protocol_version_ = spdy_session->GetProtocolVersion(); spdy_websocket_stream_.reset(new SpdyWebSocketStream(spdy_session, this)); int result = spdy_websocket_stream_->InitializeStream( diff --git a/net/websockets/websocket_job.h b/net/websockets/websocket_job.h index 7e20441..614a8e4 100644 --- a/net/websockets/websocket_job.h +++ b/net/websockets/websocket_job.h @@ -138,6 +138,7 @@ class NET_EXPORT WebSocketJob scoped_refptr<DrainableIOBuffer> current_send_buffer_; std::vector<char> received_data_after_handshake_; + int spdy_protocol_version_; scoped_ptr<SpdyWebSocketStream> spdy_websocket_stream_; std::string challenge_; diff --git a/net/websockets/websocket_job_spdy3_unittest.cc b/net/websockets/websocket_job_spdy3_unittest.cc index a05c094..b758252 100644 --- a/net/websockets/websocket_job_spdy3_unittest.cc +++ b/net/websockets/websocket_job_spdy3_unittest.cc @@ -544,17 +544,17 @@ const char WebSocketJobSpdy3Test::kDataHello[] = "Hello, "; const char WebSocketJobSpdy3Test::kDataWorld[] = "World!\n"; const char* const WebSocketJobSpdy3Test::kHandshakeRequestForSpdy[] = { - "path", "/demo", - "version", "WebSocket/13", - "scheme", "ws", - "host", "example.com", - "origin", "http://example.com", - "sec-websocket-protocol", "sample" + ":path", "/demo", + ":version", "WebSocket/13", + ":scheme", "ws", + ":host", "example.com", + ":origin", "http://example.com", + ":sec-websocket-protocol", "sample" }; const char* const WebSocketJobSpdy3Test::kHandshakeResponseForSpdy[] = { - "status", "101 Switching Protocols", - "sec-websocket-protocol", "sample" + ":status", "101 Switching Protocols", + ":sec-websocket-protocol", "sample" }; const size_t WebSocketJobSpdy3Test::kHandshakeRequestWithoutCookieLength = |