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 |