| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/websockets/websocket_handshake_handler.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/basictypes.h" | |
| 11 #include "base/strings/string_util.h" | |
| 12 #include "base/strings/stringprintf.h" | |
| 13 #include "net/http/http_response_headers.h" | |
| 14 #include "net/http/http_util.h" | |
| 15 #include "url/gurl.h" | |
| 16 | |
| 17 #include "testing/gtest/include/gtest/gtest.h" | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 const char* const kCookieHeaders[] = { | |
| 22 "cookie", "cookie2" | |
| 23 }; | |
| 24 | |
| 25 const char* const kSetCookieHeaders[] = { | |
| 26 "set-cookie", "set-cookie2" | |
| 27 }; | |
| 28 | |
| 29 // A test fixture to simplify tests for GetKeyNumber(). | |
| 30 class WebSocketHandshakeGetKeyNumberTest : public ::testing::Test { | |
| 31 protected: | |
| 32 static const char kExampleFromDraftKey1[]; | |
| 33 | |
| 34 // The object is default-initialised with an empty challenge and the example | |
| 35 // key from draft-ietf-hybi-thewebsocketprotocol-00. These can be changed | |
| 36 // using set_challenge() and set_key(). | |
| 37 WebSocketHandshakeGetKeyNumberTest() | |
| 38 : challenge_(), key_(kExampleFromDraftKey1) {} | |
| 39 | |
| 40 // A convenience wrapper for the function under test which automatically | |
| 41 // passes in the arguments stored in the object. | |
| 42 void GetKeyNumber() { ::net::internal::GetKeyNumber(key_, &challenge_); } | |
| 43 | |
| 44 // Read current challenge. | |
| 45 const std::string& challenge() const { return challenge_; } | |
| 46 | |
| 47 // Overwrite challenge. | |
| 48 void set_challenge(const std::string& challenge) { challenge_ = challenge; } | |
| 49 | |
| 50 // Reset the challenge to be empty. | |
| 51 void reset_challenge() { challenge_.clear(); } | |
| 52 | |
| 53 // Change key. | |
| 54 void set_key(const std::string& key) { key_ = key; } | |
| 55 | |
| 56 private: | |
| 57 std::string challenge_; | |
| 58 std::string key_; | |
| 59 }; | |
| 60 | |
| 61 const char WebSocketHandshakeGetKeyNumberTest::kExampleFromDraftKey1[] = | |
| 62 "3e6b263 4 17 80"; | |
| 63 | |
| 64 // A version of the above fixture for death tests. | |
| 65 class WebSocketHandshakeGetKeyNumberDeathTest | |
| 66 : public WebSocketHandshakeGetKeyNumberTest { | |
| 67 }; | |
| 68 | |
| 69 } // namespace | |
| 70 | |
| 71 namespace net { | |
| 72 | |
| 73 TEST(WebSocketHandshakeRequestHandlerTest, SimpleRequest) { | |
| 74 WebSocketHandshakeRequestHandler handler; | |
| 75 | |
| 76 static const char kHandshakeRequestMessage[] = | |
| 77 "GET /demo HTTP/1.1\r\n" | |
| 78 "Host: example.com\r\n" | |
| 79 "Connection: Upgrade\r\n" | |
| 80 "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n" | |
| 81 "Sec-WebSocket-Protocol: sample\r\n" | |
| 82 "Upgrade: WebSocket\r\n" | |
| 83 "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n" | |
| 84 "Origin: http://example.com\r\n" | |
| 85 "\r\n" | |
| 86 "^n:ds[4U"; | |
| 87 | |
| 88 EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage, | |
| 89 strlen(kHandshakeRequestMessage))); | |
| 90 EXPECT_EQ(0, handler.protocol_version()); | |
| 91 | |
| 92 handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders)); | |
| 93 | |
| 94 EXPECT_EQ(kHandshakeRequestMessage, handler.GetRawRequest()); | |
| 95 } | |
| 96 | |
| 97 TEST(WebSocketHandshakeRequestHandlerTest, SimpleRequestHybi06Handshake) { | |
| 98 WebSocketHandshakeRequestHandler handler; | |
| 99 | |
| 100 static const char kHandshakeRequestMessage[] = | |
| 101 "GET /demo HTTP/1.1\r\n" | |
| 102 "Host: example.com\r\n" | |
| 103 "Upgrade: websocket\r\n" | |
| 104 "Connection: Upgrade\r\n" | |
| 105 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
| 106 "Sec-WebSocket-Origin: http://example.com\r\n" | |
| 107 "Sec-WebSocket-Protocol: sample\r\n" | |
| 108 "Sec-WebSocket-Version: 6\r\n" | |
| 109 "\r\n"; | |
| 110 | |
| 111 EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage, | |
| 112 strlen(kHandshakeRequestMessage))); | |
| 113 EXPECT_EQ(6, handler.protocol_version()); | |
| 114 | |
| 115 handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders)); | |
| 116 | |
| 117 EXPECT_EQ(kHandshakeRequestMessage, handler.GetRawRequest()); | |
| 118 } | |
| 119 | |
| 120 TEST(WebSocketHandshakeRequestHandlerTest, ReplaceRequestCookies) { | |
| 121 WebSocketHandshakeRequestHandler handler; | |
| 122 | |
| 123 static const char kHandshakeRequestMessage[] = | |
| 124 "GET /demo HTTP/1.1\r\n" | |
| 125 "Host: example.com\r\n" | |
| 126 "Connection: Upgrade\r\n" | |
| 127 "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n" | |
| 128 "Sec-WebSocket-Protocol: sample\r\n" | |
| 129 "Upgrade: WebSocket\r\n" | |
| 130 "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n" | |
| 131 "Origin: http://example.com\r\n" | |
| 132 "Cookie: WK-websocket-test=1\r\n" | |
| 133 "\r\n" | |
| 134 "^n:ds[4U"; | |
| 135 | |
| 136 EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage, | |
| 137 strlen(kHandshakeRequestMessage))); | |
| 138 EXPECT_EQ(0, handler.protocol_version()); | |
| 139 | |
| 140 handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders)); | |
| 141 | |
| 142 handler.AppendHeaderIfMissing("Cookie", | |
| 143 "WK-websocket-test=1; " | |
| 144 "WK-websocket-test-httponly=1"); | |
| 145 | |
| 146 static const char kHandshakeRequestExpectedMessage[] = | |
| 147 "GET /demo HTTP/1.1\r\n" | |
| 148 "Host: example.com\r\n" | |
| 149 "Connection: Upgrade\r\n" | |
| 150 "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n" | |
| 151 "Sec-WebSocket-Protocol: sample\r\n" | |
| 152 "Upgrade: WebSocket\r\n" | |
| 153 "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n" | |
| 154 "Origin: http://example.com\r\n" | |
| 155 "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n" | |
| 156 "\r\n" | |
| 157 "^n:ds[4U"; | |
| 158 | |
| 159 EXPECT_EQ(kHandshakeRequestExpectedMessage, handler.GetRawRequest()); | |
| 160 } | |
| 161 | |
| 162 TEST(WebSocketHandshakeRequestHandlerTest, | |
| 163 ReplaceRequestCookiesHybi06Handshake) { | |
| 164 WebSocketHandshakeRequestHandler handler; | |
| 165 | |
| 166 static const char kHandshakeRequestMessage[] = | |
| 167 "GET /demo HTTP/1.1\r\n" | |
| 168 "Host: example.com\r\n" | |
| 169 "Upgrade: websocket\r\n" | |
| 170 "Connection: Upgrade\r\n" | |
| 171 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
| 172 "Sec-WebSocket-Origin: http://example.com\r\n" | |
| 173 "Sec-WebSocket-Protocol: sample\r\n" | |
| 174 "Sec-WebSocket-Version: 6\r\n" | |
| 175 "Cookie: WK-websocket-test=1\r\n" | |
| 176 "\r\n"; | |
| 177 | |
| 178 EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage, | |
| 179 strlen(kHandshakeRequestMessage))); | |
| 180 EXPECT_EQ(6, handler.protocol_version()); | |
| 181 | |
| 182 handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders)); | |
| 183 | |
| 184 handler.AppendHeaderIfMissing("Cookie", | |
| 185 "WK-websocket-test=1; " | |
| 186 "WK-websocket-test-httponly=1"); | |
| 187 | |
| 188 static const char kHandshakeRequestExpectedMessage[] = | |
| 189 "GET /demo HTTP/1.1\r\n" | |
| 190 "Host: example.com\r\n" | |
| 191 "Upgrade: websocket\r\n" | |
| 192 "Connection: Upgrade\r\n" | |
| 193 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
| 194 "Sec-WebSocket-Origin: http://example.com\r\n" | |
| 195 "Sec-WebSocket-Protocol: sample\r\n" | |
| 196 "Sec-WebSocket-Version: 6\r\n" | |
| 197 "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n" | |
| 198 "\r\n"; | |
| 199 | |
| 200 EXPECT_EQ(kHandshakeRequestExpectedMessage, handler.GetRawRequest()); | |
| 201 } | |
| 202 | |
| 203 TEST(WebSocketHandshakeResponseHandlerTest, SimpleResponse) { | |
| 204 WebSocketHandshakeResponseHandler handler; | |
| 205 EXPECT_EQ(0, handler.protocol_version()); | |
| 206 | |
| 207 static const char kHandshakeResponseMessage[] = | |
| 208 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" | |
| 209 "Upgrade: WebSocket\r\n" | |
| 210 "Connection: Upgrade\r\n" | |
| 211 "Sec-WebSocket-Origin: http://example.com\r\n" | |
| 212 "Sec-WebSocket-Location: ws://example.com/demo\r\n" | |
| 213 "Sec-WebSocket-Protocol: sample\r\n" | |
| 214 "\r\n" | |
| 215 "8jKS'y:G*Co,Wxa-"; | |
| 216 | |
| 217 EXPECT_EQ(strlen(kHandshakeResponseMessage), | |
| 218 handler.ParseRawResponse(kHandshakeResponseMessage, | |
| 219 strlen(kHandshakeResponseMessage))); | |
| 220 EXPECT_TRUE(handler.HasResponse()); | |
| 221 | |
| 222 handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders)); | |
| 223 | |
| 224 EXPECT_EQ(kHandshakeResponseMessage, handler.GetResponse()); | |
| 225 } | |
| 226 | |
| 227 TEST(WebSocketHandshakeResponseHandlerTest, SimpleResponseHybi06Handshake) { | |
| 228 WebSocketHandshakeResponseHandler handler; | |
| 229 handler.set_protocol_version(6); | |
| 230 EXPECT_EQ(6, handler.protocol_version()); | |
| 231 | |
| 232 static const char kHandshakeResponseMessage[] = | |
| 233 "HTTP/1.1 101 Switching Protocols\r\n" | |
| 234 "Upgrade: websocket\r\n" | |
| 235 "Connection: Upgrade\r\n" | |
| 236 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | |
| 237 "Sec-WebSocket-Protocol: sample\r\n" | |
| 238 "\r\n"; | |
| 239 | |
| 240 EXPECT_EQ(strlen(kHandshakeResponseMessage), | |
| 241 handler.ParseRawResponse(kHandshakeResponseMessage, | |
| 242 strlen(kHandshakeResponseMessage))); | |
| 243 EXPECT_TRUE(handler.HasResponse()); | |
| 244 | |
| 245 handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders)); | |
| 246 | |
| 247 EXPECT_EQ(kHandshakeResponseMessage, handler.GetResponse()); | |
| 248 } | |
| 249 | |
| 250 TEST(WebSocketHandshakeResponseHandlerTest, ReplaceResponseCookies) { | |
| 251 WebSocketHandshakeResponseHandler handler; | |
| 252 EXPECT_EQ(0, handler.protocol_version()); | |
| 253 | |
| 254 static const char kHandshakeResponseMessage[] = | |
| 255 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" | |
| 256 "Upgrade: WebSocket\r\n" | |
| 257 "Connection: Upgrade\r\n" | |
| 258 "Sec-WebSocket-Origin: http://example.com\r\n" | |
| 259 "Sec-WebSocket-Location: ws://example.com/demo\r\n" | |
| 260 "Sec-WebSocket-Protocol: sample\r\n" | |
| 261 "Set-Cookie: WK-websocket-test-1\r\n" | |
| 262 "Set-Cookie: WK-websocket-test-httponly=1; HttpOnly\r\n" | |
| 263 "\r\n" | |
| 264 "8jKS'y:G*Co,Wxa-"; | |
| 265 | |
| 266 EXPECT_EQ(strlen(kHandshakeResponseMessage), | |
| 267 handler.ParseRawResponse(kHandshakeResponseMessage, | |
| 268 strlen(kHandshakeResponseMessage))); | |
| 269 EXPECT_TRUE(handler.HasResponse()); | |
| 270 std::vector<std::string> cookies; | |
| 271 handler.GetHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders), &cookies); | |
| 272 ASSERT_EQ(2U, cookies.size()); | |
| 273 EXPECT_EQ("WK-websocket-test-1", cookies[0]); | |
| 274 EXPECT_EQ("WK-websocket-test-httponly=1; HttpOnly", cookies[1]); | |
| 275 handler.RemoveHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders)); | |
| 276 | |
| 277 static const char kHandshakeResponseExpectedMessage[] = | |
| 278 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" | |
| 279 "Upgrade: WebSocket\r\n" | |
| 280 "Connection: Upgrade\r\n" | |
| 281 "Sec-WebSocket-Origin: http://example.com\r\n" | |
| 282 "Sec-WebSocket-Location: ws://example.com/demo\r\n" | |
| 283 "Sec-WebSocket-Protocol: sample\r\n" | |
| 284 "\r\n" | |
| 285 "8jKS'y:G*Co,Wxa-"; | |
| 286 | |
| 287 EXPECT_EQ(kHandshakeResponseExpectedMessage, handler.GetResponse()); | |
| 288 } | |
| 289 | |
| 290 TEST(WebSocketHandshakeResponseHandlerTest, | |
| 291 ReplaceResponseCookiesHybi06Handshake) { | |
| 292 WebSocketHandshakeResponseHandler handler; | |
| 293 handler.set_protocol_version(6); | |
| 294 EXPECT_EQ(6, handler.protocol_version()); | |
| 295 | |
| 296 static const char kHandshakeResponseMessage[] = | |
| 297 "HTTP/1.1 101 Switching Protocols\r\n" | |
| 298 "Upgrade: websocket\r\n" | |
| 299 "Connection: Upgrade\r\n" | |
| 300 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | |
| 301 "Sec-WebSocket-Protocol: sample\r\n" | |
| 302 "Set-Cookie: WK-websocket-test-1\r\n" | |
| 303 "Set-Cookie: WK-websocket-test-httponly=1; HttpOnly\r\n" | |
| 304 "\r\n"; | |
| 305 | |
| 306 EXPECT_EQ(strlen(kHandshakeResponseMessage), | |
| 307 handler.ParseRawResponse(kHandshakeResponseMessage, | |
| 308 strlen(kHandshakeResponseMessage))); | |
| 309 EXPECT_TRUE(handler.HasResponse()); | |
| 310 std::vector<std::string> cookies; | |
| 311 handler.GetHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders), &cookies); | |
| 312 ASSERT_EQ(2U, cookies.size()); | |
| 313 EXPECT_EQ("WK-websocket-test-1", cookies[0]); | |
| 314 EXPECT_EQ("WK-websocket-test-httponly=1; HttpOnly", cookies[1]); | |
| 315 handler.RemoveHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders)); | |
| 316 | |
| 317 static const char kHandshakeResponseExpectedMessage[] = | |
| 318 "HTTP/1.1 101 Switching Protocols\r\n" | |
| 319 "Upgrade: websocket\r\n" | |
| 320 "Connection: Upgrade\r\n" | |
| 321 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | |
| 322 "Sec-WebSocket-Protocol: sample\r\n" | |
| 323 "\r\n"; | |
| 324 | |
| 325 EXPECT_EQ(kHandshakeResponseExpectedMessage, handler.GetResponse()); | |
| 326 } | |
| 327 | |
| 328 TEST(WebSocketHandshakeResponseHandlerTest, BadResponse) { | |
| 329 WebSocketHandshakeResponseHandler handler; | |
| 330 | |
| 331 static const char kBadMessage[] = "\n\n\r\net-Location: w"; | |
| 332 EXPECT_EQ(strlen(kBadMessage), | |
| 333 handler.ParseRawResponse(kBadMessage, strlen(kBadMessage))); | |
| 334 EXPECT_TRUE(handler.HasResponse()); | |
| 335 EXPECT_EQ(kBadMessage, handler.GetResponse()); | |
| 336 } | |
| 337 | |
| 338 TEST(WebSocketHandshakeResponseHandlerTest, BadResponse2) { | |
| 339 WebSocketHandshakeResponseHandler handler; | |
| 340 | |
| 341 static const char kBadMessage[] = "\n\r\n\r\net-Location: w"; | |
| 342 EXPECT_EQ(strlen(kBadMessage), | |
| 343 handler.ParseRawResponse(kBadMessage, strlen(kBadMessage))); | |
| 344 EXPECT_TRUE(handler.HasResponse()); | |
| 345 EXPECT_EQ(kBadMessage, handler.GetResponse()); | |
| 346 } | |
| 347 | |
| 348 TEST(WebSocketHandshakeHandlerTest, HttpRequestResponse) { | |
| 349 WebSocketHandshakeRequestHandler request_handler; | |
| 350 | |
| 351 static const char kHandshakeRequestMessage[] = | |
| 352 "GET /demo HTTP/1.1\r\n" | |
| 353 "Host: example.com\r\n" | |
| 354 "Connection: Upgrade\r\n" | |
| 355 "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n" | |
| 356 "Sec-WebSocket-Protocol: sample\r\n" | |
| 357 "Upgrade: WebSocket\r\n" | |
| 358 "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n" | |
| 359 "Origin: http://example.com\r\n" | |
| 360 "\r\n" | |
| 361 "^n:ds[4U"; | |
| 362 | |
| 363 EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage, | |
| 364 strlen(kHandshakeRequestMessage))); | |
| 365 EXPECT_EQ(0, request_handler.protocol_version()); | |
| 366 | |
| 367 GURL url("ws://example.com/demo"); | |
| 368 std::string challenge; | |
| 369 const HttpRequestInfo& request_info = | |
| 370 request_handler.GetRequestInfo(url, &challenge); | |
| 371 | |
| 372 EXPECT_EQ(url, request_info.url); | |
| 373 EXPECT_EQ("GET", request_info.method); | |
| 374 EXPECT_FALSE(request_info.extra_headers.HasHeader("Upgrade")); | |
| 375 EXPECT_FALSE(request_info.extra_headers.HasHeader("Connection")); | |
| 376 EXPECT_FALSE(request_info.extra_headers.HasHeader("Sec-WebSocket-Key1")); | |
| 377 EXPECT_FALSE(request_info.extra_headers.HasHeader("Sec-WebSocket-Key2")); | |
| 378 std::string value; | |
| 379 EXPECT_TRUE(request_info.extra_headers.GetHeader("Host", &value)); | |
| 380 EXPECT_EQ("example.com", value); | |
| 381 EXPECT_TRUE(request_info.extra_headers.GetHeader("Origin", &value)); | |
| 382 EXPECT_EQ("http://example.com", value); | |
| 383 EXPECT_TRUE(request_info.extra_headers.GetHeader("Sec-WebSocket-Protocol", | |
| 384 &value)); | |
| 385 EXPECT_EQ("sample", value); | |
| 386 | |
| 387 const char expected_challenge[] = "\x31\x6e\x41\x13\x0f\x7e\xd6\x3c^n:ds[4U"; | |
| 388 | |
| 389 EXPECT_EQ(expected_challenge, challenge); | |
| 390 | |
| 391 static const char kHandshakeResponseHeader[] = | |
| 392 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" | |
| 393 "Sec-WebSocket-Origin: http://example.com\r\n" | |
| 394 "Sec-WebSocket-Location: ws://example.com/demo\r\n" | |
| 395 "Sec-WebSocket-Protocol: sample\r\n"; | |
| 396 | |
| 397 std::string raw_headers = | |
| 398 HttpUtil::AssembleRawHeaders(kHandshakeResponseHeader, | |
| 399 strlen(kHandshakeResponseHeader)); | |
| 400 HttpResponseInfo response_info; | |
| 401 response_info.headers = new HttpResponseHeaders(raw_headers); | |
| 402 | |
| 403 EXPECT_TRUE(StartsWithASCII(response_info.headers->GetStatusLine(), | |
| 404 "HTTP/1.1 101 ", false)); | |
| 405 EXPECT_FALSE(response_info.headers->HasHeader("Upgrade")); | |
| 406 EXPECT_FALSE(response_info.headers->HasHeader("Connection")); | |
| 407 EXPECT_TRUE(response_info.headers->HasHeaderValue("Sec-WebSocket-Origin", | |
| 408 "http://example.com")); | |
| 409 EXPECT_TRUE(response_info.headers->HasHeaderValue("Sec-WebSocket-Location", | |
| 410 "ws://example.com/demo")); | |
| 411 EXPECT_TRUE(response_info.headers->HasHeaderValue("Sec-WebSocket-Protocol", | |
| 412 "sample")); | |
| 413 | |
| 414 WebSocketHandshakeResponseHandler response_handler; | |
| 415 EXPECT_EQ(0, response_handler.protocol_version()); | |
| 416 EXPECT_TRUE(response_handler.ParseResponseInfo(response_info, challenge)); | |
| 417 EXPECT_TRUE(response_handler.HasResponse()); | |
| 418 | |
| 419 static const char kHandshakeResponseExpectedMessage[] = | |
| 420 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" | |
| 421 "Upgrade: WebSocket\r\n" | |
| 422 "Connection: Upgrade\r\n" | |
| 423 "Sec-WebSocket-Origin: http://example.com\r\n" | |
| 424 "Sec-WebSocket-Location: ws://example.com/demo\r\n" | |
| 425 "Sec-WebSocket-Protocol: sample\r\n" | |
| 426 "\r\n" | |
| 427 "8jKS'y:G*Co,Wxa-"; | |
| 428 | |
| 429 EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse()); | |
| 430 } | |
| 431 | |
| 432 TEST(WebSocketHandshakeHandlerTest, HttpRequestResponseHybi06Handshake) { | |
| 433 WebSocketHandshakeRequestHandler request_handler; | |
| 434 | |
| 435 static const char kHandshakeRequestMessage[] = | |
| 436 "GET /demo HTTP/1.1\r\n" | |
| 437 "Host: example.com\r\n" | |
| 438 "Upgrade: websocket\r\n" | |
| 439 "Connection: Upgrade\r\n" | |
| 440 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
| 441 "Sec-WebSocket-Origin: http://example.com\r\n" | |
| 442 "Sec-WebSocket-Protocol: sample\r\n" | |
| 443 "Sec-WebSocket-Version: 6\r\n" | |
| 444 "\r\n"; | |
| 445 | |
| 446 EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage, | |
| 447 strlen(kHandshakeRequestMessage))); | |
| 448 EXPECT_EQ(6, request_handler.protocol_version()); | |
| 449 | |
| 450 GURL url("ws://example.com/demo"); | |
| 451 std::string challenge; | |
| 452 const HttpRequestInfo& request_info = | |
| 453 request_handler.GetRequestInfo(url, &challenge); | |
| 454 | |
| 455 EXPECT_EQ(url, request_info.url); | |
| 456 EXPECT_EQ("GET", request_info.method); | |
| 457 EXPECT_FALSE(request_info.extra_headers.HasHeader("Upgrade")); | |
| 458 EXPECT_FALSE(request_info.extra_headers.HasHeader("Connection")); | |
| 459 EXPECT_FALSE(request_info.extra_headers.HasHeader("Sec-WebSocket-Key")); | |
| 460 std::string value; | |
| 461 EXPECT_TRUE(request_info.extra_headers.GetHeader("Host", &value)); | |
| 462 EXPECT_EQ("example.com", value); | |
| 463 EXPECT_TRUE(request_info.extra_headers.GetHeader("Sec-WebSocket-Origin", | |
| 464 &value)); | |
| 465 EXPECT_EQ("http://example.com", value); | |
| 466 EXPECT_TRUE(request_info.extra_headers.GetHeader("Sec-WebSocket-Protocol", | |
| 467 &value)); | |
| 468 EXPECT_EQ("sample", value); | |
| 469 | |
| 470 EXPECT_EQ("dGhlIHNhbXBsZSBub25jZQ==", challenge); | |
| 471 | |
| 472 static const char kHandshakeResponseHeader[] = | |
| 473 "HTTP/1.1 101 Switching Protocols\r\n" | |
| 474 "Sec-WebSocket-Protocol: sample\r\n"; | |
| 475 | |
| 476 std::string raw_headers = | |
| 477 HttpUtil::AssembleRawHeaders(kHandshakeResponseHeader, | |
| 478 strlen(kHandshakeResponseHeader)); | |
| 479 HttpResponseInfo response_info; | |
| 480 response_info.headers = new HttpResponseHeaders(raw_headers); | |
| 481 | |
| 482 EXPECT_TRUE(StartsWithASCII(response_info.headers->GetStatusLine(), | |
| 483 "HTTP/1.1 101 ", false)); | |
| 484 EXPECT_FALSE(response_info.headers->HasHeader("Upgrade")); | |
| 485 EXPECT_FALSE(response_info.headers->HasHeader("Connection")); | |
| 486 EXPECT_FALSE(response_info.headers->HasHeader("Sec-WebSocket-Accept")); | |
| 487 EXPECT_TRUE(response_info.headers->HasHeaderValue("Sec-WebSocket-Protocol", | |
| 488 "sample")); | |
| 489 | |
| 490 WebSocketHandshakeResponseHandler response_handler; | |
| 491 response_handler.set_protocol_version(request_handler.protocol_version()); | |
| 492 EXPECT_EQ(6, response_handler.protocol_version()); | |
| 493 | |
| 494 EXPECT_TRUE(response_handler.ParseResponseInfo(response_info, challenge)); | |
| 495 EXPECT_TRUE(response_handler.HasResponse()); | |
| 496 | |
| 497 static const char kHandshakeResponseExpectedMessage[] = | |
| 498 "HTTP/1.1 101 Switching Protocols\r\n" | |
| 499 "Upgrade: websocket\r\n" | |
| 500 "Connection: Upgrade\r\n" | |
| 501 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | |
| 502 "Sec-WebSocket-Protocol: sample\r\n" | |
| 503 "\r\n"; | |
| 504 | |
| 505 EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse()); | |
| 506 } | |
| 507 | |
| 508 TEST_F(WebSocketHandshakeGetKeyNumberTest, AppendsToString) { | |
| 509 set_challenge("hello"); | |
| 510 GetKeyNumber(); | |
| 511 EXPECT_EQ("hello", challenge().substr(0, 5)); | |
| 512 } | |
| 513 | |
| 514 TEST_F(WebSocketHandshakeGetKeyNumberTest, AppendsFourBytes) { | |
| 515 set_challenge("hello"); | |
| 516 set_key("1 1"); | |
| 517 GetKeyNumber(); | |
| 518 EXPECT_EQ(9u, challenge().length()); | |
| 519 } | |
| 520 | |
| 521 TEST_F(WebSocketHandshakeGetKeyNumberTest, IsBigEndian) { | |
| 522 set_key(base::StringPrintf("%u ", 0x61626364)); | |
| 523 GetKeyNumber(); | |
| 524 EXPECT_EQ("abcd", challenge()); | |
| 525 } | |
| 526 | |
| 527 TEST_F(WebSocketHandshakeGetKeyNumberTest, IgnoresLetters) { | |
| 528 set_key("1b 1"); | |
| 529 GetKeyNumber(); | |
| 530 char expected_response[] = { 0, 0, 0, 11 }; | |
| 531 EXPECT_EQ(std::string(expected_response, 4), challenge()); | |
| 532 } | |
| 533 | |
| 534 TEST_F(WebSocketHandshakeGetKeyNumberTest, DividesBySpaces) { | |
| 535 set_key("1 2"); | |
| 536 GetKeyNumber(); | |
| 537 EXPECT_EQ(12, challenge()[3]); | |
| 538 reset_challenge(); | |
| 539 set_key("1 2"); | |
| 540 GetKeyNumber(); | |
| 541 EXPECT_EQ(6, challenge()[3]); | |
| 542 reset_challenge(); | |
| 543 set_key(" 1 2"); | |
| 544 GetKeyNumber(); | |
| 545 EXPECT_EQ(4, challenge()[3]); | |
| 546 reset_challenge(); | |
| 547 set_key(" 1 2 "); | |
| 548 GetKeyNumber(); | |
| 549 EXPECT_EQ(3, challenge()[3]); | |
| 550 } | |
| 551 | |
| 552 TEST_F(WebSocketHandshakeGetKeyNumberTest, MatchesExampleFromDraft) { | |
| 553 set_key("3e6b263 4 17 80"); | |
| 554 GetKeyNumber(); | |
| 555 char expected_response[] = { 0x36, 0x09, 0x65, 0x65 }; | |
| 556 EXPECT_EQ(std::string(expected_response, 4), challenge()); | |
| 557 } | |
| 558 | |
| 559 TEST_F(WebSocketHandshakeGetKeyNumberTest, Maximum32bitInteger) { | |
| 560 set_key("4294967295 "); | |
| 561 GetKeyNumber(); | |
| 562 char expected_response[] = { '\xFF', '\xFF', '\xFF', '\xFF' }; | |
| 563 EXPECT_EQ(std::string(expected_response, 4), challenge()); | |
| 564 } | |
| 565 | |
| 566 #if GTEST_HAS_DEATH_TEST && !defined(NDEBUG) | |
| 567 TEST_F(WebSocketHandshakeGetKeyNumberDeathTest, ThirtyThreeBitIntegerNoGood) { | |
| 568 set_key(" 4294967296"); | |
| 569 EXPECT_DEBUG_DEATH(GetKeyNumber(), "overflow"); | |
| 570 } | |
| 571 | |
| 572 TEST_F(WebSocketHandshakeGetKeyNumberDeathTest, NoSpacesNoGood) { | |
| 573 set_key("11"); | |
| 574 EXPECT_DEBUG_DEATH(GetKeyNumber(), "space"); | |
| 575 } | |
| 576 | |
| 577 TEST_F(WebSocketHandshakeGetKeyNumberDeathTest, MustBeIntegralMultiple) { | |
| 578 set_key("1 1"); | |
| 579 EXPECT_DEBUG_DEATH(GetKeyNumber(), "spaces"); | |
| 580 } | |
| 581 #endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) | |
| 582 | |
| 583 } // namespace net | |
| OLD | NEW |