| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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_job.h" | 5 #include "net/websockets/websocket_job.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 381 if (stream_type == STREAM_MOCK_SOCKET) | 381 if (stream_type == STREAM_MOCK_SOCKET) |
| 382 socket_ = new MockSocketStream(url, websocket_.get()); | 382 socket_ = new MockSocketStream(url, websocket_.get()); |
| 383 | 383 |
| 384 if (stream_type == STREAM_SOCKET || stream_type == STREAM_SPDY_WEBSOCKET) { | 384 if (stream_type == STREAM_SOCKET || stream_type == STREAM_SPDY_WEBSOCKET) { |
| 385 if (stream_type == STREAM_SPDY_WEBSOCKET) { | 385 if (stream_type == STREAM_SPDY_WEBSOCKET) { |
| 386 http_factory_.reset(new MockHttpTransactionFactory(data_.get())); | 386 http_factory_.reset(new MockHttpTransactionFactory(data_.get())); |
| 387 context_->set_http_transaction_factory(http_factory_.get()); | 387 context_->set_http_transaction_factory(http_factory_.get()); |
| 388 } | 388 } |
| 389 | 389 |
| 390 ssl_config_service_ = new MockSSLConfigService(); | 390 ssl_config_service_ = new MockSSLConfigService(); |
| 391 context_->set_ssl_config_service(ssl_config_service_); | 391 context_->set_ssl_config_service(ssl_config_service_.get()); |
| 392 proxy_service_.reset(ProxyService::CreateDirect()); | 392 proxy_service_.reset(ProxyService::CreateDirect()); |
| 393 context_->set_proxy_service(proxy_service_.get()); | 393 context_->set_proxy_service(proxy_service_.get()); |
| 394 host_resolver_.reset(new MockHostResolver); | 394 host_resolver_.reset(new MockHostResolver); |
| 395 context_->set_host_resolver(host_resolver_.get()); | 395 context_->set_host_resolver(host_resolver_.get()); |
| 396 | 396 |
| 397 socket_ = new SocketStream(url, websocket_.get()); | 397 socket_ = new SocketStream(url, websocket_.get()); |
| 398 socket_factory_.reset(new MockClientSocketFactory); | 398 socket_factory_.reset(new MockClientSocketFactory); |
| 399 DCHECK(data_.get()); | 399 DCHECK(data_.get()); |
| 400 socket_factory_->AddSocketDataProvider(data_.get()); | 400 socket_factory_->AddSocketDataProvider(data_.get()); |
| 401 socket_->SetClientSocketFactory(socket_factory_.get()); | 401 socket_->SetClientSocketFactory(socket_factory_.get()); |
| 402 } | 402 } |
| 403 | 403 |
| 404 websocket_->InitSocketStream(socket_.get()); | 404 websocket_->InitSocketStream(socket_.get()); |
| 405 websocket_->set_context(context_.get()); | 405 websocket_->set_context(context_.get()); |
| 406 // MockHostResolver resolves all hosts to 127.0.0.1; however, when we create | 406 // MockHostResolver resolves all hosts to 127.0.0.1; however, when we create |
| 407 // a WebSocketJob purely to block another one in a throttling test, we don't | 407 // a WebSocketJob purely to block another one in a throttling test, we don't |
| 408 // perform a real connect. In that case, the following address is used | 408 // perform a real connect. In that case, the following address is used |
| 409 // instead. | 409 // instead. |
| 410 IPAddressNumber ip; | 410 IPAddressNumber ip; |
| 411 ParseIPLiteralToNumber("127.0.0.1", &ip); | 411 ParseIPLiteralToNumber("127.0.0.1", &ip); |
| 412 websocket_->addresses_ = AddressList::CreateFromIPAddress(ip, 80); | 412 websocket_->addresses_ = AddressList::CreateFromIPAddress(ip, 80); |
| 413 } | 413 } |
| 414 void SkipToConnecting() { | 414 void SkipToConnecting() { |
| 415 websocket_->state_ = WebSocketJob::CONNECTING; | 415 websocket_->state_ = WebSocketJob::CONNECTING; |
| 416 WebSocketThrottle::GetInstance()->PutInQueue(websocket_); | 416 WebSocketThrottle::GetInstance()->PutInQueue(websocket_.get()); |
| 417 } | 417 } |
| 418 WebSocketJob::State GetWebSocketJobState() { | 418 WebSocketJob::State GetWebSocketJobState() { |
| 419 return websocket_->state_; | 419 return websocket_->state_; |
| 420 } | 420 } |
| 421 void CloseWebSocketJob() { | 421 void CloseWebSocketJob() { |
| 422 if (websocket_->socket_) { | 422 if (websocket_->socket_.get()) { |
| 423 websocket_->socket_->DetachDelegate(); | 423 websocket_->socket_->DetachDelegate(); |
| 424 WebSocketThrottle::GetInstance()->RemoveFromQueue(websocket_); | 424 WebSocketThrottle::GetInstance()->RemoveFromQueue(websocket_.get()); |
| 425 } | 425 } |
| 426 websocket_->state_ = WebSocketJob::CLOSED; | 426 websocket_->state_ = WebSocketJob::CLOSED; |
| 427 websocket_->delegate_ = NULL; | 427 websocket_->delegate_ = NULL; |
| 428 websocket_->socket_ = NULL; | 428 websocket_->socket_ = NULL; |
| 429 } | 429 } |
| 430 SocketStream* GetSocket(SocketStreamJob* job) { | 430 SocketStream* GetSocket(SocketStreamJob* job) { |
| 431 return job->socket_.get(); | 431 return job->socket_.get(); |
| 432 } | 432 } |
| 433 const std::string& sent_data() const { | 433 const std::string& sent_data() const { |
| 434 DCHECK_EQ(STREAM_MOCK_SOCKET, stream_type_); | 434 DCHECK_EQ(STREAM_MOCK_SOCKET, stream_type_); |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 607 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); | 607 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); |
| 608 websocket_->OnSentData(socket_.get(), | 608 websocket_->OnSentData(socket_.get(), |
| 609 kHandshakeRequestWithoutCookieLength); | 609 kHandshakeRequestWithoutCookieLength); |
| 610 EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent()); | 610 EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent()); |
| 611 | 611 |
| 612 std::vector<std::string> lines; | 612 std::vector<std::string> lines; |
| 613 base::SplitString(kHandshakeResponseWithoutCookie, '\n', &lines); | 613 base::SplitString(kHandshakeResponseWithoutCookie, '\n', &lines); |
| 614 for (size_t i = 0; i < lines.size() - 2; i++) { | 614 for (size_t i = 0; i < lines.size() - 2; i++) { |
| 615 std::string line = lines[i] + "\r\n"; | 615 std::string line = lines[i] + "\r\n"; |
| 616 SCOPED_TRACE("Line: " + line); | 616 SCOPED_TRACE("Line: " + line); |
| 617 websocket_->OnReceivedData(socket_, | 617 websocket_->OnReceivedData(socket_.get(), line.c_str(), line.size()); |
| 618 line.c_str(), | |
| 619 line.size()); | |
| 620 base::MessageLoop::current()->RunUntilIdle(); | 618 base::MessageLoop::current()->RunUntilIdle(); |
| 621 EXPECT_TRUE(delegate.received_data().empty()); | 619 EXPECT_TRUE(delegate.received_data().empty()); |
| 622 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); | 620 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); |
| 623 } | 621 } |
| 624 websocket_->OnReceivedData(socket_.get(), "\r\n", 2); | 622 websocket_->OnReceivedData(socket_.get(), "\r\n", 2); |
| 625 base::MessageLoop::current()->RunUntilIdle(); | 623 base::MessageLoop::current()->RunUntilIdle(); |
| 626 EXPECT_FALSE(delegate.received_data().empty()); | 624 EXPECT_FALSE(delegate.received_data().empty()); |
| 627 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); | 625 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); |
| 628 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); | 626 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); |
| 629 CloseWebSocketJob(); | 627 CloseWebSocketJob(); |
| 630 } | 628 } |
| 631 | 629 |
| 632 TEST_F(WebSocketJobSpdy3Test, DelayedCookies) { | 630 TEST_F(WebSocketJobSpdy3Test, DelayedCookies) { |
| 633 WebSocketJob::set_websocket_over_spdy_enabled(true); | 631 WebSocketJob::set_websocket_over_spdy_enabled(true); |
| 634 GURL url("ws://example.com/demo"); | 632 GURL url("ws://example.com/demo"); |
| 635 GURL cookieUrl("http://example.com/demo"); | 633 GURL cookieUrl("http://example.com/demo"); |
| 636 CookieOptions cookie_options; | 634 CookieOptions cookie_options; |
| 637 scoped_refptr<DelayedCookieMonster> cookie_store = new DelayedCookieMonster(); | 635 scoped_refptr<DelayedCookieMonster> cookie_store = new DelayedCookieMonster(); |
| 638 context_->set_cookie_store(cookie_store); | 636 context_->set_cookie_store(cookie_store.get()); |
| 639 cookie_store->SetCookieWithOptionsAsync( | 637 cookie_store->SetCookieWithOptionsAsync(cookieUrl, |
| 640 cookieUrl, "CR-test=1", cookie_options, | 638 "CR-test=1", |
| 641 CookieMonster::SetCookiesCallback()); | 639 cookie_options, |
| 640 CookieMonster::SetCookiesCallback()); |
| 642 cookie_options.set_include_httponly(); | 641 cookie_options.set_include_httponly(); |
| 643 cookie_store->SetCookieWithOptionsAsync( | 642 cookie_store->SetCookieWithOptionsAsync( |
| 644 cookieUrl, "CR-test-httponly=1", cookie_options, | 643 cookieUrl, "CR-test-httponly=1", cookie_options, |
| 645 CookieMonster::SetCookiesCallback()); | 644 CookieMonster::SetCookiesCallback()); |
| 646 | 645 |
| 647 MockSocketStreamDelegate delegate; | 646 MockSocketStreamDelegate delegate; |
| 648 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET); | 647 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET); |
| 649 SkipToConnecting(); | 648 SkipToConnecting(); |
| 650 | 649 |
| 651 bool sent = websocket_->SendData(kHandshakeRequestWithCookie, | 650 bool sent = websocket_->SendData(kHandshakeRequestWithCookie, |
| 652 kHandshakeRequestWithCookieLength); | 651 kHandshakeRequestWithCookieLength); |
| 653 EXPECT_TRUE(sent); | 652 EXPECT_TRUE(sent); |
| 654 base::MessageLoop::current()->RunUntilIdle(); | 653 base::MessageLoop::current()->RunUntilIdle(); |
| 655 EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data()); | 654 EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data()); |
| 656 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); | 655 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); |
| 657 websocket_->OnSentData(socket_, | 656 websocket_->OnSentData(socket_.get(), |
| 658 kHandshakeRequestWithFilteredCookieLength); | 657 kHandshakeRequestWithFilteredCookieLength); |
| 659 EXPECT_EQ(kHandshakeRequestWithCookieLength, | 658 EXPECT_EQ(kHandshakeRequestWithCookieLength, |
| 660 delegate.amount_sent()); | 659 delegate.amount_sent()); |
| 661 | 660 |
| 662 websocket_->OnReceivedData(socket_.get(), | 661 websocket_->OnReceivedData(socket_.get(), |
| 663 kHandshakeResponseWithCookie, | 662 kHandshakeResponseWithCookie, |
| 664 kHandshakeResponseWithCookieLength); | 663 kHandshakeResponseWithCookieLength); |
| 665 base::MessageLoop::current()->RunUntilIdle(); | 664 base::MessageLoop::current()->RunUntilIdle(); |
| 666 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); | 665 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); |
| 667 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); | 666 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 682 MockSocketStreamDelegate delegate; | 681 MockSocketStreamDelegate delegate; |
| 683 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET); | 682 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET); |
| 684 SkipToConnecting(); | 683 SkipToConnecting(); |
| 685 | 684 |
| 686 bool sent = websocket_->SendData(kHandshakeRequestWithCookie, | 685 bool sent = websocket_->SendData(kHandshakeRequestWithCookie, |
| 687 kHandshakeRequestWithCookieLength); | 686 kHandshakeRequestWithCookieLength); |
| 688 EXPECT_TRUE(sent); | 687 EXPECT_TRUE(sent); |
| 689 base::MessageLoop::current()->RunUntilIdle(); | 688 base::MessageLoop::current()->RunUntilIdle(); |
| 690 EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data()); | 689 EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data()); |
| 691 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); | 690 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); |
| 692 websocket_->OnSentData(socket_, | 691 websocket_->OnSentData(socket_.get(), |
| 693 kHandshakeRequestWithFilteredCookieLength); | 692 kHandshakeRequestWithFilteredCookieLength); |
| 694 EXPECT_EQ(kHandshakeRequestWithCookieLength, | 693 EXPECT_EQ(kHandshakeRequestWithCookieLength, |
| 695 delegate.amount_sent()); | 694 delegate.amount_sent()); |
| 696 | 695 |
| 697 websocket_->OnReceivedData(socket_.get(), | 696 websocket_->OnReceivedData(socket_.get(), |
| 698 kHandshakeResponseWithCookie, | 697 kHandshakeResponseWithCookie, |
| 699 kHandshakeResponseWithCookieLength); | 698 kHandshakeResponseWithCookieLength); |
| 700 base::MessageLoop::current()->RunUntilIdle(); | 699 base::MessageLoop::current()->RunUntilIdle(); |
| 701 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); | 700 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); |
| 702 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); | 701 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 726 delegate.set_allow_all_cookies(false); | 725 delegate.set_allow_all_cookies(false); |
| 727 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET); | 726 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET); |
| 728 SkipToConnecting(); | 727 SkipToConnecting(); |
| 729 | 728 |
| 730 bool sent = websocket_->SendData(kHandshakeRequestWithCookie, | 729 bool sent = websocket_->SendData(kHandshakeRequestWithCookie, |
| 731 kHandshakeRequestWithCookieLength); | 730 kHandshakeRequestWithCookieLength); |
| 732 EXPECT_TRUE(sent); | 731 EXPECT_TRUE(sent); |
| 733 base::MessageLoop::current()->RunUntilIdle(); | 732 base::MessageLoop::current()->RunUntilIdle(); |
| 734 EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data()); | 733 EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data()); |
| 735 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); | 734 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); |
| 736 websocket_->OnSentData(socket_, kHandshakeRequestWithoutCookieLength); | 735 websocket_->OnSentData(socket_.get(), kHandshakeRequestWithoutCookieLength); |
| 737 EXPECT_EQ(kHandshakeRequestWithCookieLength, | 736 EXPECT_EQ(kHandshakeRequestWithCookieLength, delegate.amount_sent()); |
| 738 delegate.amount_sent()); | |
| 739 | 737 |
| 740 websocket_->OnReceivedData(socket_.get(), | 738 websocket_->OnReceivedData(socket_.get(), |
| 741 kHandshakeResponseWithCookie, | 739 kHandshakeResponseWithCookie, |
| 742 kHandshakeResponseWithCookieLength); | 740 kHandshakeResponseWithCookieLength); |
| 743 base::MessageLoop::current()->RunUntilIdle(); | 741 base::MessageLoop::current()->RunUntilIdle(); |
| 744 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); | 742 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); |
| 745 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); | 743 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); |
| 746 | 744 |
| 747 EXPECT_EQ(2U, cookie_store_->entries().size()); | 745 EXPECT_EQ(2U, cookie_store_->entries().size()); |
| 748 EXPECT_EQ(cookieUrl, cookie_store_->entries()[0].url); | 746 EXPECT_EQ(cookieUrl, cookie_store_->entries()[0].url); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 856 } | 854 } |
| 857 | 855 |
| 858 websocket_->Connect(); | 856 websocket_->Connect(); |
| 859 | 857 |
| 860 if (throttling == THROTTLING_ON) { | 858 if (throttling == THROTTLING_ON) { |
| 861 EXPECT_EQ(OK, WaitForResult()); | 859 EXPECT_EQ(OK, WaitForResult()); |
| 862 EXPECT_TRUE(websocket_->IsWaiting()); | 860 EXPECT_TRUE(websocket_->IsWaiting()); |
| 863 | 861 |
| 864 // Remove the former WebSocket object from throttling queue to unblock the | 862 // Remove the former WebSocket object from throttling queue to unblock the |
| 865 // latter. | 863 // latter. |
| 866 WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket); | 864 WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket.get()); |
| 867 block_websocket->state_ = WebSocketJob::CLOSED; | 865 block_websocket->state_ = WebSocketJob::CLOSED; |
| 868 block_websocket = NULL; | 866 block_websocket = NULL; |
| 869 WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary(); | 867 WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary(); |
| 870 } | 868 } |
| 871 | 869 |
| 872 EXPECT_EQ(OK, WaitForResult()); | 870 EXPECT_EQ(OK, WaitForResult()); |
| 873 EXPECT_TRUE(data_->at_read_eof()); | 871 EXPECT_TRUE(data_->at_read_eof()); |
| 874 EXPECT_TRUE(data_->at_write_eof()); | 872 EXPECT_TRUE(data_->at_write_eof()); |
| 875 EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState()); | 873 EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState()); |
| 876 } | 874 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 } | 970 } |
| 973 | 971 |
| 974 websocket_->Connect(); | 972 websocket_->Connect(); |
| 975 | 973 |
| 976 if (throttling == THROTTLING_ON) { | 974 if (throttling == THROTTLING_ON) { |
| 977 EXPECT_EQ(OK, WaitForResult()); | 975 EXPECT_EQ(OK, WaitForResult()); |
| 978 EXPECT_TRUE(websocket_->IsWaiting()); | 976 EXPECT_TRUE(websocket_->IsWaiting()); |
| 979 | 977 |
| 980 // Remove the former WebSocket object from throttling queue to unblock the | 978 // Remove the former WebSocket object from throttling queue to unblock the |
| 981 // latter. | 979 // latter. |
| 982 WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket); | 980 WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket.get()); |
| 983 block_websocket->state_ = WebSocketJob::CLOSED; | 981 block_websocket->state_ = WebSocketJob::CLOSED; |
| 984 block_websocket = NULL; | 982 block_websocket = NULL; |
| 985 WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary(); | 983 WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary(); |
| 986 } | 984 } |
| 987 | 985 |
| 988 EXPECT_EQ(OK, WaitForResult()); | 986 EXPECT_EQ(OK, WaitForResult()); |
| 989 EXPECT_TRUE(data_->at_read_eof()); | 987 EXPECT_TRUE(data_->at_read_eof()); |
| 990 EXPECT_TRUE(data_->at_write_eof()); | 988 EXPECT_TRUE(data_->at_write_eof()); |
| 991 EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState()); | 989 EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState()); |
| 992 } | 990 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1088 } | 1086 } |
| 1089 | 1087 |
| 1090 TEST_F(WebSocketJobSpdy3Test, ThrottlingSpdySpdyEnabled) { | 1088 TEST_F(WebSocketJobSpdy3Test, ThrottlingSpdySpdyEnabled) { |
| 1091 WebSocketJob::set_websocket_over_spdy_enabled(true); | 1089 WebSocketJob::set_websocket_over_spdy_enabled(true); |
| 1092 TestConnectBySpdy(SPDY_ON, THROTTLING_ON); | 1090 TestConnectBySpdy(SPDY_ON, THROTTLING_ON); |
| 1093 } | 1091 } |
| 1094 | 1092 |
| 1095 // TODO(toyoshim): Add tests to verify throttling, SPDY stream limitation. | 1093 // TODO(toyoshim): Add tests to verify throttling, SPDY stream limitation. |
| 1096 // TODO(toyoshim,yutak): Add tests to verify closing handshake. | 1094 // TODO(toyoshim,yutak): Add tests to verify closing handshake. |
| 1097 } // namespace net | 1095 } // namespace net |
| OLD | NEW |