| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/websockets/websocket_stream.h" | 5 #include "net/websockets/websocket_stream.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <utility> | 9 #include <utility> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 scoped_ptr<WebSocketStreamRequest> stream_request_; | 177 scoped_ptr<WebSocketStreamRequest> stream_request_; |
| 178 // Only set if the connection succeeded. | 178 // Only set if the connection succeeded. |
| 179 scoped_ptr<WebSocketStream> stream_; | 179 scoped_ptr<WebSocketStream> stream_; |
| 180 // Only set if the connection failed. | 180 // Only set if the connection failed. |
| 181 std::string failure_message_; | 181 std::string failure_message_; |
| 182 bool has_failed_; | 182 bool has_failed_; |
| 183 scoped_ptr<WebSocketHandshakeRequestInfo> request_info_; | 183 scoped_ptr<WebSocketHandshakeRequestInfo> request_info_; |
| 184 scoped_ptr<WebSocketHandshakeResponseInfo> response_info_; | 184 scoped_ptr<WebSocketHandshakeResponseInfo> response_info_; |
| 185 }; | 185 }; |
| 186 | 186 |
| 187 // There are enough tests of the Sec-WebSocket-Extensions header that they |
| 188 // deserve their own test fixture. |
| 189 class WebSocketStreamCreateExtensionTest : public WebSocketStreamCreateTest { |
| 190 public: |
| 191 // Performs a standard connect, with the value of the Sec-WebSocket-Extensions |
| 192 // header in the response set to |extensions_header_value|. Runs the event |
| 193 // loop to allow the connect to complete. |
| 194 void CreateAndConnectWithExtensions( |
| 195 const std::string& extensions_header_value) { |
| 196 CreateAndConnectStandard( |
| 197 "ws://localhost/testing_path", |
| 198 "/testing_path", |
| 199 NoSubProtocols(), |
| 200 "http://localhost/", |
| 201 "", |
| 202 "Sec-WebSocket-Extensions: " + extensions_header_value + "\r\n"); |
| 203 RunUntilIdle(); |
| 204 } |
| 205 }; |
| 206 |
| 187 // Confirm that the basic case works as expected. | 207 // Confirm that the basic case works as expected. |
| 188 TEST_F(WebSocketStreamCreateTest, SimpleSuccess) { | 208 TEST_F(WebSocketStreamCreateTest, SimpleSuccess) { |
| 189 CreateAndConnectStandard( | 209 CreateAndConnectStandard( |
| 190 "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); | 210 "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); |
| 191 EXPECT_FALSE(request_info_); | 211 EXPECT_FALSE(request_info_); |
| 192 EXPECT_FALSE(response_info_); | 212 EXPECT_FALSE(response_info_); |
| 193 RunUntilIdle(); | 213 RunUntilIdle(); |
| 194 EXPECT_FALSE(has_failed()); | 214 EXPECT_FALSE(has_failed()); |
| 195 EXPECT_TRUE(stream_); | 215 EXPECT_TRUE(stream_); |
| 196 EXPECT_TRUE(request_info_); | 216 EXPECT_TRUE(request_info_); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 222 ASSERT_TRUE(request_info_); | 242 ASSERT_TRUE(request_info_); |
| 223 ASSERT_TRUE(response_info_); | 243 ASSERT_TRUE(response_info_); |
| 224 std::vector<HeaderKeyValuePair> request_headers = | 244 std::vector<HeaderKeyValuePair> request_headers = |
| 225 ToVector(request_info_->headers); | 245 ToVector(request_info_->headers); |
| 226 // We examine the contents of request_info_ and response_info_ | 246 // We examine the contents of request_info_ and response_info_ |
| 227 // mainly only in this test case. | 247 // mainly only in this test case. |
| 228 EXPECT_EQ(GURL("ws://localhost/"), request_info_->url); | 248 EXPECT_EQ(GURL("ws://localhost/"), request_info_->url); |
| 229 EXPECT_EQ(GURL("ws://localhost/"), response_info_->url); | 249 EXPECT_EQ(GURL("ws://localhost/"), response_info_->url); |
| 230 EXPECT_EQ(101, response_info_->status_code); | 250 EXPECT_EQ(101, response_info_->status_code); |
| 231 EXPECT_EQ("Switching Protocols", response_info_->status_text); | 251 EXPECT_EQ("Switching Protocols", response_info_->status_text); |
| 232 EXPECT_EQ(9u, request_headers.size()); | 252 EXPECT_EQ(10u, request_headers.size()); |
| 233 EXPECT_EQ(HeaderKeyValuePair("Host", "localhost"), request_headers[0]); | 253 EXPECT_EQ(HeaderKeyValuePair("Host", "localhost"), request_headers[0]); |
| 234 EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]); | 254 EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]); |
| 235 EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[2]); | 255 EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[2]); |
| 236 EXPECT_EQ(HeaderKeyValuePair("Origin", "http://localhost/"), | 256 EXPECT_EQ(HeaderKeyValuePair("Origin", "http://localhost/"), |
| 237 request_headers[3]); | 257 request_headers[3]); |
| 238 EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"), | 258 EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"), |
| 239 request_headers[4]); | 259 request_headers[4]); |
| 240 EXPECT_EQ(HeaderKeyValuePair("User-Agent", ""), request_headers[5]); | 260 EXPECT_EQ(HeaderKeyValuePair("User-Agent", ""), request_headers[5]); |
| 241 EXPECT_EQ(HeaderKeyValuePair("Accept-Encoding", "gzip,deflate"), | 261 EXPECT_EQ(HeaderKeyValuePair("Accept-Encoding", "gzip,deflate"), |
| 242 request_headers[6]); | 262 request_headers[6]); |
| 243 EXPECT_EQ(HeaderKeyValuePair("Accept-Language", "en-us,fr"), | 263 EXPECT_EQ(HeaderKeyValuePair("Accept-Language", "en-us,fr"), |
| 244 request_headers[7]); | 264 request_headers[7]); |
| 245 EXPECT_EQ("Sec-WebSocket-Key", request_headers[8].first); | 265 EXPECT_EQ("Sec-WebSocket-Key", request_headers[8].first); |
| 266 EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Extensions", |
| 267 "permessage-deflate; client_max_window_bits"), |
| 268 request_headers[9]); |
| 246 | 269 |
| 247 std::vector<HeaderKeyValuePair> response_headers = | 270 std::vector<HeaderKeyValuePair> response_headers = |
| 248 ToVector(*response_info_->headers); | 271 ToVector(*response_info_->headers); |
| 249 ASSERT_EQ(6u, response_headers.size()); | 272 ASSERT_EQ(6u, response_headers.size()); |
| 250 // Sort the headers for ease of verification. | 273 // Sort the headers for ease of verification. |
| 251 std::sort(response_headers.begin(), response_headers.end()); | 274 std::sort(response_headers.begin(), response_headers.end()); |
| 252 | 275 |
| 253 EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), response_headers[0]); | 276 EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), response_headers[0]); |
| 254 EXPECT_EQ("Sec-WebSocket-Accept", response_headers[1].first); | 277 EXPECT_EQ("Sec-WebSocket-Accept", response_headers[1].first); |
| 255 EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), response_headers[2]); | 278 EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), response_headers[2]); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 "Sec-WebSocket-Protocol: chatv21.chromium.org\r\n"); | 405 "Sec-WebSocket-Protocol: chatv21.chromium.org\r\n"); |
| 383 RunUntilIdle(); | 406 RunUntilIdle(); |
| 384 EXPECT_FALSE(stream_); | 407 EXPECT_FALSE(stream_); |
| 385 EXPECT_TRUE(has_failed()); | 408 EXPECT_TRUE(has_failed()); |
| 386 EXPECT_EQ("Error during WebSocket handshake: " | 409 EXPECT_EQ("Error during WebSocket handshake: " |
| 387 "'Sec-WebSocket-Protocol' header value 'chatv21.chromium.org' " | 410 "'Sec-WebSocket-Protocol' header value 'chatv21.chromium.org' " |
| 388 "in response does not match any of sent values", | 411 "in response does not match any of sent values", |
| 389 failure_message()); | 412 failure_message()); |
| 390 } | 413 } |
| 391 | 414 |
| 415 // permessage-deflate extension basic success case. |
| 416 TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateSuccess) { |
| 417 CreateAndConnectWithExtensions("permessage-deflate"); |
| 418 EXPECT_TRUE(stream_); |
| 419 EXPECT_FALSE(has_failed()); |
| 420 } |
| 421 |
| 422 // permessage-deflate extensions success with all parameters. |
| 423 TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateParamsSuccess) { |
| 424 CreateAndConnectWithExtensions( |
| 425 "permessage-deflate; client_no_content_takeover; " |
| 426 "server_max_window_bits=11; client_max_window_bits=13; " |
| 427 "server_no_content_takeover"); |
| 428 EXPECT_TRUE(stream_); |
| 429 EXPECT_FALSE(has_failed()); |
| 430 } |
| 431 |
| 392 // Unknown extension in the response is rejected | 432 // Unknown extension in the response is rejected |
| 393 TEST_F(WebSocketStreamCreateTest, UnknownExtension) { | 433 TEST_F(WebSocketStreamCreateExtensionTest, UnknownExtension) { |
| 394 CreateAndConnectStandard("ws://localhost/testing_path", | 434 CreateAndConnectWithExtensions("x-unknown-extension"); |
| 395 "/testing_path", | |
| 396 NoSubProtocols(), | |
| 397 "http://localhost/", | |
| 398 "", | |
| 399 "Sec-WebSocket-Extensions: x-unknown-extension\r\n"); | |
| 400 RunUntilIdle(); | |
| 401 EXPECT_FALSE(stream_); | 435 EXPECT_FALSE(stream_); |
| 402 EXPECT_TRUE(has_failed()); | 436 EXPECT_TRUE(has_failed()); |
| 403 EXPECT_EQ("Error during WebSocket handshake: " | 437 EXPECT_EQ("Error during WebSocket handshake: " |
| 404 "Found an unsupported extension 'x-unknown-extension' " | 438 "Found an unsupported extension 'x-unknown-extension' " |
| 405 "in 'Sec-WebSocket-Extensions' header", | 439 "in 'Sec-WebSocket-Extensions' header", |
| 406 failure_message()); | 440 failure_message()); |
| 407 } | 441 } |
| 408 | 442 |
| 443 // Malformed extensions are rejected (this file does not cover all possible |
| 444 // parse failures, as the parser is covered thoroughly by its own unit tests). |
| 445 TEST_F(WebSocketStreamCreateExtensionTest, MalformedExtension) { |
| 446 CreateAndConnectWithExtensions(";"); |
| 447 EXPECT_FALSE(stream_); |
| 448 EXPECT_TRUE(has_failed()); |
| 449 EXPECT_EQ( |
| 450 "Error during WebSocket handshake: 'Sec-WebSocket-Extensions' header " |
| 451 "value is rejected by the parser: ;", |
| 452 failure_message()); |
| 453 } |
| 454 |
| 455 // The permessage-deflate extension may only be specified once. |
| 456 TEST_F(WebSocketStreamCreateExtensionTest, OnlyOnePerMessageDeflateAllowed) { |
| 457 CreateAndConnectWithExtensions( |
| 458 "permessage-deflate, permessage-deflate; client_max_window_bits=10"); |
| 459 EXPECT_FALSE(stream_); |
| 460 EXPECT_TRUE(has_failed()); |
| 461 EXPECT_EQ( |
| 462 "Error during WebSocket handshake: Received duplicate permessage-deflate " |
| 463 "response", |
| 464 failure_message()); |
| 465 } |
| 466 |
| 467 // permessage-deflate parameters may not be duplicated. |
| 468 TEST_F(WebSocketStreamCreateExtensionTest, NoDuplicateParameters) { |
| 469 CreateAndConnectWithExtensions( |
| 470 "permessage-deflate; client_no_content_takeover; " |
| 471 "client_no_content_takeover"); |
| 472 EXPECT_FALSE(stream_); |
| 473 EXPECT_TRUE(has_failed()); |
| 474 EXPECT_EQ( |
| 475 "Error during WebSocket handshake: Received duplicate permessage-deflate " |
| 476 "extension parameter client_no_content_takeover", |
| 477 failure_message()); |
| 478 } |
| 479 |
| 480 // permessage-deflate parameters must start with "client_" or "server_" |
| 481 TEST_F(WebSocketStreamCreateExtensionTest, BadParameterPrefix) { |
| 482 CreateAndConnectWithExtensions( |
| 483 "permessage-deflate; absurd_no_content_takeover"); |
| 484 EXPECT_FALSE(stream_); |
| 485 EXPECT_TRUE(has_failed()); |
| 486 EXPECT_EQ( |
| 487 "Error during WebSocket handshake: Received an unexpected " |
| 488 "permessage-deflate extension parameter", |
| 489 failure_message()); |
| 490 } |
| 491 |
| 492 // permessage-deflate parameters must be either *_no_content_takeover or |
| 493 // *_max_window_bits |
| 494 TEST_F(WebSocketStreamCreateExtensionTest, BadParameterSuffix) { |
| 495 CreateAndConnectWithExtensions( |
| 496 "permessage-deflate; client_max_content_bits=5"); |
| 497 EXPECT_FALSE(stream_); |
| 498 EXPECT_TRUE(has_failed()); |
| 499 EXPECT_EQ( |
| 500 "Error during WebSocket handshake: Received an unexpected " |
| 501 "permessage-deflate extension parameter", |
| 502 failure_message()); |
| 503 } |
| 504 |
| 505 // *_no_content_takeover parameters must not have an argument |
| 506 TEST_F(WebSocketStreamCreateExtensionTest, BadParameterValue) { |
| 507 CreateAndConnectWithExtensions( |
| 508 "permessage-deflate; client_no_content_takeover=true"); |
| 509 EXPECT_FALSE(stream_); |
| 510 EXPECT_TRUE(has_failed()); |
| 511 EXPECT_EQ( |
| 512 "Error during WebSocket handshake: Received invalid " |
| 513 "client_no_content_takeover parameter", |
| 514 failure_message()); |
| 515 } |
| 516 |
| 517 // *_max_window_bits must have an argument |
| 518 TEST_F(WebSocketStreamCreateExtensionTest, NoMaxWindowBitsArgument) { |
| 519 CreateAndConnectWithExtensions("permessage-deflate; client_max_window_bits"); |
| 520 EXPECT_FALSE(stream_); |
| 521 EXPECT_TRUE(has_failed()); |
| 522 EXPECT_EQ( |
| 523 "Error during WebSocket handshake: client_max_window_bits must have " |
| 524 "value", |
| 525 failure_message()); |
| 526 } |
| 527 |
| 528 // *_max_window_bits must be an integer |
| 529 TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueInteger) { |
| 530 CreateAndConnectWithExtensions( |
| 531 "permessage-deflate; server_max_window_bits=banana"); |
| 532 EXPECT_FALSE(stream_); |
| 533 EXPECT_TRUE(has_failed()); |
| 534 EXPECT_EQ( |
| 535 "Error during WebSocket handshake: Received invalid " |
| 536 "server_max_window_bits parameter", |
| 537 failure_message()); |
| 538 } |
| 539 |
| 540 // *_max_window_bits must be >= 8 |
| 541 TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueTooSmall) { |
| 542 CreateAndConnectWithExtensions( |
| 543 "permessage-deflate; server_max_window_bits=7"); |
| 544 EXPECT_FALSE(stream_); |
| 545 EXPECT_TRUE(has_failed()); |
| 546 EXPECT_EQ( |
| 547 "Error during WebSocket handshake: Received invalid " |
| 548 "server_max_window_bits parameter", |
| 549 failure_message()); |
| 550 } |
| 551 |
| 552 // *_max_window_bits must be <= 15 |
| 553 TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueTooBig) { |
| 554 CreateAndConnectWithExtensions( |
| 555 "permessage-deflate; client_max_window_bits=16"); |
| 556 EXPECT_FALSE(stream_); |
| 557 EXPECT_TRUE(has_failed()); |
| 558 EXPECT_EQ( |
| 559 "Error during WebSocket handshake: Received invalid " |
| 560 "client_max_window_bits parameter", |
| 561 failure_message()); |
| 562 } |
| 563 |
| 564 // *_max_window_bits must not start with 0 |
| 565 TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueStartsWithZero) { |
| 566 CreateAndConnectWithExtensions( |
| 567 "permessage-deflate; client_max_window_bits=08"); |
| 568 EXPECT_FALSE(stream_); |
| 569 EXPECT_TRUE(has_failed()); |
| 570 EXPECT_EQ( |
| 571 "Error during WebSocket handshake: Received invalid " |
| 572 "client_max_window_bits parameter", |
| 573 failure_message()); |
| 574 } |
| 575 |
| 576 // *_max_window_bits must not start with + |
| 577 TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueStartsWithPlus) { |
| 578 CreateAndConnectWithExtensions( |
| 579 "permessage-deflate; server_max_window_bits=+9"); |
| 580 EXPECT_FALSE(stream_); |
| 581 EXPECT_TRUE(has_failed()); |
| 582 EXPECT_EQ( |
| 583 "Error during WebSocket handshake: Received invalid " |
| 584 "server_max_window_bits parameter", |
| 585 failure_message()); |
| 586 } |
| 587 |
| 588 // TODO(ricea): Check that WebSocketDeflateStream is initialised with the |
| 589 // arguments from the server. This is difficult because the data written to the |
| 590 // socket is randomly masked. |
| 591 |
| 409 // Additional Sec-WebSocket-Accept headers should be rejected. | 592 // Additional Sec-WebSocket-Accept headers should be rejected. |
| 410 TEST_F(WebSocketStreamCreateTest, DoubleAccept) { | 593 TEST_F(WebSocketStreamCreateTest, DoubleAccept) { |
| 411 CreateAndConnectStandard( | 594 CreateAndConnectStandard( |
| 412 "ws://localhost/", | 595 "ws://localhost/", |
| 413 "/", | 596 "/", |
| 414 NoSubProtocols(), | 597 NoSubProtocols(), |
| 415 "http://localhost/", | 598 "http://localhost/", |
| 416 "", | 599 "", |
| 417 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"); | 600 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"); |
| 418 RunUntilIdle(); | 601 RunUntilIdle(); |
| (...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 743 stream_request_.reset(); | 926 stream_request_.reset(); |
| 744 RunUntilIdle(); | 927 RunUntilIdle(); |
| 745 EXPECT_FALSE(has_failed()); | 928 EXPECT_FALSE(has_failed()); |
| 746 EXPECT_FALSE(stream_); | 929 EXPECT_FALSE(stream_); |
| 747 EXPECT_TRUE(request_info_); | 930 EXPECT_TRUE(request_info_); |
| 748 EXPECT_FALSE(response_info_); | 931 EXPECT_FALSE(response_info_); |
| 749 } | 932 } |
| 750 | 933 |
| 751 } // namespace | 934 } // namespace |
| 752 } // namespace net | 935 } // namespace net |
| OLD | NEW |