| Index: net/websockets/websocket_handshake_unittest.cc
|
| diff --git a/net/websockets/websocket_handshake_unittest.cc b/net/websockets/websocket_handshake_unittest.cc
|
| index beae8059ae8ff673f24a540a7d1f83c171c3ea1c..f68855404aa37fa0a585deb635993fdff88ebb19 100644
|
| --- a/net/websockets/websocket_handshake_unittest.cc
|
| +++ b/net/websockets/websocket_handshake_unittest.cc
|
| @@ -6,6 +6,7 @@
|
| #include <vector>
|
|
|
| #include "base/scoped_ptr.h"
|
| +#include "base/string_util.h"
|
| #include "net/websockets/websocket_handshake.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
| #include "testing/gmock/include/gmock/gmock.h"
|
| @@ -13,100 +14,216 @@
|
|
|
| namespace net {
|
|
|
| -TEST(WebSocketHandshakeTest, Connect) {
|
| +class WebSocketHandshakeTest : public testing::Test {
|
| + public:
|
| + static void SetUpParameter(WebSocketHandshake* handshake,
|
| + uint32 number_1, uint32 number_2,
|
| + const std::string& key_1, const std::string& key_2,
|
| + const std::string& key_3) {
|
| + WebSocketHandshake::Parameter* parameter =
|
| + new WebSocketHandshake::Parameter;
|
| + parameter->number_1_ = number_1;
|
| + parameter->number_2_ = number_2;
|
| + parameter->key_1_ = key_1;
|
| + parameter->key_2_ = key_2;
|
| + parameter->key_3_ = key_3;
|
| + handshake->parameter_.reset(parameter);
|
| + }
|
| +
|
| + static void ExpectHeaderEquals(const std::string& expected,
|
| + const std::string& actual) {
|
| + std::vector<std::string> expected_lines;
|
| + Tokenize(expected, "\r\n", &expected_lines);
|
| + std::vector<std::string> actual_lines;
|
| + Tokenize(actual, "\r\n", &actual_lines);
|
| + // Request lines.
|
| + EXPECT_EQ(expected_lines[0], actual_lines[0]);
|
| +
|
| + std::vector<std::string> expected_headers;
|
| + for (size_t i = 1; i < expected_lines.size(); i++) {
|
| + // Finish at first CRLF CRLF. Note that /key_3/ might include CRLF.
|
| + if (expected_lines[i] == "")
|
| + break;
|
| + expected_headers.push_back(expected_lines[i]);
|
| + }
|
| + sort(expected_headers.begin(), expected_headers.end());
|
| +
|
| + std::vector<std::string> actual_headers;
|
| + for (size_t i = 1; i < actual_lines.size(); i++) {
|
| + // Finish at first CRLF CRLF. Note that /key_3/ might include CRLF.
|
| + if (actual_lines[i] == "")
|
| + break;
|
| + actual_headers.push_back(actual_lines[i]);
|
| + }
|
| + sort(actual_headers.begin(), actual_headers.end());
|
| +
|
| + EXPECT_EQ(expected_headers.size(), actual_headers.size())
|
| + << "expected:" << expected
|
| + << "\nactual:" << actual;
|
| + for (size_t i = 0; i < expected_headers.size(); i++) {
|
| + EXPECT_EQ(expected_headers[i], actual_headers[i]);
|
| + }
|
| + }
|
| +
|
| + static void ExpectHandshakeMessageEquals(const std::string& expected,
|
| + const std::string& actual) {
|
| + // Headers.
|
| + ExpectHeaderEquals(expected, actual);
|
| + // Compare tailing \r\n\r\n<key3> (4 + 8 bytes).
|
| + ASSERT_GT(expected.size(), 12U);
|
| + const char* expected_key3 = expected.data() + expected.size() - 12;
|
| + EXPECT_GT(actual.size(), 12U);
|
| + if (actual.size() <= 12U)
|
| + return;
|
| + const char* actual_key3 = actual.data() + actual.size() - 12;
|
| + EXPECT_TRUE(memcmp(expected_key3, actual_key3, 12) == 0)
|
| + << "expected_key3:" << DumpKey(expected_key3, 12)
|
| + << ", actual_key3:" << DumpKey(actual_key3, 12);
|
| + }
|
| +
|
| + static std::string DumpKey(const char* buf, int len) {
|
| + std::string s;
|
| + for (int i = 0; i < len; i++) {
|
| + if (isprint(buf[i]))
|
| + s += StringPrintf("%c", buf[i]);
|
| + else
|
| + s += StringPrintf("\\x%02x", buf[i]);
|
| + }
|
| + return s;
|
| + }
|
| +
|
| + static std::string GetResourceName(WebSocketHandshake* handshake) {
|
| + return handshake->GetResourceName();
|
| + }
|
| + static std::string GetHostFieldValue(WebSocketHandshake* handshake) {
|
| + return handshake->GetHostFieldValue();
|
| + }
|
| + static std::string GetOriginFieldValue(WebSocketHandshake* handshake) {
|
| + return handshake->GetOriginFieldValue();
|
| + }
|
| +};
|
| +
|
| +
|
| +TEST_F(WebSocketHandshakeTest, Connect) {
|
| const std::string kExpectedClientHandshakeMessage =
|
| "GET /demo HTTP/1.1\r\n"
|
| "Upgrade: WebSocket\r\n"
|
| "Connection: Upgrade\r\n"
|
| "Host: example.com\r\n"
|
| "Origin: http://example.com\r\n"
|
| - "WebSocket-Protocol: sample\r\n"
|
| - "\r\n";
|
| + "Sec-WebSocket-Protocol: sample\r\n"
|
| + "Sec-WebSocket-Key1: 388P O503D&ul7 {K%gX( %7 15\r\n"
|
| + "Sec-WebSocket-Key2: 1 N ?|k UT0or 3o 4 I97N 5-S3O 31\r\n"
|
| + "\r\n"
|
| + "\x47\x30\x22\x2D\x5A\x3F\x47\x58";
|
|
|
| scoped_ptr<WebSocketHandshake> handshake(
|
| new WebSocketHandshake(GURL("ws://example.com/demo"),
|
| "http://example.com",
|
| "ws://example.com/demo",
|
| "sample"));
|
| + SetUpParameter(handshake.get(), 777007543U, 114997259U,
|
| + "388P O503D&ul7 {K%gX( %7 15",
|
| + "1 N ?|k UT0or 3o 4 I97N 5-S3O 31",
|
| + std::string("\x47\x30\x22\x2D\x5A\x3F\x47\x58", 8));
|
| EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
|
| - EXPECT_EQ(kExpectedClientHandshakeMessage,
|
| - handshake->CreateClientHandshakeMessage());
|
| + ExpectHandshakeMessageEquals(
|
| + kExpectedClientHandshakeMessage,
|
| + handshake->CreateClientHandshakeMessage());
|
|
|
| - const char kResponse[] = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
|
| + const char kResponse[] = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
|
| "Upgrade: WebSocket\r\n"
|
| "Connection: Upgrade\r\n"
|
| - "WebSocket-Origin: http://example.com\r\n"
|
| - "WebSocket-Location: ws://example.com/demo\r\n"
|
| - "WebSocket-Protocol: sample\r\n"
|
| - "\r\n";
|
| + "Sec-WebSocket-Origin: http://example.com\r\n"
|
| + "Sec-WebSocket-Location: ws://example.com/demo\r\n"
|
| + "Sec-WebSocket-Protocol: sample\r\n"
|
| + "\r\n"
|
| + "\x30\x73\x74\x33\x52\x6C\x26\x71\x2D\x32\x5A\x55\x5E\x77\x65\x75";
|
| + std::vector<std::string> response_lines;
|
| + SplitStringDontTrim(kResponse, '\n', &response_lines);
|
|
|
| EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
|
| // too short
|
| EXPECT_EQ(-1, handshake->ReadServerHandshake(kResponse, 16));
|
| EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
|
| +
|
| // only status line
|
| + std::string response = response_lines[0];
|
| EXPECT_EQ(-1, handshake->ReadServerHandshake(
|
| - kResponse,
|
| - WebSocketHandshake::kServerHandshakeHeaderLength));
|
| - EXPECT_EQ(WebSocketHandshake::MODE_NORMAL, handshake->mode());
|
| + response.data(), response.size()));
|
| + EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
|
| // by upgrade header
|
| + response += response_lines[1];
|
| EXPECT_EQ(-1, handshake->ReadServerHandshake(
|
| - kResponse,
|
| - WebSocketHandshake::kServerHandshakeHeaderLength +
|
| - WebSocketHandshake::kUpgradeHeaderLength));
|
| - EXPECT_EQ(WebSocketHandshake::MODE_NORMAL, handshake->mode());
|
| + response.data(), response.size()));
|
| + EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
|
| // by connection header
|
| + response += response_lines[2];
|
| EXPECT_EQ(-1, handshake->ReadServerHandshake(
|
| - kResponse,
|
| - WebSocketHandshake::kServerHandshakeHeaderLength +
|
| - WebSocketHandshake::kUpgradeHeaderLength +
|
| - WebSocketHandshake::kConnectionHeaderLength));
|
| - EXPECT_EQ(WebSocketHandshake::MODE_NORMAL, handshake->mode());
|
| + response.data(), response.size()));
|
| + EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
|
|
|
| + response += response_lines[3]; // Sec-WebSocket-Origin
|
| + response += response_lines[4]; // Sec-WebSocket-Location
|
| + response += response_lines[5]; // Sec-WebSocket-Protocol
|
| EXPECT_EQ(-1, handshake->ReadServerHandshake(
|
| - kResponse, sizeof(kResponse) - 2));
|
| - EXPECT_EQ(WebSocketHandshake::MODE_NORMAL, handshake->mode());
|
| + response.data(), response.size()));
|
| + EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
|
|
|
| - int handshake_length = strlen(kResponse);
|
| + response += response_lines[6]; // \r\n
|
| + EXPECT_EQ(-1, handshake->ReadServerHandshake(
|
| + response.data(), response.size()));
|
| + EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
|
| +
|
| + int handshake_length = sizeof(kResponse) - 1; // -1 for terminating \0
|
| EXPECT_EQ(handshake_length, handshake->ReadServerHandshake(
|
| - kResponse, sizeof(kResponse) - 1)); // -1 for terminating \0
|
| + kResponse, handshake_length)); // -1 for terminating \0
|
| EXPECT_EQ(WebSocketHandshake::MODE_CONNECTED, handshake->mode());
|
| }
|
|
|
| -TEST(WebSocketHandshakeTest, ServerSentData) {
|
| +TEST_F(WebSocketHandshakeTest, ServerSentData) {
|
| const std::string kExpectedClientHandshakeMessage =
|
| "GET /demo HTTP/1.1\r\n"
|
| "Upgrade: WebSocket\r\n"
|
| "Connection: Upgrade\r\n"
|
| "Host: example.com\r\n"
|
| "Origin: http://example.com\r\n"
|
| - "WebSocket-Protocol: sample\r\n"
|
| - "\r\n";
|
| + "Sec-WebSocket-Protocol: sample\r\n"
|
| + "Sec-WebSocket-Key1: 388P O503D&ul7 {K%gX( %7 15\r\n"
|
| + "Sec-WebSocket-Key2: 1 N ?|k UT0or 3o 4 I97N 5-S3O 31\r\n"
|
| + "\r\n"
|
| + "\x47\x30\x22\x2D\x5A\x3F\x47\x58";
|
| scoped_ptr<WebSocketHandshake> handshake(
|
| new WebSocketHandshake(GURL("ws://example.com/demo"),
|
| "http://example.com",
|
| "ws://example.com/demo",
|
| "sample"));
|
| + SetUpParameter(handshake.get(), 777007543U, 114997259U,
|
| + "388P O503D&ul7 {K%gX( %7 15",
|
| + "1 N ?|k UT0or 3o 4 I97N 5-S3O 31",
|
| + std::string("\x47\x30\x22\x2D\x5A\x3F\x47\x58", 8));
|
| EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
|
| - EXPECT_EQ(kExpectedClientHandshakeMessage,
|
| - handshake->CreateClientHandshakeMessage());
|
| + ExpectHandshakeMessageEquals(
|
| + kExpectedClientHandshakeMessage,
|
| + handshake->CreateClientHandshakeMessage());
|
|
|
| - const char kResponse[] ="HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
|
| + const char kResponse[] = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
|
| "Upgrade: WebSocket\r\n"
|
| "Connection: Upgrade\r\n"
|
| - "WebSocket-Origin: http://example.com\r\n"
|
| - "WebSocket-Location: ws://example.com/demo\r\n"
|
| - "WebSocket-Protocol: sample\r\n"
|
| + "Sec-WebSocket-Origin: http://example.com\r\n"
|
| + "Sec-WebSocket-Location: ws://example.com/demo\r\n"
|
| + "Sec-WebSocket-Protocol: sample\r\n"
|
| "\r\n"
|
| + "\x30\x73\x74\x33\x52\x6C\x26\x71\x2D\x32\x5A\x55\x5E\x77\x65\x75"
|
| "\0Hello\xff";
|
|
|
| - int handshake_length = strlen(kResponse);
|
| + int handshake_length = strlen(kResponse); // key3 doesn't contain \0.
|
| EXPECT_EQ(handshake_length, handshake->ReadServerHandshake(
|
| kResponse, sizeof(kResponse) - 1)); // -1 for terminating \0
|
| EXPECT_EQ(WebSocketHandshake::MODE_CONNECTED, handshake->mode());
|
| }
|
|
|
| -TEST(WebSocketHandshakeTest, is_secure_false) {
|
| +TEST_F(WebSocketHandshakeTest, is_secure_false) {
|
| scoped_ptr<WebSocketHandshake> handshake(
|
| new WebSocketHandshake(GURL("ws://example.com/demo"),
|
| "http://example.com",
|
| @@ -115,7 +232,7 @@ TEST(WebSocketHandshakeTest, is_secure_false) {
|
| EXPECT_FALSE(handshake->is_secure());
|
| }
|
|
|
| -TEST(WebSocketHandshakeTest, is_secure_true) {
|
| +TEST_F(WebSocketHandshakeTest, is_secure_true) {
|
| // wss:// is secure.
|
| scoped_ptr<WebSocketHandshake> handshake(
|
| new WebSocketHandshake(GURL("wss://example.com/demo"),
|
| @@ -125,80 +242,59 @@ TEST(WebSocketHandshakeTest, is_secure_true) {
|
| EXPECT_TRUE(handshake->is_secure());
|
| }
|
|
|
| -TEST(WebSocketHandshakeTest, CreateClientHandshakeMessage_Simple) {
|
| - scoped_ptr<WebSocketHandshake> handshake(
|
| - new WebSocketHandshake(GURL("ws://example.com/demo"),
|
| - "http://example.com",
|
| - "ws://example.com/demo",
|
| - "sample"));
|
| - EXPECT_EQ("GET /demo HTTP/1.1\r\n"
|
| - "Upgrade: WebSocket\r\n"
|
| - "Connection: Upgrade\r\n"
|
| - "Host: example.com\r\n"
|
| - "Origin: http://example.com\r\n"
|
| - "WebSocket-Protocol: sample\r\n"
|
| - "\r\n",
|
| - handshake->CreateClientHandshakeMessage());
|
| -}
|
| -
|
| -TEST(WebSocketHandshakeTest, CreateClientHandshakeMessage_PathAndQuery) {
|
| +TEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_ResourceName) {
|
| scoped_ptr<WebSocketHandshake> handshake(
|
| new WebSocketHandshake(GURL("ws://example.com/Test?q=xxx&p=%20"),
|
| "http://example.com",
|
| "ws://example.com/demo",
|
| "sample"));
|
| // Path and query should be preserved as-is.
|
| - EXPECT_THAT(handshake->CreateClientHandshakeMessage(),
|
| - testing::HasSubstr("GET /Test?q=xxx&p=%20 HTTP/1.1\r\n"));
|
| + EXPECT_EQ("/Test?q=xxx&p=%20", GetResourceName(handshake.get()));
|
| }
|
|
|
| -TEST(WebSocketHandshakeTest, CreateClientHandshakeMessage_Host) {
|
| +TEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_Host) {
|
| scoped_ptr<WebSocketHandshake> handshake(
|
| new WebSocketHandshake(GURL("ws://Example.Com/demo"),
|
| "http://Example.Com",
|
| "ws://Example.Com/demo",
|
| "sample"));
|
| // Host should be lowercased
|
| - EXPECT_THAT(handshake->CreateClientHandshakeMessage(),
|
| - testing::HasSubstr("Host: example.com\r\n"));
|
| - EXPECT_THAT(handshake->CreateClientHandshakeMessage(),
|
| - testing::HasSubstr("Origin: http://example.com\r\n"));
|
| + EXPECT_EQ("example.com", GetHostFieldValue(handshake.get()));
|
| + EXPECT_EQ("http://example.com", GetOriginFieldValue(handshake.get()));
|
| }
|
|
|
| -TEST(WebSocketHandshakeTest, CreateClientHandshakeMessage_TrimPort80) {
|
| +TEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_TrimPort80) {
|
| scoped_ptr<WebSocketHandshake> handshake(
|
| new WebSocketHandshake(GURL("ws://example.com:80/demo"),
|
| "http://example.com",
|
| "ws://example.com/demo",
|
| "sample"));
|
| // :80 should be trimmed as it's the default port for ws://.
|
| - EXPECT_THAT(handshake->CreateClientHandshakeMessage(),
|
| - testing::HasSubstr("Host: example.com\r\n"));
|
| + EXPECT_EQ("example.com", GetHostFieldValue(handshake.get()));
|
| }
|
|
|
| -TEST(WebSocketHandshakeTest, CreateClientHandshakeMessage_TrimPort443) {
|
| +TEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_TrimPort443) {
|
| scoped_ptr<WebSocketHandshake> handshake(
|
| new WebSocketHandshake(GURL("wss://example.com:443/demo"),
|
| "http://example.com",
|
| "wss://example.com/demo",
|
| "sample"));
|
| // :443 should be trimmed as it's the default port for wss://.
|
| - EXPECT_THAT(handshake->CreateClientHandshakeMessage(),
|
| - testing::HasSubstr("Host: example.com\r\n"));
|
| + EXPECT_EQ("example.com", GetHostFieldValue(handshake.get()));
|
| }
|
|
|
| -TEST(WebSocketHandshakeTest, CreateClientHandshakeMessage_NonDefaultPortForWs) {
|
| +TEST_F(WebSocketHandshakeTest,
|
| + CreateClientHandshakeMessage_NonDefaultPortForWs) {
|
| scoped_ptr<WebSocketHandshake> handshake(
|
| new WebSocketHandshake(GURL("ws://example.com:8080/demo"),
|
| "http://example.com",
|
| "wss://example.com/demo",
|
| "sample"));
|
| // :8080 should be preserved as it's not the default port for ws://.
|
| - EXPECT_THAT(handshake->CreateClientHandshakeMessage(),
|
| - testing::HasSubstr("Host: example.com:8080\r\n"));
|
| + EXPECT_EQ("example.com:8080", GetHostFieldValue(handshake.get()));
|
| }
|
|
|
| -TEST(WebSocketHandshakeTest,
|
| +TEST_F(WebSocketHandshakeTest,
|
| CreateClientHandshakeMessage_NonDefaultPortForWss) {
|
| scoped_ptr<WebSocketHandshake> handshake(
|
| new WebSocketHandshake(GURL("wss://example.com:4443/demo"),
|
| @@ -206,30 +302,27 @@ TEST(WebSocketHandshakeTest,
|
| "wss://example.com/demo",
|
| "sample"));
|
| // :4443 should be preserved as it's not the default port for wss://.
|
| - EXPECT_THAT(handshake->CreateClientHandshakeMessage(),
|
| - testing::HasSubstr("Host: example.com:4443\r\n"));
|
| + EXPECT_EQ("example.com:4443", GetHostFieldValue(handshake.get()));
|
| }
|
|
|
| -TEST(WebSocketHandshakeTest, CreateClientHandshakeMessage_WsBut443) {
|
| +TEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_WsBut443) {
|
| scoped_ptr<WebSocketHandshake> handshake(
|
| new WebSocketHandshake(GURL("ws://example.com:443/demo"),
|
| "http://example.com",
|
| "ws://example.com/demo",
|
| "sample"));
|
| // :443 should be preserved as it's not the default port for ws://.
|
| - EXPECT_THAT(handshake->CreateClientHandshakeMessage(),
|
| - testing::HasSubstr("Host: example.com:443\r\n"));
|
| + EXPECT_EQ("example.com:443", GetHostFieldValue(handshake.get()));
|
| }
|
|
|
| -TEST(WebSocketHandshakeTest, CreateClientHandshakeMessage_WssBut80) {
|
| +TEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_WssBut80) {
|
| scoped_ptr<WebSocketHandshake> handshake(
|
| new WebSocketHandshake(GURL("wss://example.com:80/demo"),
|
| "http://example.com",
|
| "wss://example.com/demo",
|
| "sample"));
|
| // :80 should be preserved as it's not the default port for wss://.
|
| - EXPECT_THAT(handshake->CreateClientHandshakeMessage(),
|
| - testing::HasSubstr("Host: example.com:80\r\n"));
|
| + EXPECT_EQ("example.com:80", GetHostFieldValue(handshake.get()));
|
| }
|
|
|
| } // namespace net
|
|
|