Index: net/spdy/spdy_session_unittest.cc |
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc |
deleted file mode 100644 |
index ba3cb611ac849157ca10ea0a9d55b01820ad6239..0000000000000000000000000000000000000000 |
--- a/net/spdy/spdy_session_unittest.cc |
+++ /dev/null |
@@ -1,5136 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "net/spdy/spdy_session.h" |
- |
-#include "base/base64.h" |
-#include "base/bind.h" |
-#include "base/callback.h" |
-#include "base/memory/scoped_ptr.h" |
-#include "base/run_loop.h" |
-#include "base/test/histogram_tester.h" |
-#include "net/base/io_buffer.h" |
-#include "net/base/ip_endpoint.h" |
-#include "net/base/net_log_unittest.h" |
-#include "net/base/request_priority.h" |
-#include "net/base/test_data_directory.h" |
-#include "net/base/test_data_stream.h" |
-#include "net/socket/client_socket_pool_manager.h" |
-#include "net/socket/next_proto.h" |
-#include "net/socket/socket_test_util.h" |
-#include "net/spdy/spdy_http_utils.h" |
-#include "net/spdy/spdy_session_pool.h" |
-#include "net/spdy/spdy_session_test_util.h" |
-#include "net/spdy/spdy_stream.h" |
-#include "net/spdy/spdy_stream_test_util.h" |
-#include "net/spdy/spdy_test_util_common.h" |
-#include "net/spdy/spdy_test_utils.h" |
-#include "net/test/cert_test_util.h" |
-#include "testing/platform_test.h" |
- |
-namespace net { |
- |
-namespace { |
- |
-static const char kTestUrl[] = "http://www.example.org/"; |
-static const char kTestHost[] = "www.example.org"; |
-static const int kTestPort = 80; |
- |
-const char kBodyData[] = "Body data"; |
-const size_t kBodyDataSize = arraysize(kBodyData); |
-const base::StringPiece kBodyDataStringPiece(kBodyData, kBodyDataSize); |
- |
-static base::TimeDelta g_time_delta; |
-base::TimeTicks TheNearFuture() { |
- return base::TimeTicks::Now() + g_time_delta; |
-} |
- |
-} // namespace |
- |
-class SpdySessionTest : public PlatformTest, |
- public ::testing::WithParamInterface<NextProto> { |
- public: |
- // Functions used with RunResumeAfterUnstallTest(). |
- |
- void StallSessionOnly(SpdySession* session, SpdyStream* stream) { |
- StallSessionSend(session); |
- } |
- |
- void StallStreamOnly(SpdySession* session, SpdyStream* stream) { |
- StallStreamSend(stream); |
- } |
- |
- void StallSessionStream(SpdySession* session, SpdyStream* stream) { |
- StallSessionSend(session); |
- StallStreamSend(stream); |
- } |
- |
- void StallStreamSession(SpdySession* session, SpdyStream* stream) { |
- StallStreamSend(stream); |
- StallSessionSend(session); |
- } |
- |
- void UnstallSessionOnly(SpdySession* session, |
- SpdyStream* stream, |
- int32 delta_window_size) { |
- UnstallSessionSend(session, delta_window_size); |
- } |
- |
- void UnstallStreamOnly(SpdySession* session, |
- SpdyStream* stream, |
- int32 delta_window_size) { |
- UnstallStreamSend(stream, delta_window_size); |
- } |
- |
- void UnstallSessionStream(SpdySession* session, |
- SpdyStream* stream, |
- int32 delta_window_size) { |
- UnstallSessionSend(session, delta_window_size); |
- UnstallStreamSend(stream, delta_window_size); |
- } |
- |
- void UnstallStreamSession(SpdySession* session, |
- SpdyStream* stream, |
- int32 delta_window_size) { |
- UnstallStreamSend(stream, delta_window_size); |
- UnstallSessionSend(session, delta_window_size); |
- } |
- |
- protected: |
- SpdySessionTest() |
- : old_max_group_sockets_(ClientSocketPoolManager::max_sockets_per_group( |
- HttpNetworkSession::NORMAL_SOCKET_POOL)), |
- old_max_pool_sockets_(ClientSocketPoolManager::max_sockets_per_pool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL)), |
- spdy_util_(GetParam()), |
- session_deps_(GetParam()), |
- spdy_session_pool_(NULL), |
- test_url_(kTestUrl), |
- test_host_port_pair_(kTestHost, kTestPort), |
- key_(test_host_port_pair_, ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED) { |
- } |
- |
- virtual ~SpdySessionTest() { |
- // Important to restore the per-pool limit first, since the pool limit must |
- // always be greater than group limit, and the tests reduce both limits. |
- ClientSocketPoolManager::set_max_sockets_per_pool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_pool_sockets_); |
- ClientSocketPoolManager::set_max_sockets_per_group( |
- HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_group_sockets_); |
- } |
- |
- void SetUp() override { g_time_delta = base::TimeDelta(); } |
- |
- void CreateDeterministicNetworkSession() { |
- http_session_ = |
- SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); |
- spdy_session_pool_ = http_session_->spdy_session_pool(); |
- } |
- |
- void CreateNetworkSession() { |
- http_session_ = |
- SpdySessionDependencies::SpdyCreateSession(&session_deps_); |
- spdy_session_pool_ = http_session_->spdy_session_pool(); |
- } |
- |
- void StallSessionSend(SpdySession* session) { |
- // Reduce the send window size to 0 to stall. |
- while (session->session_send_window_size_ > 0) { |
- session->DecreaseSendWindowSize( |
- std::min(kMaxSpdyFrameChunkSize, session->session_send_window_size_)); |
- } |
- } |
- |
- void UnstallSessionSend(SpdySession* session, int32 delta_window_size) { |
- session->IncreaseSendWindowSize(delta_window_size); |
- } |
- |
- void StallStreamSend(SpdyStream* stream) { |
- // Reduce the send window size to 0 to stall. |
- while (stream->send_window_size() > 0) { |
- stream->DecreaseSendWindowSize( |
- std::min(kMaxSpdyFrameChunkSize, stream->send_window_size())); |
- } |
- } |
- |
- void UnstallStreamSend(SpdyStream* stream, int32 delta_window_size) { |
- stream->IncreaseSendWindowSize(delta_window_size); |
- } |
- |
- void RunResumeAfterUnstallTest( |
- const base::Callback<void(SpdySession*, SpdyStream*)>& stall_function, |
- const base::Callback<void(SpdySession*, SpdyStream*, int32)>& |
- unstall_function); |
- |
- // Original socket limits. Some tests set these. Safest to always restore |
- // them once each test has been run. |
- int old_max_group_sockets_; |
- int old_max_pool_sockets_; |
- |
- SpdyTestUtil spdy_util_; |
- SpdySessionDependencies session_deps_; |
- scoped_refptr<HttpNetworkSession> http_session_; |
- SpdySessionPool* spdy_session_pool_; |
- GURL test_url_; |
- HostPortPair test_host_port_pair_; |
- SpdySessionKey key_; |
-}; |
- |
-INSTANTIATE_TEST_CASE_P( |
- NextProto, |
- SpdySessionTest, |
- testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); |
- |
-// Try to create a SPDY session that will fail during |
-// initialization. Nothing should blow up. |
-TEST_P(SpdySessionTest, InitialReadError) { |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = TryCreateFakeSpdySessionExpectingFailure( |
- spdy_session_pool_, key_, ERR_CONNECTION_CLOSED); |
- EXPECT_TRUE(session); |
- // Flush the read. |
- base::RunLoop().RunUntilIdle(); |
- EXPECT_FALSE(session); |
-} |
- |
-namespace { |
- |
-// A helper class that vends a callback that, when fired, destroys a |
-// given SpdyStreamRequest. |
-class StreamRequestDestroyingCallback : public TestCompletionCallbackBase { |
- public: |
- StreamRequestDestroyingCallback() {} |
- |
- ~StreamRequestDestroyingCallback() override {} |
- |
- void SetRequestToDestroy(scoped_ptr<SpdyStreamRequest> request) { |
- request_ = request.Pass(); |
- } |
- |
- CompletionCallback MakeCallback() { |
- return base::Bind(&StreamRequestDestroyingCallback::OnComplete, |
- base::Unretained(this)); |
- } |
- |
- private: |
- void OnComplete(int result) { |
- request_.reset(); |
- SetResult(result); |
- } |
- |
- scoped_ptr<SpdyStreamRequest> request_; |
-}; |
- |
-} // namespace |
- |
-// Request kInitialMaxConcurrentStreams streams. Request two more |
-// streams, but have the callback for one destroy the second stream |
-// request. Close the session. Nothing should blow up. This is a |
-// regression test for http://crbug.com/250841 . |
-TEST_P(SpdySessionTest, PendingStreamCancellingAnother) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockRead reads[] = {MockRead(ASYNC, 0, 0), }; |
- |
- DeterministicSocketData data(reads, arraysize(reads), NULL, 0); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- // Create the maximum number of concurrent streams. |
- for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) { |
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously( |
- SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream != NULL); |
- } |
- |
- SpdyStreamRequest request1; |
- scoped_ptr<SpdyStreamRequest> request2(new SpdyStreamRequest); |
- |
- StreamRequestDestroyingCallback callback1; |
- ASSERT_EQ(ERR_IO_PENDING, |
- request1.StartRequest(SPDY_BIDIRECTIONAL_STREAM, |
- session, |
- test_url_, |
- MEDIUM, |
- BoundNetLog(), |
- callback1.MakeCallback())); |
- |
- // |callback2| is never called. |
- TestCompletionCallback callback2; |
- ASSERT_EQ(ERR_IO_PENDING, |
- request2->StartRequest(SPDY_BIDIRECTIONAL_STREAM, |
- session, |
- test_url_, |
- MEDIUM, |
- BoundNetLog(), |
- callback2.callback())); |
- |
- callback1.SetRequestToDestroy(request2.Pass()); |
- |
- session->CloseSessionOnError(ERR_ABORTED, "Aborting session"); |
- |
- EXPECT_EQ(ERR_ABORTED, callback1.WaitForResult()); |
-} |
- |
-// A session receiving a GOAWAY frame with no active streams should close. |
-TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1)); |
- MockRead reads[] = { |
- CreateMockRead(*goaway, 0), |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), NULL, 0); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion()); |
- |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- // Read and process the GOAWAY frame. |
- data.RunFor(1); |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- base::RunLoop().RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// A session receiving a GOAWAY frame immediately with no active |
-// streams should then close. |
-TEST_P(SpdySessionTest, GoAwayImmediatelyWithNoActiveStreams) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1)); |
- MockRead reads[] = { |
- CreateMockRead(*goaway, 0, SYNCHRONOUS), |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), NULL, 0); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- data.StopAfter(1); |
- |
- base::WeakPtr<SpdySession> session = |
- TryCreateInsecureSpdySessionExpectingFailure( |
- http_session_, key_, ERR_CONNECTION_CLOSED, BoundNetLog()); |
- base::RunLoop().RunUntilIdle(); |
- |
- EXPECT_FALSE(session); |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
-} |
- |
-// A session receiving a GOAWAY frame with active streams should close |
-// when the last active stream is closed. |
-TEST_P(SpdySessionTest, GoAwayWithActiveStreams) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1)); |
- MockRead reads[] = { |
- CreateMockRead(*goaway, 2), |
- MockRead(ASYNC, 0, 3) // EOF |
- }; |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- scoped_ptr<SpdyFrame> req2( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- CreateMockWrite(*req2, 1), |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion()); |
- |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- base::WeakPtr<SpdyStream> spdy_stream2 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate2(spdy_stream2); |
- spdy_stream2->SetDelegate(&delegate2); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(*headers)); |
- |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders()); |
- |
- data.RunFor(2); |
- |
- EXPECT_EQ(1u, spdy_stream1->stream_id()); |
- EXPECT_EQ(3u, spdy_stream2->stream_id()); |
- |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- // Read and process the GOAWAY frame. |
- data.RunFor(1); |
- |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- EXPECT_FALSE(session->IsStreamActive(3)); |
- EXPECT_EQ(NULL, spdy_stream2.get()); |
- EXPECT_TRUE(session->IsStreamActive(1)); |
- |
- EXPECT_TRUE(session->IsGoingAway()); |
- |
- // Should close the session. |
- spdy_stream1->Close(); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Have a session receive two GOAWAY frames, with the last one causing |
-// the last active stream to be closed. The session should then be |
-// closed after the second GOAWAY frame. |
-TEST_P(SpdySessionTest, GoAwayTwice) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> goaway1(spdy_util_.ConstructSpdyGoAway(1)); |
- scoped_ptr<SpdyFrame> goaway2(spdy_util_.ConstructSpdyGoAway(0)); |
- MockRead reads[] = { |
- CreateMockRead(*goaway1, 2), |
- CreateMockRead(*goaway2, 3), |
- MockRead(ASYNC, 0, 4) // EOF |
- }; |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- scoped_ptr<SpdyFrame> req2( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- CreateMockWrite(*req2, 1), |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion()); |
- |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- base::WeakPtr<SpdyStream> spdy_stream2 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate2(spdy_stream2); |
- spdy_stream2->SetDelegate(&delegate2); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(*headers)); |
- |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders()); |
- |
- data.RunFor(2); |
- |
- EXPECT_EQ(1u, spdy_stream1->stream_id()); |
- EXPECT_EQ(3u, spdy_stream2->stream_id()); |
- |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- // Read and process the first GOAWAY frame. |
- data.RunFor(1); |
- |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- EXPECT_FALSE(session->IsStreamActive(3)); |
- EXPECT_EQ(NULL, spdy_stream2.get()); |
- EXPECT_TRUE(session->IsStreamActive(1)); |
- EXPECT_TRUE(session->IsGoingAway()); |
- |
- // Read and process the second GOAWAY frame, which should close the |
- // session. |
- data.RunFor(1); |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Have a session with active streams receive a GOAWAY frame and then |
-// close it. It should handle the close properly (i.e., not try to |
-// make itself unavailable in its pool twice). |
-TEST_P(SpdySessionTest, GoAwayWithActiveStreamsThenClose) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1)); |
- MockRead reads[] = { |
- CreateMockRead(*goaway, 2), |
- MockRead(ASYNC, 0, 3) // EOF |
- }; |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- scoped_ptr<SpdyFrame> req2( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- CreateMockWrite(*req2, 1), |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion()); |
- |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- base::WeakPtr<SpdyStream> spdy_stream2 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate2(spdy_stream2); |
- spdy_stream2->SetDelegate(&delegate2); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(*headers)); |
- |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders()); |
- |
- data.RunFor(2); |
- |
- EXPECT_EQ(1u, spdy_stream1->stream_id()); |
- EXPECT_EQ(3u, spdy_stream2->stream_id()); |
- |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- // Read and process the GOAWAY frame. |
- data.RunFor(1); |
- |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- EXPECT_FALSE(session->IsStreamActive(3)); |
- EXPECT_EQ(NULL, spdy_stream2.get()); |
- EXPECT_TRUE(session->IsStreamActive(1)); |
- EXPECT_TRUE(session->IsGoingAway()); |
- |
- session->CloseSessionOnError(ERR_ABORTED, "Aborting session"); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Process a joint read buffer which causes the session to begin draining, and |
-// then processes a GOAWAY. The session should gracefully drain. Regression test |
-// for crbug.com/379469 |
-TEST_P(SpdySessionTest, GoAwayWhileDraining) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), |
- }; |
- |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1)); |
- scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
- size_t joint_size = goaway->size() * 2 + body->size(); |
- |
- // Compose interleaved |goaway| and |body| frames into a single read. |
- scoped_ptr<char[]> buffer(new char[joint_size]); |
- { |
- size_t out = 0; |
- memcpy(&buffer[out], goaway->data(), goaway->size()); |
- out += goaway->size(); |
- memcpy(&buffer[out], body->data(), body->size()); |
- out += body->size(); |
- memcpy(&buffer[out], goaway->data(), goaway->size()); |
- out += goaway->size(); |
- ASSERT_EQ(out, joint_size); |
- } |
- SpdyFrame joint_frames(buffer.get(), joint_size, false); |
- |
- MockRead reads[] = { |
- CreateMockRead(*resp, 1), CreateMockRead(joint_frames, 2), |
- MockRead(ASYNC, 0, 3) // EOF |
- }; |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- DeterministicSocketData data( |
- reads, arraysize(reads), writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate(spdy_stream); |
- spdy_stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders()); |
- |
- data.RunFor(3); |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- // Stream and session closed gracefully. |
- EXPECT_TRUE(delegate.StreamIsClosed()); |
- EXPECT_EQ(OK, delegate.WaitForClose()); |
- EXPECT_EQ(kUploadData, delegate.TakeReceivedData()); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Try to create a stream after receiving a GOAWAY frame. It should |
-// fail. |
-TEST_P(SpdySessionTest, CreateStreamAfterGoAway) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1)); |
- MockRead reads[] = { |
- CreateMockRead(*goaway, 1), |
- MockRead(ASYNC, 0, 2) // EOF |
- }; |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion()); |
- |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate(spdy_stream); |
- spdy_stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders()); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(1u, spdy_stream->stream_id()); |
- |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- // Read and process the GOAWAY frame. |
- data.RunFor(1); |
- |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- EXPECT_TRUE(session->IsStreamActive(1)); |
- |
- SpdyStreamRequest stream_request; |
- int rv = stream_request.StartRequest( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog(), |
- CompletionCallback()); |
- EXPECT_EQ(ERR_FAILED, rv); |
- |
- // Read and process EOF. |
- data.RunFor(1); |
- |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Receiving a SYN_STREAM frame after a GOAWAY frame should result in |
-// the stream being refused. |
-TEST_P(SpdySessionTest, SynStreamAfterGoAway) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1)); |
- scoped_ptr<SpdyFrame> |
- push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kDefaultURL)); |
- MockRead reads[] = { |
- CreateMockRead(*goaway, 1), |
- CreateMockRead(*push, 2), |
- MockRead(ASYNC, 0, 4) // EOF |
- }; |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- scoped_ptr<SpdyFrame> rst( |
- spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), |
- CreateMockWrite(*rst, 3) |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion()); |
- |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate(spdy_stream); |
- spdy_stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders()); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(1u, spdy_stream->stream_id()); |
- |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- // Read and process the GOAWAY frame. |
- data.RunFor(1); |
- |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- EXPECT_TRUE(session->IsStreamActive(1)); |
- |
- // Read and process the SYN_STREAM frame, the subsequent RST_STREAM, |
- // and EOF. |
- data.RunFor(3); |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// A session observing a network change with active streams should close |
-// when the last active stream is closed. |
-TEST_P(SpdySessionTest, NetworkChangeWithActiveStreams) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 1) // EOF |
- }; |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion()); |
- |
- base::WeakPtr<SpdyStream> spdy_stream = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, |
- GURL(kDefaultURL), MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate(spdy_stream); |
- spdy_stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(kDefaultURL)); |
- |
- spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders()); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(1u, spdy_stream->stream_id()); |
- |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- spdy_session_pool_->OnIPAddressChanged(); |
- |
- // The SpdySessionPool behavior differs based on how the OSs reacts to |
- // network changes; see comment in SpdySessionPool::OnIPAddressChanged(). |
-#if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS) |
- // For OSs where the TCP connections will close upon relevant network |
- // changes, SpdySessionPool doesn't need to force them to close, so in these |
- // cases verify the session has become unavailable but remains open and the |
- // pre-existing stream is still active. |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- EXPECT_TRUE(session->IsGoingAway()); |
- |
- EXPECT_TRUE(session->IsStreamActive(1)); |
- |
- // Should close the session. |
- spdy_stream->Close(); |
-#endif |
- EXPECT_EQ(NULL, spdy_stream.get()); |
- |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-TEST_P(SpdySessionTest, ClientPing) { |
- session_deps_.enable_ping = true; |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> read_ping(spdy_util_.ConstructSpdyPing(1, true)); |
- MockRead reads[] = { |
- CreateMockRead(*read_ping, 1), |
- MockRead(ASYNC, 0, 0, 2) // EOF |
- }; |
- scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false)); |
- MockWrite writes[] = { |
- CreateMockWrite(*write_ping, 0), |
- }; |
- DeterministicSocketData data( |
- reads, arraysize(reads), writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, test_url_, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL); |
- spdy_stream1->SetDelegate(&delegate); |
- |
- base::TimeTicks before_ping_time = base::TimeTicks::Now(); |
- |
- session->set_connection_at_risk_of_loss_time( |
- base::TimeDelta::FromSeconds(-1)); |
- session->set_hung_interval(base::TimeDelta::FromMilliseconds(50)); |
- |
- session->SendPrefacePingIfNoneInFlight(); |
- |
- data.RunFor(2); |
- |
- session->CheckPingStatus(before_ping_time); |
- |
- EXPECT_EQ(0, session->pings_in_flight()); |
- EXPECT_GE(session->next_ping_id(), 1U); |
- EXPECT_FALSE(session->check_ping_status_pending()); |
- EXPECT_GE(session->last_activity_time(), before_ping_time); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); |
- |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-TEST_P(SpdySessionTest, ServerPing) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> read_ping(spdy_util_.ConstructSpdyPing(2, false)); |
- MockRead reads[] = { |
- CreateMockRead(*read_ping), |
- MockRead(SYNCHRONOUS, 0, 0) // EOF |
- }; |
- scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(2, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*write_ping), |
- }; |
- StaticSocketDataProvider data( |
- reads, arraysize(reads), writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, test_url_, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL); |
- spdy_stream1->SetDelegate(&delegate); |
- |
- // Flush the read completion task. |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- EXPECT_TRUE(session == NULL); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
-} |
- |
-// Cause a ping to be sent out while producing a write. The write loop |
-// should handle this properly, i.e. another DoWriteLoop task should |
-// not be posted. This is a regression test for |
-// http://crbug.com/261043 . |
-TEST_P(SpdySessionTest, PingAndWriteLoop) { |
- session_deps_.enable_ping = true; |
- session_deps_.time_func = TheNearFuture; |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false)); |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), |
- CreateMockWrite(*write_ping, 1), |
- }; |
- |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 2) // EOF |
- }; |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, LOWEST, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate(spdy_stream); |
- spdy_stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- |
- // Shift time so that a ping will be sent out. |
- g_time_delta = base::TimeDelta::FromSeconds(11); |
- |
- data.RunFor(2); |
- |
- session->CloseSessionOnError(ERR_ABORTED, "Aborting"); |
-} |
- |
-TEST_P(SpdySessionTest, StreamIdSpaceExhausted) { |
- const SpdyStreamId kLastStreamId = 0x7fffffff; |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- // Test setup: |stream_hi_water_mark_| and |max_concurrent_streams_| are |
- // fixed to allow for two stream ID assignments, and three concurrent |
- // streams. Four streams are started, and two are activated. Verify the |
- // session goes away, and that the created (but not activated) and |
- // stalled streams are aborted. Also verify the activated streams complete, |
- // at which point the session closes. |
- |
- scoped_ptr<SpdyFrame> req1(spdy_util_.ConstructSpdyGet( |
- NULL, 0, false, kLastStreamId - 2, MEDIUM, true)); |
- scoped_ptr<SpdyFrame> req2( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, kLastStreamId, MEDIUM, true)); |
- |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), CreateMockWrite(*req2, 1), |
- }; |
- |
- scoped_ptr<SpdyFrame> resp1( |
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, kLastStreamId - 2)); |
- scoped_ptr<SpdyFrame> resp2( |
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, kLastStreamId)); |
- |
- scoped_ptr<SpdyFrame> body1( |
- spdy_util_.ConstructSpdyBodyFrame(kLastStreamId - 2, true)); |
- scoped_ptr<SpdyFrame> body2( |
- spdy_util_.ConstructSpdyBodyFrame(kLastStreamId, true)); |
- |
- MockRead reads[] = { |
- CreateMockRead(*resp1, 2), CreateMockRead(*resp2, 3), |
- CreateMockRead(*body1, 4), CreateMockRead(*body2, 5), |
- MockRead(ASYNC, 0, 6) // EOF |
- }; |
- |
- DeterministicSocketData data( |
- reads, arraysize(reads), writes, arraysize(writes)); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- // Fix stream_hi_water_mark_ to allow for two stream activations. |
- session->stream_hi_water_mark_ = kLastStreamId - 2; |
- // Fix max_concurrent_streams to allow for three stream creations. |
- session->max_concurrent_streams_ = 3; |
- |
- // Create three streams synchronously, and begin a fourth (which is stalled). |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> stream1 = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate1(stream1); |
- stream1->SetDelegate(&delegate1); |
- |
- base::WeakPtr<SpdyStream> stream2 = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate2(stream2); |
- stream2->SetDelegate(&delegate2); |
- |
- base::WeakPtr<SpdyStream> stream3 = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate3(stream3); |
- stream3->SetDelegate(&delegate3); |
- |
- SpdyStreamRequest request4; |
- TestCompletionCallback callback4; |
- EXPECT_EQ(ERR_IO_PENDING, |
- request4.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, |
- session, |
- url, |
- MEDIUM, |
- BoundNetLog(), |
- callback4.callback())); |
- |
- // Streams 1-3 were created. 4th is stalled. No streams are active yet. |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(3u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->pending_create_stream_queue_size(MEDIUM)); |
- |
- // Activate stream 1. One ID remains available. |
- stream1->SendRequestHeaders( |
- scoped_ptr<SpdyHeaderBlock>( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())), |
- NO_MORE_DATA_TO_SEND); |
- data.RunFor(1); |
- |
- EXPECT_EQ(kLastStreamId - 2u, stream1->stream_id()); |
- EXPECT_EQ(1u, session->num_active_streams()); |
- EXPECT_EQ(2u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->pending_create_stream_queue_size(MEDIUM)); |
- |
- // Activate stream 2. ID space is exhausted. |
- stream2->SendRequestHeaders( |
- scoped_ptr<SpdyHeaderBlock>( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())), |
- NO_MORE_DATA_TO_SEND); |
- data.RunFor(1); |
- |
- // Active streams remain active. |
- EXPECT_EQ(kLastStreamId, stream2->stream_id()); |
- EXPECT_EQ(2u, session->num_active_streams()); |
- |
- // Session is going away. Created and stalled streams were aborted. |
- EXPECT_EQ(SpdySession::STATE_GOING_AWAY, session->availability_state_); |
- EXPECT_EQ(ERR_ABORTED, delegate3.WaitForClose()); |
- EXPECT_EQ(ERR_ABORTED, callback4.WaitForResult()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->pending_create_stream_queue_size(MEDIUM)); |
- |
- // Read responses on remaining active streams. |
- data.RunFor(4); |
- EXPECT_EQ(OK, delegate1.WaitForClose()); |
- EXPECT_EQ(kUploadData, delegate1.TakeReceivedData()); |
- EXPECT_EQ(OK, delegate2.WaitForClose()); |
- EXPECT_EQ(kUploadData, delegate2.TakeReceivedData()); |
- |
- // Session was destroyed. |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_FALSE(session.get()); |
-} |
- |
-// Verifies that an unstalled pending stream creation racing with a new stream |
-// creation doesn't violate the maximum stream concurrency. Regression test for |
-// crbug.com/373858. |
-TEST_P(SpdySessionTest, UnstallRacesWithStreamCreation) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
- }; |
- |
- StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- // Fix max_concurrent_streams to allow for one open stream. |
- session->max_concurrent_streams_ = 1; |
- |
- // Create two streams: one synchronously, and one which stalls. |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> stream1 = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); |
- |
- SpdyStreamRequest request2; |
- TestCompletionCallback callback2; |
- EXPECT_EQ(ERR_IO_PENDING, |
- request2.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, |
- session, |
- url, |
- MEDIUM, |
- BoundNetLog(), |
- callback2.callback())); |
- |
- EXPECT_EQ(1u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->pending_create_stream_queue_size(MEDIUM)); |
- |
- // Cancel the first stream. A callback to unstall the second stream was |
- // posted. Don't run it yet. |
- stream1->Cancel(); |
- |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->pending_create_stream_queue_size(MEDIUM)); |
- |
- // Create a third stream prior to the second stream's callback. |
- base::WeakPtr<SpdyStream> stream3 = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); |
- |
- EXPECT_EQ(1u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->pending_create_stream_queue_size(MEDIUM)); |
- |
- // NOW run the message loop. The unstalled stream will re-stall itself. |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_EQ(1u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->pending_create_stream_queue_size(MEDIUM)); |
- |
- // Cancel the third stream and run the message loop. Verify that the second |
- // stream creation now completes. |
- stream3->Cancel(); |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- EXPECT_EQ(1u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->pending_create_stream_queue_size(MEDIUM)); |
- EXPECT_EQ(OK, callback2.WaitForResult()); |
-} |
- |
-TEST_P(SpdySessionTest, DeleteExpiredPushStreams) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- session_deps_.time_func = TheNearFuture; |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- scoped_ptr<SpdyFrame> rst( |
- spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM)); |
- |
- scoped_ptr<SpdyFrame> push_a(spdy_util_.ConstructSpdyPush( |
- NULL, 0, 2, 1, "http://www.google.com/a.dat")); |
- scoped_ptr<SpdyFrame> push_a_body( |
- spdy_util_.ConstructSpdyBodyFrame(2, false)); |
- // In ascii "0" < "a". We use it to verify that we properly handle std::map |
- // iterators inside. See http://crbug.com/443490 |
- scoped_ptr<SpdyFrame> push_b(spdy_util_.ConstructSpdyPush( |
- NULL, 0, 4, 1, "http://www.google.com/0.dat")); |
- MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4)}; |
- MockRead reads[] = { |
- CreateMockRead(*push_a, 1), CreateMockRead(*push_a_body, 2), |
- CreateMockRead(*push_b, 3), MockRead(ASYNC, 0, 5), // EOF |
- }; |
- DeterministicSocketData data( |
- reads, arraysize(reads), writes, arraysize(writes)); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- // Process the principal request, and the first push stream request & body. |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate(spdy_stream); |
- spdy_stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- |
- data.RunFor(3); |
- |
- // Verify that there is one unclaimed push stream. |
- EXPECT_EQ(1u, session->num_unclaimed_pushed_streams()); |
- SpdySession::PushedStreamMap::iterator iter = |
- session->unclaimed_pushed_streams_.find( |
- GURL("http://www.google.com/a.dat")); |
- EXPECT_TRUE(session->unclaimed_pushed_streams_.end() != iter); |
- |
- if (session->flow_control_state_ == |
- SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) { |
- // Unclaimed push body consumed bytes from the session window. |
- EXPECT_EQ(SpdySession::GetInitialWindowSize(GetParam()) - kUploadDataSize, |
- session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
- } |
- |
- // Shift time to expire the push stream. Read the second SYN_STREAM, |
- // and verify a RST_STREAM was written. |
- g_time_delta = base::TimeDelta::FromSeconds(301); |
- data.RunFor(2); |
- |
- // Verify that the second pushed stream evicted the first pushed stream. |
- EXPECT_EQ(1u, session->num_unclaimed_pushed_streams()); |
- iter = session->unclaimed_pushed_streams_.find( |
- GURL("http://www.google.com/0.dat")); |
- EXPECT_TRUE(session->unclaimed_pushed_streams_.end() != iter); |
- |
- if (session->flow_control_state_ == |
- SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) { |
- // Verify that the session window reclaimed the evicted stream body. |
- EXPECT_EQ(SpdySession::GetInitialWindowSize(GetParam()), |
- session->session_recv_window_size_); |
- EXPECT_EQ(kUploadDataSize, session->session_unacked_recv_window_bytes_); |
- } |
- |
- // Read and process EOF. |
- data.RunFor(1); |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-TEST_P(SpdySessionTest, FailedPing) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
- }; |
- scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false)); |
- scoped_ptr<SpdyFrame> goaway( |
- spdy_util_.ConstructSpdyGoAway(0, GOAWAY_PROTOCOL_ERROR, "Failed ping.")); |
- MockWrite writes[] = {CreateMockWrite(*write_ping), CreateMockWrite(*goaway)}; |
- StaticSocketDataProvider data( |
- reads, arraysize(reads), writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, test_url_, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL); |
- spdy_stream1->SetDelegate(&delegate); |
- |
- session->set_connection_at_risk_of_loss_time(base::TimeDelta::FromSeconds(0)); |
- session->set_hung_interval(base::TimeDelta::FromSeconds(0)); |
- |
- // Send a PING frame. |
- session->WritePingFrame(1, false); |
- EXPECT_LT(0, session->pings_in_flight()); |
- EXPECT_GE(session->next_ping_id(), 1U); |
- EXPECT_TRUE(session->check_ping_status_pending()); |
- |
- // Assert session is not closed. |
- EXPECT_TRUE(session->IsAvailable()); |
- EXPECT_LT(0u, session->num_active_streams() + session->num_created_streams()); |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- // We set last time we have received any data in 1 sec less than now. |
- // CheckPingStatus will trigger timeout because hung interval is zero. |
- base::TimeTicks now = base::TimeTicks::Now(); |
- session->last_activity_time_ = now - base::TimeDelta::FromSeconds(1); |
- session->CheckPingStatus(now); |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- EXPECT_TRUE(session == NULL); |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
-} |
- |
-// Request kInitialMaxConcurrentStreams + 1 streams. Receive a |
-// settings frame increasing the max concurrent streams by 1. Make |
-// sure nothing blows up. This is a regression test for |
-// http://crbug.com/57331 . |
-TEST_P(SpdySessionTest, OnSettings) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- const SpdySettingsIds kSpdySettingsIds = SETTINGS_MAX_CONCURRENT_STREAMS; |
- |
- SettingsMap new_settings; |
- const uint32 max_concurrent_streams = kInitialMaxConcurrentStreams + 1; |
- new_settings[kSpdySettingsIds] = |
- SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams); |
- scoped_ptr<SpdyFrame> settings_frame( |
- spdy_util_.ConstructSpdySettings(new_settings)); |
- MockRead reads[] = { |
- CreateMockRead(*settings_frame, 0), |
- MockRead(ASYNC, 0, 1), |
- }; |
- |
- scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); |
- MockWrite writes[] = { |
- CreateMockWrite(*settings_ack, 2), |
- }; |
- |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- // Create the maximum number of concurrent streams. |
- for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) { |
- base::WeakPtr<SpdyStream> spdy_stream = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, test_url_, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream != NULL); |
- } |
- |
- StreamReleaserCallback stream_releaser; |
- SpdyStreamRequest request; |
- ASSERT_EQ(ERR_IO_PENDING, |
- request.StartRequest( |
- SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM, |
- BoundNetLog(), |
- stream_releaser.MakeCallback(&request))); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(OK, stream_releaser.WaitForResult()); |
- |
- data.RunFor(1); |
- if (spdy_util_.spdy_version() >= SPDY4) { |
- // Allow the SETTINGS+ACK to write, so the session finishes draining. |
- data.RunFor(1); |
- } |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Start with a persisted value for max concurrent streams. Receive a |
-// settings frame increasing the max concurrent streams by 1 and which |
-// also clears the persisted data. Verify that persisted data is |
-// correct. |
-TEST_P(SpdySessionTest, ClearSettings) { |
- if (spdy_util_.spdy_version() >= SPDY4) { |
- // SPDY4 doesn't include settings persistence, or a CLEAR_SETTINGS flag. |
- // Flag 0x1, CLEAR_SETTINGS in SPDY3, is instead settings ACK in SPDY4. |
- return; |
- } |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- SettingsMap new_settings; |
- const uint32 max_concurrent_streams = kInitialMaxConcurrentStreams + 1; |
- new_settings[SETTINGS_MAX_CONCURRENT_STREAMS] = |
- SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams); |
- scoped_ptr<SpdyFrame> settings_frame( |
- spdy_util_.ConstructSpdySettings(new_settings)); |
- uint8 flags = SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS; |
- test::SetFrameFlags(settings_frame.get(), flags, spdy_util_.spdy_version()); |
- MockRead reads[] = { |
- CreateMockRead(*settings_frame, 0), |
- MockRead(ASYNC, 0, 1), |
- }; |
- |
- DeterministicSocketData data(reads, arraysize(reads), NULL, 0); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- // Initialize the SpdySetting with the default. |
- spdy_session_pool_->http_server_properties()->SetSpdySetting( |
- test_host_port_pair_, |
- SETTINGS_MAX_CONCURRENT_STREAMS, |
- SETTINGS_FLAG_PLEASE_PERSIST, |
- kInitialMaxConcurrentStreams); |
- |
- EXPECT_FALSE( |
- spdy_session_pool_->http_server_properties()->GetSpdySettings( |
- test_host_port_pair_).empty()); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- // Create the maximum number of concurrent streams. |
- for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) { |
- base::WeakPtr<SpdyStream> spdy_stream = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, test_url_, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream != NULL); |
- } |
- |
- StreamReleaserCallback stream_releaser; |
- |
- SpdyStreamRequest request; |
- ASSERT_EQ(ERR_IO_PENDING, |
- request.StartRequest( |
- SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM, |
- BoundNetLog(), |
- stream_releaser.MakeCallback(&request))); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(OK, stream_releaser.WaitForResult()); |
- |
- // Make sure that persisted data is cleared. |
- EXPECT_TRUE( |
- spdy_session_pool_->http_server_properties()->GetSpdySettings( |
- test_host_port_pair_).empty()); |
- |
- // Make sure session's max_concurrent_streams is correct. |
- EXPECT_EQ(kInitialMaxConcurrentStreams + 1, |
- session->max_concurrent_streams()); |
- |
- data.RunFor(1); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Start with max concurrent streams set to 1. Request two streams. |
-// When the first completes, have the callback close its stream, which |
-// should trigger the second stream creation. Then cancel that one |
-// immediately. Don't crash. This is a regression test for |
-// http://crbug.com/63532 . |
-TEST_P(SpdySessionTest, CancelPendingCreateStream) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
- }; |
- |
- StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- |
- // Initialize the SpdySetting with 1 max concurrent streams. |
- spdy_session_pool_->http_server_properties()->SetSpdySetting( |
- test_host_port_pair_, |
- SETTINGS_MAX_CONCURRENT_STREAMS, |
- SETTINGS_FLAG_PLEASE_PERSIST, |
- 1); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- // Leave room for only one more stream to be created. |
- for (size_t i = 0; i < kInitialMaxConcurrentStreams - 1; ++i) { |
- base::WeakPtr<SpdyStream> spdy_stream = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, test_url_, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream != NULL); |
- } |
- |
- // Create 2 more streams. First will succeed. Second will be pending. |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, test_url_, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- |
- // Use scoped_ptr to let us invalidate the memory when we want to, to trigger |
- // a valgrind error if the callback is invoked when it's not supposed to be. |
- scoped_ptr<TestCompletionCallback> callback(new TestCompletionCallback); |
- |
- SpdyStreamRequest request; |
- ASSERT_EQ(ERR_IO_PENDING, |
- request.StartRequest( |
- SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM, |
- BoundNetLog(), |
- callback->callback())); |
- |
- // Release the first one, this will allow the second to be created. |
- spdy_stream1->Cancel(); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- |
- request.CancelRequest(); |
- callback.reset(); |
- |
- // Should not crash when running the pending callback. |
- base::MessageLoop::current()->RunUntilIdle(); |
-} |
- |
-TEST_P(SpdySessionTest, SendInitialDataOnNewSession) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
- }; |
- |
- SettingsMap settings; |
- const SpdySettingsIds kSpdySettingsIds1 = SETTINGS_MAX_CONCURRENT_STREAMS; |
- const SpdySettingsIds kSpdySettingsIds2 = SETTINGS_INITIAL_WINDOW_SIZE; |
- const uint32 kInitialRecvWindowSize = 10 * 1024 * 1024; |
- settings[kSpdySettingsIds1] = |
- SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams); |
- if (spdy_util_.spdy_version() >= SPDY3) { |
- settings[kSpdySettingsIds2] = |
- SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kInitialRecvWindowSize); |
- } |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> settings_frame( |
- spdy_util_.ConstructSpdySettings(settings)); |
- scoped_ptr<SpdyFrame> initial_window_update( |
- spdy_util_.ConstructSpdyWindowUpdate( |
- kSessionFlowControlStreamId, |
- kDefaultInitialRecvWindowSize - |
- SpdySession::GetInitialWindowSize(GetParam()))); |
- std::vector<MockWrite> writes; |
- if ((GetParam() >= kProtoSPDY4MinimumVersion) && |
- (GetParam() <= kProtoSPDY4MaximumVersion)) { |
- writes.push_back( |
- MockWrite(ASYNC, |
- kHttp2ConnectionHeaderPrefix, |
- kHttp2ConnectionHeaderPrefixSize)); |
- } |
- writes.push_back(CreateMockWrite(*settings_frame)); |
- if (GetParam() >= kProtoSPDY31) { |
- writes.push_back(CreateMockWrite(*initial_window_update)); |
- }; |
- |
- SettingsMap server_settings; |
- const uint32 initial_max_concurrent_streams = 1; |
- server_settings[SETTINGS_MAX_CONCURRENT_STREAMS] = |
- SettingsFlagsAndValue(SETTINGS_FLAG_PERSISTED, |
- initial_max_concurrent_streams); |
- scoped_ptr<SpdyFrame> server_settings_frame( |
- spdy_util_.ConstructSpdySettings(server_settings)); |
- if (GetParam() <= kProtoSPDY31) { |
- writes.push_back(CreateMockWrite(*server_settings_frame)); |
- } |
- |
- session_deps_.stream_initial_recv_window_size = kInitialRecvWindowSize; |
- |
- StaticSocketDataProvider data(reads, arraysize(reads), |
- vector_as_array(&writes), writes.size()); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- |
- spdy_session_pool_->http_server_properties()->SetSpdySetting( |
- test_host_port_pair_, |
- SETTINGS_MAX_CONCURRENT_STREAMS, |
- SETTINGS_FLAG_PLEASE_PERSIST, |
- initial_max_concurrent_streams); |
- |
- SpdySessionPoolPeer pool_peer(spdy_session_pool_); |
- pool_peer.SetEnableSendingInitialData(true); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(data.at_write_eof()); |
-} |
- |
-TEST_P(SpdySessionTest, ClearSettingsStorageOnIPAddressChanged) { |
- CreateNetworkSession(); |
- |
- base::WeakPtr<HttpServerProperties> test_http_server_properties = |
- spdy_session_pool_->http_server_properties(); |
- SettingsFlagsAndValue flags_and_value1(SETTINGS_FLAG_PLEASE_PERSIST, 2); |
- test_http_server_properties->SetSpdySetting( |
- test_host_port_pair_, |
- SETTINGS_MAX_CONCURRENT_STREAMS, |
- SETTINGS_FLAG_PLEASE_PERSIST, |
- 2); |
- EXPECT_NE(0u, test_http_server_properties->GetSpdySettings( |
- test_host_port_pair_).size()); |
- spdy_session_pool_->OnIPAddressChanged(); |
- EXPECT_EQ(0u, test_http_server_properties->GetSpdySettings( |
- test_host_port_pair_).size()); |
-} |
- |
-TEST_P(SpdySessionTest, Initialize) { |
- CapturingBoundNetLog log; |
- session_deps_.net_log = log.bound().net_log(); |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 0) // EOF |
- }; |
- |
- StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, log.bound()); |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- // Flush the read completion task. |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- net::CapturingNetLog::CapturedEntryList entries; |
- log.GetEntries(&entries); |
- EXPECT_LT(0u, entries.size()); |
- |
- // Check that we logged TYPE_SPDY_SESSION_INITIALIZED correctly. |
- int pos = net::ExpectLogContainsSomewhere( |
- entries, 0, |
- net::NetLog::TYPE_SPDY_SESSION_INITIALIZED, |
- net::NetLog::PHASE_NONE); |
- EXPECT_LT(0, pos); |
- |
- CapturingNetLog::CapturedEntry entry = entries[pos]; |
- NetLog::Source socket_source; |
- EXPECT_TRUE(NetLog::Source::FromEventParameters(entry.params.get(), |
- &socket_source)); |
- EXPECT_TRUE(socket_source.IsValid()); |
- EXPECT_NE(log.bound().source().id, socket_source.id); |
-} |
- |
-TEST_P(SpdySessionTest, NetLogOnSessionGoaway) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway()); |
- MockRead reads[] = { |
- CreateMockRead(*goaway), |
- MockRead(SYNCHRONOUS, 0, 0) // EOF |
- }; |
- |
- StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- |
- CapturingBoundNetLog log; |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, log.bound()); |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- // Flush the read completion task. |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- EXPECT_TRUE(session == NULL); |
- |
- // Check that the NetLog was filled reasonably. |
- net::CapturingNetLog::CapturedEntryList entries; |
- log.GetEntries(&entries); |
- EXPECT_LT(0u, entries.size()); |
- |
- // Check that we logged SPDY_SESSION_CLOSE correctly. |
- int pos = net::ExpectLogContainsSomewhere( |
- entries, 0, |
- net::NetLog::TYPE_SPDY_SESSION_CLOSE, |
- net::NetLog::PHASE_NONE); |
- |
- if (pos < static_cast<int>(entries.size())) { |
- CapturingNetLog::CapturedEntry entry = entries[pos]; |
- int error_code = 0; |
- ASSERT_TRUE(entry.GetNetErrorCode(&error_code)); |
- EXPECT_EQ(OK, error_code); |
- } else { |
- ADD_FAILURE(); |
- } |
-} |
- |
-TEST_P(SpdySessionTest, NetLogOnSessionEOF) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, 0, 0) // EOF |
- }; |
- |
- StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- |
- CapturingBoundNetLog log; |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, log.bound()); |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- // Flush the read completion task. |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- EXPECT_TRUE(session == NULL); |
- |
- // Check that the NetLog was filled reasonably. |
- net::CapturingNetLog::CapturedEntryList entries; |
- log.GetEntries(&entries); |
- EXPECT_LT(0u, entries.size()); |
- |
- // Check that we logged SPDY_SESSION_CLOSE correctly. |
- int pos = |
- net::ExpectLogContainsSomewhere(entries, |
- 0, |
- net::NetLog::TYPE_SPDY_SESSION_CLOSE, |
- net::NetLog::PHASE_NONE); |
- |
- if (pos < static_cast<int>(entries.size())) { |
- CapturingNetLog::CapturedEntry entry = entries[pos]; |
- int error_code = 0; |
- ASSERT_TRUE(entry.GetNetErrorCode(&error_code)); |
- EXPECT_EQ(ERR_CONNECTION_CLOSED, error_code); |
- } else { |
- ADD_FAILURE(); |
- } |
-} |
- |
-TEST_P(SpdySessionTest, SynCompressionHistograms) { |
- session_deps_.enable_compression = true; |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, true, 1, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), |
- }; |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 1) // EOF |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate(spdy_stream); |
- spdy_stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders()); |
- |
- // Write request headers & capture resulting histogram update. |
- base::HistogramTester histogram_tester; |
- |
- data.RunFor(1); |
- // Regression test of compression performance under the request fixture. |
- switch (spdy_util_.spdy_version()) { |
- case SPDY3: |
- histogram_tester.ExpectBucketCount( |
- "Net.SpdySynStreamCompressionPercentage", 30, 1); |
- break; |
- case SPDY4: |
- histogram_tester.ExpectBucketCount( |
- "Net.SpdySynStreamCompressionPercentage", 82, 1); |
- break; |
- default: |
- NOTREACHED(); |
- } |
- |
- // Read and process EOF. |
- data.RunFor(1); |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Queue up a low-priority SYN_STREAM followed by a high-priority |
-// one. The high priority one should still send first and receive |
-// first. |
-TEST_P(SpdySessionTest, OutOfOrderSynStreams) { |
- // Construct the request. |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> req_highest( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, HIGHEST, true)); |
- scoped_ptr<SpdyFrame> req_lowest( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req_highest, 0), |
- CreateMockWrite(*req_lowest, 1), |
- }; |
- |
- scoped_ptr<SpdyFrame> resp_highest( |
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- scoped_ptr<SpdyFrame> body_highest( |
- spdy_util_.ConstructSpdyBodyFrame(1, true)); |
- scoped_ptr<SpdyFrame> resp_lowest( |
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); |
- scoped_ptr<SpdyFrame> body_lowest( |
- spdy_util_.ConstructSpdyBodyFrame(3, true)); |
- MockRead reads[] = { |
- CreateMockRead(*resp_highest, 2), |
- CreateMockRead(*body_highest, 3), |
- CreateMockRead(*resp_lowest, 4), |
- CreateMockRead(*body_lowest, 5), |
- MockRead(ASYNC, 0, 6) // EOF |
- }; |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url(kDefaultURL); |
- |
- base::WeakPtr<SpdyStream> spdy_stream_lowest = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream_lowest); |
- EXPECT_EQ(0u, spdy_stream_lowest->stream_id()); |
- test::StreamDelegateDoNothing delegate_lowest(spdy_stream_lowest); |
- spdy_stream_lowest->SetDelegate(&delegate_lowest); |
- |
- base::WeakPtr<SpdyStream> spdy_stream_highest = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, HIGHEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream_highest); |
- EXPECT_EQ(0u, spdy_stream_highest->stream_id()); |
- test::StreamDelegateDoNothing delegate_highest(spdy_stream_highest); |
- spdy_stream_highest->SetDelegate(&delegate_highest); |
- |
- // Queue the lower priority one first. |
- |
- scoped_ptr<SpdyHeaderBlock> headers_lowest( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- spdy_stream_lowest->SendRequestHeaders( |
- headers_lowest.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream_lowest->HasUrlFromHeaders()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers_highest( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- spdy_stream_highest->SendRequestHeaders( |
- headers_highest.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream_highest->HasUrlFromHeaders()); |
- |
- data.RunFor(7); |
- |
- EXPECT_FALSE(spdy_stream_lowest); |
- EXPECT_FALSE(spdy_stream_highest); |
- EXPECT_EQ(3u, delegate_lowest.stream_id()); |
- EXPECT_EQ(1u, delegate_highest.stream_id()); |
-} |
- |
-TEST_P(SpdySessionTest, CancelStream) { |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- // Request 1, at HIGHEST priority, will be cancelled before it writes data. |
- // Request 2, at LOWEST priority, will be a full request and will be id 1. |
- scoped_ptr<SpdyFrame> req2( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req2, 0), |
- }; |
- |
- scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
- MockRead reads[] = { |
- CreateMockRead(*resp2, 1), |
- CreateMockRead(*body2, 2), |
- MockRead(ASYNC, 0, 3) // EOF |
- }; |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url1, HIGHEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- GURL url2(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream2 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url2, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream2.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream2->stream_id()); |
- test::StreamDelegateDoNothing delegate2(spdy_stream2); |
- spdy_stream2->SetDelegate(&delegate2); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers2( |
- spdy_util_.ConstructGetHeaderBlock(url2.spec())); |
- spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders()); |
- |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- |
- spdy_stream1->Cancel(); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- |
- EXPECT_EQ(0u, delegate1.stream_id()); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(0u, delegate1.stream_id()); |
- EXPECT_EQ(1u, delegate2.stream_id()); |
- |
- spdy_stream2->Cancel(); |
- EXPECT_EQ(NULL, spdy_stream2.get()); |
-} |
- |
-// Create two streams that are set to re-close themselves on close, |
-// and then close the session. Nothing should blow up. Also a |
-// regression test for http://crbug.com/139518 . |
-TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- // No actual data will be sent. |
- MockWrite writes[] = { |
- MockWrite(ASYNC, 0, 1) // EOF |
- }; |
- |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 0) // EOF |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, url1, HIGHEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- |
- GURL url2(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream2 = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, url2, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream2.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream2->stream_id()); |
- |
- test::ClosingDelegate delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- test::ClosingDelegate delegate2(spdy_stream2); |
- spdy_stream2->SetDelegate(&delegate2); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers2( |
- spdy_util_.ConstructGetHeaderBlock(url2.spec())); |
- spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders()); |
- |
- // Ensure that the streams have not yet been activated and assigned an id. |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- EXPECT_EQ(0u, spdy_stream2->stream_id()); |
- |
- // Ensure we don't crash while closing the session. |
- session->CloseSessionOnError(ERR_ABORTED, std::string()); |
- |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- EXPECT_EQ(NULL, spdy_stream2.get()); |
- |
- EXPECT_TRUE(delegate1.StreamIsClosed()); |
- EXPECT_TRUE(delegate2.StreamIsClosed()); |
- |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Create two streams that are set to close each other on close, and |
-// then close the session. Nothing should blow up. |
-TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- // No actual data will be sent. |
- MockWrite writes[] = { |
- MockWrite(ASYNC, 0, 1) // EOF |
- }; |
- |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 0) // EOF |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, url1, HIGHEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- |
- GURL url2(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream2 = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, url2, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream2.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream2->stream_id()); |
- |
- // Make |spdy_stream1| close |spdy_stream2|. |
- test::ClosingDelegate delegate1(spdy_stream2); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- // Make |spdy_stream2| close |spdy_stream1|. |
- test::ClosingDelegate delegate2(spdy_stream1); |
- spdy_stream2->SetDelegate(&delegate2); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers2( |
- spdy_util_.ConstructGetHeaderBlock(url2.spec())); |
- spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders()); |
- |
- // Ensure that the streams have not yet been activated and assigned an id. |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- EXPECT_EQ(0u, spdy_stream2->stream_id()); |
- |
- // Ensure we don't crash while closing the session. |
- session->CloseSessionOnError(ERR_ABORTED, std::string()); |
- |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- EXPECT_EQ(NULL, spdy_stream2.get()); |
- |
- EXPECT_TRUE(delegate1.StreamIsClosed()); |
- EXPECT_TRUE(delegate2.StreamIsClosed()); |
- |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Create two streams that are set to re-close themselves on close, |
-// activate them, and then close the session. Nothing should blow up. |
-TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- scoped_ptr<SpdyFrame> req2( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- CreateMockWrite(*req2, 1), |
- }; |
- |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 2) // EOF |
- }; |
- |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url1, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- |
- GURL url2(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream2 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url2, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream2.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream2->stream_id()); |
- |
- test::ClosingDelegate delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- test::ClosingDelegate delegate2(spdy_stream2); |
- spdy_stream2->SetDelegate(&delegate2); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers2( |
- spdy_util_.ConstructGetHeaderBlock(url2.spec())); |
- spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders()); |
- |
- // Ensure that the streams have not yet been activated and assigned an id. |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- EXPECT_EQ(0u, spdy_stream2->stream_id()); |
- |
- data.RunFor(2); |
- |
- EXPECT_EQ(1u, spdy_stream1->stream_id()); |
- EXPECT_EQ(3u, spdy_stream2->stream_id()); |
- |
- // Ensure we don't crash while closing the session. |
- session->CloseSessionOnError(ERR_ABORTED, std::string()); |
- |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- EXPECT_EQ(NULL, spdy_stream2.get()); |
- |
- EXPECT_TRUE(delegate1.StreamIsClosed()); |
- EXPECT_TRUE(delegate2.StreamIsClosed()); |
- |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Create two streams that are set to close each other on close, |
-// activate them, and then close the session. Nothing should blow up. |
-TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- scoped_ptr<SpdyFrame> req2( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- CreateMockWrite(*req2, 1), |
- }; |
- |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 2) // EOF |
- }; |
- |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url1, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- |
- GURL url2(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream2 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url2, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream2.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream2->stream_id()); |
- |
- // Make |spdy_stream1| close |spdy_stream2|. |
- test::ClosingDelegate delegate1(spdy_stream2); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- // Make |spdy_stream2| close |spdy_stream1|. |
- test::ClosingDelegate delegate2(spdy_stream1); |
- spdy_stream2->SetDelegate(&delegate2); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers2( |
- spdy_util_.ConstructGetHeaderBlock(url2.spec())); |
- spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders()); |
- |
- // Ensure that the streams have not yet been activated and assigned an id. |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- EXPECT_EQ(0u, spdy_stream2->stream_id()); |
- |
- data.RunFor(2); |
- |
- EXPECT_EQ(1u, spdy_stream1->stream_id()); |
- EXPECT_EQ(3u, spdy_stream2->stream_id()); |
- |
- // Ensure we don't crash while closing the session. |
- session->CloseSessionOnError(ERR_ABORTED, std::string()); |
- |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- EXPECT_EQ(NULL, spdy_stream2.get()); |
- |
- EXPECT_TRUE(delegate1.StreamIsClosed()); |
- EXPECT_TRUE(delegate2.StreamIsClosed()); |
- |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Delegate that closes a given session when the stream is closed. |
-class SessionClosingDelegate : public test::StreamDelegateDoNothing { |
- public: |
- SessionClosingDelegate(const base::WeakPtr<SpdyStream>& stream, |
- const base::WeakPtr<SpdySession>& session_to_close) |
- : StreamDelegateDoNothing(stream), |
- session_to_close_(session_to_close) {} |
- |
- ~SessionClosingDelegate() override {} |
- |
- void OnClose(int status) override { |
- session_to_close_->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Error"); |
- } |
- |
- private: |
- base::WeakPtr<SpdySession> session_to_close_; |
-}; |
- |
-// Close an activated stream that closes its session. Nothing should |
-// blow up. This is a regression test for http://crbug.com/263691 . |
-TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- scoped_ptr<SpdyFrame> rst( |
- spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); |
- scoped_ptr<SpdyFrame> goaway( |
- spdy_util_.ConstructSpdyGoAway(0, GOAWAY_PROTOCOL_ERROR, "Error")); |
- // The GOAWAY has higher-priority than the RST_STREAM, and is written first |
- // despite being queued second. |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 1), |
- CreateMockWrite(*rst, 2), |
- }; |
- |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 3) // EOF |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream->stream_id()); |
- |
- SessionClosingDelegate delegate(spdy_stream, session); |
- spdy_stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders()); |
- |
- EXPECT_EQ(0u, spdy_stream->stream_id()); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(1u, spdy_stream->stream_id()); |
- |
- // Ensure we don't crash while closing the stream (which closes the |
- // session). |
- spdy_stream->Cancel(); |
- |
- EXPECT_EQ(NULL, spdy_stream.get()); |
- EXPECT_TRUE(delegate.StreamIsClosed()); |
- |
- data.RunFor(2); // Write the RST_STREAM & GOAWAY. |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-TEST_P(SpdySessionTest, VerifyDomainAuthentication) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- // No actual data will be sent. |
- MockWrite writes[] = { |
- MockWrite(ASYNC, 0, 1) // EOF |
- }; |
- |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 0) // EOF |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- // Load a cert that is valid for: |
- // www.example.org |
- // mail.example.org |
- // www.example.com |
- base::FilePath certs_dir = GetTestCertsDirectory(); |
- scoped_refptr<X509Certificate> test_cert( |
- ImportCertFromFile(certs_dir, "spdy_pooling.pem")); |
- ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get()); |
- |
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK); |
- ssl.cert = test_cert; |
- session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateSecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- EXPECT_TRUE(session->VerifyDomainAuthentication("www.example.org")); |
- EXPECT_TRUE(session->VerifyDomainAuthentication("mail.example.org")); |
- EXPECT_TRUE(session->VerifyDomainAuthentication("mail.example.com")); |
- EXPECT_FALSE(session->VerifyDomainAuthentication("mail.google.com")); |
-} |
- |
-TEST_P(SpdySessionTest, ConnectionPooledWithTlsChannelId) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- // No actual data will be sent. |
- MockWrite writes[] = { |
- MockWrite(ASYNC, 0, 1) // EOF |
- }; |
- |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 0) // EOF |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- // Load a cert that is valid for: |
- // www.example.org |
- // mail.example.org |
- // www.example.com |
- base::FilePath certs_dir = GetTestCertsDirectory(); |
- scoped_refptr<X509Certificate> test_cert( |
- ImportCertFromFile(certs_dir, "spdy_pooling.pem")); |
- ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get()); |
- |
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK); |
- ssl.channel_id_sent = true; |
- ssl.cert = test_cert; |
- session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateSecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- EXPECT_TRUE(session->VerifyDomainAuthentication("www.example.org")); |
- EXPECT_TRUE(session->VerifyDomainAuthentication("mail.example.org")); |
- EXPECT_FALSE(session->VerifyDomainAuthentication("mail.example.com")); |
- EXPECT_FALSE(session->VerifyDomainAuthentication("mail.google.com")); |
-} |
- |
-TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) { |
- // TODO(rtenneti): Define a helper class/methods and move the common code in |
- // this file. |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- SettingsMap new_settings; |
- const SpdySettingsIds kSpdySettingsIds1 = SETTINGS_MAX_CONCURRENT_STREAMS; |
- const uint32 max_concurrent_streams = 1; |
- new_settings[kSpdySettingsIds1] = |
- SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams); |
- |
- scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
- scoped_ptr<SpdyFrame> req2( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); |
- scoped_ptr<SpdyFrame> req3( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*settings_ack, 1), |
- CreateMockWrite(*req1, 2), |
- CreateMockWrite(*req2, 5), |
- CreateMockWrite(*req3, 8), |
- }; |
- |
- // Set up the socket so we read a SETTINGS frame that sets max concurrent |
- // streams to 1. |
- scoped_ptr<SpdyFrame> settings_frame( |
- spdy_util_.ConstructSpdySettings(new_settings)); |
- |
- scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
- |
- scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); |
- scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, true)); |
- |
- scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5)); |
- scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, true)); |
- |
- MockRead reads[] = { |
- CreateMockRead(*settings_frame), |
- CreateMockRead(*resp1, 3), |
- CreateMockRead(*body1, 4), |
- CreateMockRead(*resp2, 6), |
- CreateMockRead(*body2, 7), |
- CreateMockRead(*resp3, 9), |
- CreateMockRead(*body3, 10), |
- MockRead(ASYNC, 0, 11) // EOF |
- }; |
- |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- // Read the settings frame. |
- data.RunFor(1); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url1, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- TestCompletionCallback callback2; |
- GURL url2(kDefaultURL); |
- SpdyStreamRequest request2; |
- ASSERT_EQ(ERR_IO_PENDING, |
- request2.StartRequest( |
- SPDY_REQUEST_RESPONSE_STREAM, |
- session, url2, LOWEST, BoundNetLog(), callback2.callback())); |
- |
- TestCompletionCallback callback3; |
- GURL url3(kDefaultURL); |
- SpdyStreamRequest request3; |
- ASSERT_EQ(ERR_IO_PENDING, |
- request3.StartRequest( |
- SPDY_REQUEST_RESPONSE_STREAM, |
- session, url3, LOWEST, BoundNetLog(), callback3.callback())); |
- |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(1u, session->num_created_streams()); |
- EXPECT_EQ(2u, session->pending_create_stream_queue_size(LOWEST)); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- // Run until 1st stream is activated and then closed. |
- EXPECT_EQ(0u, delegate1.stream_id()); |
- data.RunFor(4); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- EXPECT_EQ(1u, delegate1.stream_id()); |
- |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST)); |
- |
- // Pump loop for SpdySession::ProcessPendingStreamRequests() to |
- // create the 2nd stream. |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(1u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST)); |
- |
- base::WeakPtr<SpdyStream> stream2 = request2.ReleaseStream(); |
- test::StreamDelegateDoNothing delegate2(stream2); |
- stream2->SetDelegate(&delegate2); |
- scoped_ptr<SpdyHeaderBlock> headers2( |
- spdy_util_.ConstructGetHeaderBlock(url2.spec())); |
- stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(stream2->HasUrlFromHeaders()); |
- |
- // Run until 2nd stream is activated and then closed. |
- EXPECT_EQ(0u, delegate2.stream_id()); |
- data.RunFor(3); |
- EXPECT_EQ(NULL, stream2.get()); |
- EXPECT_EQ(3u, delegate2.stream_id()); |
- |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST)); |
- |
- // Pump loop for SpdySession::ProcessPendingStreamRequests() to |
- // create the 3rd stream. |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(1u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST)); |
- |
- base::WeakPtr<SpdyStream> stream3 = request3.ReleaseStream(); |
- test::StreamDelegateDoNothing delegate3(stream3); |
- stream3->SetDelegate(&delegate3); |
- scoped_ptr<SpdyHeaderBlock> headers3( |
- spdy_util_.ConstructGetHeaderBlock(url3.spec())); |
- stream3->SendRequestHeaders(headers3.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(stream3->HasUrlFromHeaders()); |
- |
- // Run until 2nd stream is activated and then closed. |
- EXPECT_EQ(0u, delegate3.stream_id()); |
- data.RunFor(3); |
- EXPECT_EQ(NULL, stream3.get()); |
- EXPECT_EQ(5u, delegate3.stream_id()); |
- |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST)); |
- |
- data.RunFor(1); |
-} |
- |
-TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
- }; |
- |
- StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- // Leave room for only one more stream to be created. |
- for (size_t i = 0; i < kInitialMaxConcurrentStreams - 1; ++i) { |
- base::WeakPtr<SpdyStream> spdy_stream = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, test_url_, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream != NULL); |
- } |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, url1, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- |
- TestCompletionCallback callback2; |
- GURL url2(kDefaultURL); |
- SpdyStreamRequest request2; |
- ASSERT_EQ(ERR_IO_PENDING, |
- request2.StartRequest( |
- SPDY_BIDIRECTIONAL_STREAM, session, url2, LOWEST, BoundNetLog(), |
- callback2.callback())); |
- |
- TestCompletionCallback callback3; |
- GURL url3(kDefaultURL); |
- SpdyStreamRequest request3; |
- ASSERT_EQ(ERR_IO_PENDING, |
- request3.StartRequest( |
- SPDY_BIDIRECTIONAL_STREAM, session, url3, LOWEST, BoundNetLog(), |
- callback3.callback())); |
- |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(kInitialMaxConcurrentStreams, session->num_created_streams()); |
- EXPECT_EQ(2u, session->pending_create_stream_queue_size(LOWEST)); |
- |
- // Cancel the first stream; this will allow the second stream to be created. |
- EXPECT_TRUE(spdy_stream1.get() != NULL); |
- spdy_stream1->Cancel(); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- |
- EXPECT_EQ(OK, callback2.WaitForResult()); |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(kInitialMaxConcurrentStreams, session->num_created_streams()); |
- EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST)); |
- |
- // Cancel the second stream; this will allow the third stream to be created. |
- base::WeakPtr<SpdyStream> spdy_stream2 = request2.ReleaseStream(); |
- spdy_stream2->Cancel(); |
- EXPECT_EQ(NULL, spdy_stream2.get()); |
- |
- EXPECT_EQ(OK, callback3.WaitForResult()); |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(kInitialMaxConcurrentStreams, session->num_created_streams()); |
- EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST)); |
- |
- // Cancel the third stream. |
- base::WeakPtr<SpdyStream> spdy_stream3 = request3.ReleaseStream(); |
- spdy_stream3->Cancel(); |
- EXPECT_EQ(NULL, spdy_stream3.get()); |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(kInitialMaxConcurrentStreams - 1, session->num_created_streams()); |
- EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST)); |
-} |
- |
-// Test that SpdySession::DoReadLoop reads data from the socket |
-// without yielding. This test makes 32k - 1 bytes of data available |
-// on the socket for reading. It then verifies that it has read all |
-// the available data without yielding. |
-TEST_P(SpdySessionTest, ReadDataWithoutYielding) { |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
- |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- }; |
- |
- // Build buffer of size kMaxReadBytesWithoutYielding / 4 |
- // (-spdy_data_frame_size). |
- ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding); |
- const int kPayloadSize = |
- kMaxReadBytesWithoutYielding / 4 - framer.GetControlFrameHeaderSize(); |
- TestDataStream test_stream; |
- scoped_refptr<net::IOBuffer> payload(new net::IOBuffer(kPayloadSize)); |
- char* payload_data = payload->data(); |
- test_stream.GetBytes(payload_data, kPayloadSize); |
- |
- scoped_ptr<SpdyFrame> partial_data_frame( |
- framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_NONE)); |
- scoped_ptr<SpdyFrame> finish_data_frame( |
- framer.CreateDataFrame(1, payload_data, kPayloadSize - 1, DATA_FLAG_FIN)); |
- |
- scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- |
- // Write 1 byte less than kMaxReadBytes to check that DoRead reads up to 32k |
- // bytes. |
- MockRead reads[] = { |
- CreateMockRead(*resp1, 1), |
- CreateMockRead(*partial_data_frame, 2), |
- CreateMockRead(*partial_data_frame, 3, SYNCHRONOUS), |
- CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS), |
- CreateMockRead(*finish_data_frame, 5, SYNCHRONOUS), |
- MockRead(ASYNC, 0, 6) // EOF |
- }; |
- |
- // Create SpdySession and SpdyStream and send the request. |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url1, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- scoped_ptr<SpdyHeaderBlock> headers1( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- // Set up the TaskObserver to verify SpdySession::DoReadLoop doesn't |
- // post a task. |
- SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop"); |
- |
- // Run until 1st read. |
- EXPECT_EQ(0u, delegate1.stream_id()); |
- data.RunFor(2); |
- EXPECT_EQ(1u, delegate1.stream_id()); |
- EXPECT_EQ(0u, observer.executed_count()); |
- |
- // Read all the data and verify SpdySession::DoReadLoop has not |
- // posted a task. |
- data.RunFor(4); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- |
- // Verify task observer's executed_count is zero, which indicates DoRead read |
- // all the available data. |
- EXPECT_EQ(0u, observer.executed_count()); |
- EXPECT_TRUE(data.at_write_eof()); |
- EXPECT_TRUE(data.at_read_eof()); |
-} |
- |
-// Test that SpdySession::DoReadLoop yields while reading the |
-// data. This test makes 32k + 1 bytes of data available on the socket |
-// for reading. It then verifies that DoRead has yielded even though |
-// there is data available for it to read (i.e, socket()->Read didn't |
-// return ERR_IO_PENDING during socket reads). |
-TEST_P(SpdySessionTest, TestYieldingDuringReadData) { |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
- |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- }; |
- |
- // Build buffer of size kMaxReadBytesWithoutYielding / 4 |
- // (-spdy_data_frame_size). |
- ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding); |
- const int kPayloadSize = |
- kMaxReadBytesWithoutYielding / 4 - framer.GetControlFrameHeaderSize(); |
- TestDataStream test_stream; |
- scoped_refptr<net::IOBuffer> payload(new net::IOBuffer(kPayloadSize)); |
- char* payload_data = payload->data(); |
- test_stream.GetBytes(payload_data, kPayloadSize); |
- |
- scoped_ptr<SpdyFrame> partial_data_frame( |
- framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_NONE)); |
- scoped_ptr<SpdyFrame> finish_data_frame( |
- framer.CreateDataFrame(1, "h", 1, DATA_FLAG_FIN)); |
- |
- scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- |
- // Write 1 byte more than kMaxReadBytes to check that DoRead yields. |
- MockRead reads[] = { |
- CreateMockRead(*resp1, 1), |
- CreateMockRead(*partial_data_frame, 2), |
- CreateMockRead(*partial_data_frame, 3, SYNCHRONOUS), |
- CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS), |
- CreateMockRead(*partial_data_frame, 5, SYNCHRONOUS), |
- CreateMockRead(*finish_data_frame, 6, SYNCHRONOUS), |
- MockRead(ASYNC, 0, 7) // EOF |
- }; |
- |
- // Create SpdySession and SpdyStream and send the request. |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url1, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- scoped_ptr<SpdyHeaderBlock> headers1( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- // Set up the TaskObserver to verify SpdySession::DoReadLoop posts a |
- // task. |
- SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop"); |
- |
- // Run until 1st read. |
- EXPECT_EQ(0u, delegate1.stream_id()); |
- data.RunFor(2); |
- EXPECT_EQ(1u, delegate1.stream_id()); |
- EXPECT_EQ(0u, observer.executed_count()); |
- |
- // Read all the data and verify SpdySession::DoReadLoop has posted a |
- // task. |
- data.RunFor(6); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- |
- // Verify task observer's executed_count is 1, which indicates DoRead has |
- // posted only one task and thus yielded though there is data available for it |
- // to read. |
- EXPECT_EQ(1u, observer.executed_count()); |
- EXPECT_TRUE(data.at_write_eof()); |
- EXPECT_TRUE(data.at_read_eof()); |
-} |
- |
-// Test that SpdySession::DoReadLoop() tests interactions of yielding |
-// + async, by doing the following MockReads. |
-// |
-// MockRead of SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K |
-// ASYNC 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K. |
-// |
-// The above reads 26K synchronously. Since that is less that 32K, we |
-// will attempt to read again. However, that DoRead() will return |
-// ERR_IO_PENDING (because of async read), so DoReadLoop() will |
-// yield. When we come back, DoRead() will read the results from the |
-// async read, and rest of the data synchronously. |
-TEST_P(SpdySessionTest, TestYieldingDuringAsyncReadData) { |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
- |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- }; |
- |
- // Build buffer of size kMaxReadBytesWithoutYielding / 4 |
- // (-spdy_data_frame_size). |
- ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding); |
- TestDataStream test_stream; |
- const int kEightKPayloadSize = |
- kMaxReadBytesWithoutYielding / 4 - framer.GetControlFrameHeaderSize(); |
- scoped_refptr<net::IOBuffer> eightk_payload( |
- new net::IOBuffer(kEightKPayloadSize)); |
- char* eightk_payload_data = eightk_payload->data(); |
- test_stream.GetBytes(eightk_payload_data, kEightKPayloadSize); |
- |
- // Build buffer of 2k size. |
- TestDataStream test_stream2; |
- const int kTwoKPayloadSize = kEightKPayloadSize - 6 * 1024; |
- scoped_refptr<net::IOBuffer> twok_payload( |
- new net::IOBuffer(kTwoKPayloadSize)); |
- char* twok_payload_data = twok_payload->data(); |
- test_stream2.GetBytes(twok_payload_data, kTwoKPayloadSize); |
- |
- scoped_ptr<SpdyFrame> eightk_data_frame(framer.CreateDataFrame( |
- 1, eightk_payload_data, kEightKPayloadSize, DATA_FLAG_NONE)); |
- scoped_ptr<SpdyFrame> twok_data_frame(framer.CreateDataFrame( |
- 1, twok_payload_data, kTwoKPayloadSize, DATA_FLAG_NONE)); |
- scoped_ptr<SpdyFrame> finish_data_frame(framer.CreateDataFrame( |
- 1, "h", 1, DATA_FLAG_FIN)); |
- |
- scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- |
- MockRead reads[] = { |
- CreateMockRead(*resp1, 1), |
- CreateMockRead(*eightk_data_frame, 2), |
- CreateMockRead(*eightk_data_frame, 3, SYNCHRONOUS), |
- CreateMockRead(*eightk_data_frame, 4, SYNCHRONOUS), |
- CreateMockRead(*twok_data_frame, 5, SYNCHRONOUS), |
- CreateMockRead(*eightk_data_frame, 6, ASYNC), |
- CreateMockRead(*eightk_data_frame, 7, SYNCHRONOUS), |
- CreateMockRead(*eightk_data_frame, 8, SYNCHRONOUS), |
- CreateMockRead(*eightk_data_frame, 9, SYNCHRONOUS), |
- CreateMockRead(*twok_data_frame, 10, SYNCHRONOUS), |
- CreateMockRead(*finish_data_frame, 11, SYNCHRONOUS), |
- MockRead(ASYNC, 0, 12) // EOF |
- }; |
- |
- // Create SpdySession and SpdyStream and send the request. |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url1, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- scoped_ptr<SpdyHeaderBlock> headers1( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- // Set up the TaskObserver to monitor SpdySession::DoReadLoop |
- // posting of tasks. |
- SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop"); |
- |
- // Run until 1st read. |
- EXPECT_EQ(0u, delegate1.stream_id()); |
- data.RunFor(2); |
- EXPECT_EQ(1u, delegate1.stream_id()); |
- EXPECT_EQ(0u, observer.executed_count()); |
- |
- // Read all the data and verify SpdySession::DoReadLoop has posted a |
- // task. |
- data.RunFor(12); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- |
- // Verify task observer's executed_count is 1, which indicates DoRead has |
- // posted only one task and thus yielded though there is data available for |
- // it to read. |
- EXPECT_EQ(1u, observer.executed_count()); |
- EXPECT_TRUE(data.at_write_eof()); |
- EXPECT_TRUE(data.at_read_eof()); |
-} |
- |
-// Send a GoAway frame when SpdySession is in DoReadLoop. Make sure |
-// nothing blows up. |
-TEST_P(SpdySessionTest, GoAwayWhileInDoReadLoop) { |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
- |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- }; |
- |
- scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
- scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway()); |
- |
- MockRead reads[] = { |
- CreateMockRead(*resp1, 1), |
- CreateMockRead(*body1, 2), |
- CreateMockRead(*goaway, 3), |
- }; |
- |
- // Create SpdySession and SpdyStream and send the request. |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url1, MEDIUM, BoundNetLog()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers1( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- // Run until 1st read. |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- data.RunFor(1); |
- EXPECT_EQ(1u, spdy_stream1->stream_id()); |
- |
- // Run until GoAway. |
- data.RunFor(3); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- EXPECT_TRUE(data.at_write_eof()); |
- EXPECT_TRUE(data.at_read_eof()); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-// Within this framework, a SpdySession should be initialized with |
-// flow control disabled for protocol version 2, with flow control |
-// enabled only for streams for protocol version 3, and with flow |
-// control enabled for streams and sessions for higher versions. |
-TEST_P(SpdySessionTest, ProtocolNegotiation) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, 0, 0) // EOF |
- }; |
- StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateFakeSpdySession(spdy_session_pool_, key_); |
- |
- EXPECT_EQ(spdy_util_.spdy_version(), |
- session->buffered_spdy_framer_->protocol_version()); |
- EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
- session->flow_control_state()); |
- EXPECT_EQ(SpdySession::GetInitialWindowSize(GetParam()), |
- session->session_send_window_size_); |
- EXPECT_EQ(SpdySession::GetInitialWindowSize(GetParam()), |
- session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
-} |
- |
-// Tests the case of a non-SPDY request closing an idle SPDY session when no |
-// pointers to the idle session are currently held. |
-TEST_P(SpdySessionTest, CloseOneIdleConnection) { |
- ClientSocketPoolManager::set_max_sockets_per_group( |
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
- ClientSocketPoolManager::set_max_sockets_per_pool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
- }; |
- StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- |
- TransportClientSocketPool* pool = |
- http_session_->GetTransportSocketPool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL); |
- |
- // Create an idle SPDY session. |
- SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- base::WeakPtr<SpdySession> session1 = |
- CreateInsecureSpdySession(http_session_, key1, BoundNetLog()); |
- EXPECT_FALSE(pool->IsStalled()); |
- |
- // Trying to create a new connection should cause the pool to be stalled, and |
- // post a task asynchronously to try and close the session. |
- TestCompletionCallback callback2; |
- HostPortPair host_port2("2.com", 80); |
- scoped_refptr<TransportSocketParams> params2( |
- new TransportSocketParams( |
- host_port2, false, false, OnHostResolutionCallback(), |
- TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); |
- scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle); |
- EXPECT_EQ(ERR_IO_PENDING, |
- connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, |
- callback2.callback(), pool, BoundNetLog())); |
- EXPECT_TRUE(pool->IsStalled()); |
- |
- // The socket pool should close the connection asynchronously and establish a |
- // new connection. |
- EXPECT_EQ(OK, callback2.WaitForResult()); |
- EXPECT_FALSE(pool->IsStalled()); |
- EXPECT_TRUE(session1 == NULL); |
-} |
- |
-// Tests the case of a non-SPDY request closing an idle SPDY session when no |
-// pointers to the idle session are currently held, in the case the SPDY session |
-// has an alias. |
-TEST_P(SpdySessionTest, CloseOneIdleConnectionWithAlias) { |
- ClientSocketPoolManager::set_max_sockets_per_group( |
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
- ClientSocketPoolManager::set_max_sockets_per_pool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
- }; |
- StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- session_deps_.host_resolver->rules()->AddIPLiteralRule( |
- "1.com", "192.168.0.2", std::string()); |
- session_deps_.host_resolver->rules()->AddIPLiteralRule( |
- "2.com", "192.168.0.2", std::string()); |
- // Not strictly needed. |
- session_deps_.host_resolver->rules()->AddIPLiteralRule( |
- "3.com", "192.168.0.3", std::string()); |
- |
- CreateNetworkSession(); |
- |
- TransportClientSocketPool* pool = |
- http_session_->GetTransportSocketPool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL); |
- |
- // Create an idle SPDY session. |
- SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- base::WeakPtr<SpdySession> session1 = |
- CreateInsecureSpdySession(http_session_, key1, BoundNetLog()); |
- EXPECT_FALSE(pool->IsStalled()); |
- |
- // Set up an alias for the idle SPDY session, increasing its ref count to 2. |
- SpdySessionKey key2(HostPortPair("2.com", 80), ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- HostResolver::RequestInfo info(key2.host_port_pair()); |
- AddressList addresses; |
- // Pre-populate the DNS cache, since a synchronous resolution is required in |
- // order to create the alias. |
- session_deps_.host_resolver->Resolve(info, |
- DEFAULT_PRIORITY, |
- &addresses, |
- CompletionCallback(), |
- NULL, |
- BoundNetLog()); |
- // Get a session for |key2|, which should return the session created earlier. |
- base::WeakPtr<SpdySession> session2 = |
- spdy_session_pool_->FindAvailableSession(key2, BoundNetLog()); |
- ASSERT_EQ(session1.get(), session2.get()); |
- EXPECT_FALSE(pool->IsStalled()); |
- |
- // Trying to create a new connection should cause the pool to be stalled, and |
- // post a task asynchronously to try and close the session. |
- TestCompletionCallback callback3; |
- HostPortPair host_port3("3.com", 80); |
- scoped_refptr<TransportSocketParams> params3( |
- new TransportSocketParams( |
- host_port3, false, false, OnHostResolutionCallback(), |
- TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); |
- scoped_ptr<ClientSocketHandle> connection3(new ClientSocketHandle); |
- EXPECT_EQ(ERR_IO_PENDING, |
- connection3->Init(host_port3.ToString(), params3, DEFAULT_PRIORITY, |
- callback3.callback(), pool, BoundNetLog())); |
- EXPECT_TRUE(pool->IsStalled()); |
- |
- // The socket pool should close the connection asynchronously and establish a |
- // new connection. |
- EXPECT_EQ(OK, callback3.WaitForResult()); |
- EXPECT_FALSE(pool->IsStalled()); |
- EXPECT_TRUE(session1 == NULL); |
- EXPECT_TRUE(session2 == NULL); |
-} |
- |
-// Tests that when a SPDY session becomes idle, it closes itself if there is |
-// a lower layer pool stalled on the per-pool socket limit. |
-TEST_P(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) { |
- ClientSocketPoolManager::set_max_sockets_per_group( |
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
- ClientSocketPoolManager::set_max_sockets_per_pool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
- }; |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
- scoped_ptr<SpdyFrame> cancel1( |
- spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 1), |
- CreateMockWrite(*cancel1, 1), |
- }; |
- StaticSocketDataProvider data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- MockRead http_reads[] = { |
- MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
- }; |
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), |
- NULL, 0); |
- http_data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&http_data); |
- |
- |
- CreateNetworkSession(); |
- |
- TransportClientSocketPool* pool = |
- http_session_->GetTransportSocketPool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL); |
- |
- // Create a SPDY session. |
- GURL url1(kDefaultURL); |
- SpdySessionKey key1(HostPortPair(url1.host(), 80), |
- ProxyServer::Direct(), PRIVACY_MODE_DISABLED); |
- base::WeakPtr<SpdySession> session1 = |
- CreateInsecureSpdySession(http_session_, key1, BoundNetLog()); |
- EXPECT_FALSE(pool->IsStalled()); |
- |
- // Create a stream using the session, and send a request. |
- |
- TestCompletionCallback callback1; |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session1, url1, DEFAULT_PRIORITY, |
- BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- scoped_ptr<SpdyHeaderBlock> headers1( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- EXPECT_EQ(ERR_IO_PENDING, |
- spdy_stream1->SendRequestHeaders( |
- headers1.Pass(), NO_MORE_DATA_TO_SEND)); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- // Trying to create a new connection should cause the pool to be stalled, and |
- // post a task asynchronously to try and close the session. |
- TestCompletionCallback callback2; |
- HostPortPair host_port2("2.com", 80); |
- scoped_refptr<TransportSocketParams> params2( |
- new TransportSocketParams( |
- host_port2, false, false, OnHostResolutionCallback(), |
- TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); |
- scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle); |
- EXPECT_EQ(ERR_IO_PENDING, |
- connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, |
- callback2.callback(), pool, BoundNetLog())); |
- EXPECT_TRUE(pool->IsStalled()); |
- |
- // Running the message loop should cause the socket pool to ask the SPDY |
- // session to close an idle socket, but since the socket is in use, nothing |
- // happens. |
- base::RunLoop().RunUntilIdle(); |
- EXPECT_TRUE(pool->IsStalled()); |
- EXPECT_FALSE(callback2.have_result()); |
- |
- // Cancelling the request should result in the session's socket being |
- // closed, since the pool is stalled. |
- ASSERT_TRUE(spdy_stream1.get()); |
- spdy_stream1->Cancel(); |
- base::RunLoop().RunUntilIdle(); |
- ASSERT_FALSE(pool->IsStalled()); |
- EXPECT_EQ(OK, callback2.WaitForResult()); |
-} |
- |
-// Verify that SpdySessionKey and therefore SpdySession is different when |
-// privacy mode is enabled or disabled. |
-TEST_P(SpdySessionTest, SpdySessionKeyPrivacyMode) { |
- CreateDeterministicNetworkSession(); |
- |
- HostPortPair host_port_pair("www.google.com", 443); |
- SpdySessionKey key_privacy_enabled(host_port_pair, ProxyServer::Direct(), |
- PRIVACY_MODE_ENABLED); |
- SpdySessionKey key_privacy_disabled(host_port_pair, ProxyServer::Direct(), |
- PRIVACY_MODE_DISABLED); |
- |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled)); |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled)); |
- |
- // Add SpdySession with PrivacyMode Enabled to the pool. |
- base::WeakPtr<SpdySession> session_privacy_enabled = |
- CreateFakeSpdySession(spdy_session_pool_, key_privacy_enabled); |
- |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_enabled)); |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled)); |
- |
- // Add SpdySession with PrivacyMode Disabled to the pool. |
- base::WeakPtr<SpdySession> session_privacy_disabled = |
- CreateFakeSpdySession(spdy_session_pool_, key_privacy_disabled); |
- |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_enabled)); |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_disabled)); |
- |
- session_privacy_enabled->CloseSessionOnError(ERR_ABORTED, std::string()); |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled)); |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_disabled)); |
- |
- session_privacy_disabled->CloseSessionOnError(ERR_ABORTED, std::string()); |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled)); |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled)); |
-} |
- |
-// Delegate that creates another stream when its stream is closed. |
-class StreamCreatingDelegate : public test::StreamDelegateDoNothing { |
- public: |
- StreamCreatingDelegate(const base::WeakPtr<SpdyStream>& stream, |
- const base::WeakPtr<SpdySession>& session) |
- : StreamDelegateDoNothing(stream), |
- session_(session) {} |
- |
- ~StreamCreatingDelegate() override {} |
- |
- void OnClose(int status) override { |
- GURL url(kDefaultURL); |
- ignore_result( |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session_, url, MEDIUM, BoundNetLog())); |
- } |
- |
- private: |
- const base::WeakPtr<SpdySession> session_; |
-}; |
- |
-// Create another stream in response to a stream being reset. Nothing |
-// should blow up. This is a regression test for |
-// http://crbug.com/263690 . |
-TEST_P(SpdySessionTest, CreateStreamOnStreamReset) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), |
- }; |
- |
- scoped_ptr<SpdyFrame> rst( |
- spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM)); |
- MockRead reads[] = { |
- CreateMockRead(*rst, 1), |
- MockRead(ASYNC, 0, 2) // EOF |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream->stream_id()); |
- |
- StreamCreatingDelegate delegate(spdy_stream, session); |
- spdy_stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders()); |
- |
- EXPECT_EQ(0u, spdy_stream->stream_id()); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(1u, spdy_stream->stream_id()); |
- |
- // Cause the stream to be reset, which should cause another stream |
- // to be created. |
- data.RunFor(1); |
- |
- EXPECT_EQ(NULL, spdy_stream.get()); |
- EXPECT_TRUE(delegate.StreamIsClosed()); |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(1u, session->num_created_streams()); |
-} |
- |
-// The tests below are only for SPDY/3 and above. |
- |
-TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) { |
- // Set SETTINGS_INITIAL_WINDOW_SIZE to a small number so that WINDOW_UPDATE |
- // gets sent. |
- SettingsMap new_settings; |
- int32 window_size = 1; |
- new_settings[SETTINGS_INITIAL_WINDOW_SIZE] = |
- SettingsFlagsAndValue(SETTINGS_FLAG_NONE, window_size); |
- |
- // Set up the socket so we read a SETTINGS frame that sets |
- // INITIAL_WINDOW_SIZE. |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> settings_frame( |
- spdy_util_.ConstructSpdySettings(new_settings)); |
- MockRead reads[] = { |
- CreateMockRead(*settings_frame, 0), |
- MockRead(ASYNC, 0, 1) // EOF |
- }; |
- |
- scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); |
- MockWrite writes[] = { |
- CreateMockWrite(*settings_ack, 2), |
- }; |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, test_url_, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- TestCompletionCallback callback1; |
- EXPECT_NE(spdy_stream1->send_window_size(), window_size); |
- |
- data.RunFor(1); // Process the SETTINGS frame, but not the EOF |
- base::MessageLoop::current()->RunUntilIdle(); |
- EXPECT_EQ(session->stream_initial_send_window_size(), window_size); |
- EXPECT_EQ(spdy_stream1->send_window_size(), window_size); |
- |
- // Release the first one, this will allow the second to be created. |
- spdy_stream1->Cancel(); |
- EXPECT_EQ(NULL, spdy_stream1.get()); |
- |
- base::WeakPtr<SpdyStream> spdy_stream2 = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, test_url_, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream2.get() != NULL); |
- EXPECT_EQ(spdy_stream2->send_window_size(), window_size); |
- spdy_stream2->Cancel(); |
- EXPECT_EQ(NULL, spdy_stream2.get()); |
-} |
- |
-// The tests below are only for SPDY/3.1 and above. |
- |
-// SpdySession::{Increase,Decrease}RecvWindowSize should properly |
-// adjust the session receive window size for SPDY 3.1 and higher. In |
-// addition, SpdySession::IncreaseRecvWindowSize should trigger |
-// sending a WINDOW_UPDATE frame for a large enough delta. |
-TEST_P(SpdySessionTest, AdjustRecvWindowSize) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- const int32 initial_window_size = |
- SpdySession::GetInitialWindowSize(GetParam()); |
- const int32 delta_window_size = 100; |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 1) // EOF |
- }; |
- scoped_ptr<SpdyFrame> window_update(spdy_util_.ConstructSpdyWindowUpdate( |
- kSessionFlowControlStreamId, initial_window_size + delta_window_size)); |
- MockWrite writes[] = { |
- CreateMockWrite(*window_update, 0), |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
- session->flow_control_state()); |
- |
- EXPECT_EQ(initial_window_size, session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
- |
- session->IncreaseRecvWindowSize(delta_window_size); |
- EXPECT_EQ(initial_window_size + delta_window_size, |
- session->session_recv_window_size_); |
- EXPECT_EQ(delta_window_size, session->session_unacked_recv_window_bytes_); |
- |
- // Should trigger sending a WINDOW_UPDATE frame. |
- session->IncreaseRecvWindowSize(initial_window_size); |
- EXPECT_EQ(initial_window_size + delta_window_size + initial_window_size, |
- session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
- |
- data.RunFor(1); |
- |
- // DecreaseRecvWindowSize() expects |in_io_loop_| to be true. |
- session->in_io_loop_ = true; |
- session->DecreaseRecvWindowSize(initial_window_size + delta_window_size + |
- initial_window_size); |
- session->in_io_loop_ = false; |
- EXPECT_EQ(0, session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
-} |
- |
-// SpdySession::{Increase,Decrease}SendWindowSize should properly |
-// adjust the session send window size when the "enable_spdy_31" flag |
-// is set. |
-TEST_P(SpdySessionTest, AdjustSendWindowSize) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, 0, 0) // EOF |
- }; |
- StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateFakeSpdySession(spdy_session_pool_, key_); |
- EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
- session->flow_control_state()); |
- |
- const int32 initial_window_size = |
- SpdySession::GetInitialWindowSize(GetParam()); |
- const int32 delta_window_size = 100; |
- |
- EXPECT_EQ(initial_window_size, session->session_send_window_size_); |
- |
- session->IncreaseSendWindowSize(delta_window_size); |
- EXPECT_EQ(initial_window_size + delta_window_size, |
- session->session_send_window_size_); |
- |
- session->DecreaseSendWindowSize(delta_window_size); |
- EXPECT_EQ(initial_window_size, session->session_send_window_size_); |
-} |
- |
-// Incoming data for an inactive stream should not cause the session |
-// receive window size to decrease, but it should cause the unacked |
-// bytes to increase. |
-TEST_P(SpdySessionTest, SessionFlowControlInactiveStream) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyBodyFrame(1, false)); |
- MockRead reads[] = { |
- CreateMockRead(*resp, 0), |
- MockRead(ASYNC, 0, 1) // EOF |
- }; |
- DeterministicSocketData data(reads, arraysize(reads), NULL, 0); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
- session->flow_control_state()); |
- |
- EXPECT_EQ(SpdySession::GetInitialWindowSize(GetParam()), |
- session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(SpdySession::GetInitialWindowSize(GetParam()), |
- session->session_recv_window_size_); |
- EXPECT_EQ(kUploadDataSize, session->session_unacked_recv_window_bytes_); |
- |
- data.RunFor(1); |
-} |
- |
-// A delegate that drops any received data. |
-class DropReceivedDataDelegate : public test::StreamDelegateSendImmediate { |
- public: |
- DropReceivedDataDelegate(const base::WeakPtr<SpdyStream>& stream, |
- base::StringPiece data) |
- : StreamDelegateSendImmediate(stream, data) {} |
- |
- ~DropReceivedDataDelegate() override {} |
- |
- // Drop any received data. |
- void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) override {} |
-}; |
- |
-// Send data back and forth but use a delegate that drops its received |
-// data. The receive window should still increase to its original |
-// value, i.e. we shouldn't "leak" receive window bytes. |
-TEST_P(SpdySessionTest, SessionFlowControlNoReceiveLeaks) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- const char kStreamUrl[] = "http://www.google.com/"; |
- |
- const int32 msg_data_size = 100; |
- const std::string msg_data(msg_data_size, 'a'); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyPost( |
- kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0)); |
- scoped_ptr<SpdyFrame> msg( |
- spdy_util_.ConstructSpdyBodyFrame( |
- 1, msg_data.data(), msg_data_size, false)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), |
- CreateMockWrite(*msg, 2), |
- }; |
- |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- scoped_ptr<SpdyFrame> echo( |
- spdy_util_.ConstructSpdyBodyFrame( |
- 1, msg_data.data(), msg_data_size, false)); |
- scoped_ptr<SpdyFrame> window_update( |
- spdy_util_.ConstructSpdyWindowUpdate( |
- kSessionFlowControlStreamId, msg_data_size)); |
- MockRead reads[] = { |
- CreateMockRead(*resp, 1), |
- CreateMockRead(*echo, 3), |
- MockRead(ASYNC, 0, 4) // EOF |
- }; |
- |
- // Create SpdySession and SpdyStream and send the request. |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url(kStreamUrl); |
- base::WeakPtr<SpdyStream> stream = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(stream.get() != NULL); |
- EXPECT_EQ(0u, stream->stream_id()); |
- |
- DropReceivedDataDelegate delegate(stream, msg_data); |
- stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructPostHeaderBlock(url.spec(), msg_data_size)); |
- EXPECT_EQ(ERR_IO_PENDING, |
- stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); |
- EXPECT_TRUE(stream->HasUrlFromHeaders()); |
- |
- const int32 initial_window_size = |
- SpdySession::GetInitialWindowSize(GetParam()); |
- EXPECT_EQ(initial_window_size, session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
- |
- data.RunFor(4); |
- |
- EXPECT_TRUE(data.at_write_eof()); |
- EXPECT_TRUE(data.at_read_eof()); |
- |
- EXPECT_EQ(initial_window_size, session->session_recv_window_size_); |
- EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); |
- |
- stream->Close(); |
- EXPECT_EQ(NULL, stream.get()); |
- |
- EXPECT_EQ(OK, delegate.WaitForClose()); |
- |
- EXPECT_EQ(initial_window_size, session->session_recv_window_size_); |
- EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); |
-} |
- |
-// Send data back and forth but close the stream before its data frame |
-// can be written to the socket. The send window should then increase |
-// to its original value, i.e. we shouldn't "leak" send window bytes. |
-TEST_P(SpdySessionTest, SessionFlowControlNoSendLeaks) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- const char kStreamUrl[] = "http://www.google.com/"; |
- |
- const int32 msg_data_size = 100; |
- const std::string msg_data(msg_data_size, 'a'); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyPost( |
- kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), |
- }; |
- |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- MockRead reads[] = { |
- CreateMockRead(*resp, 1), |
- MockRead(ASYNC, 0, 2) // EOF |
- }; |
- |
- // Create SpdySession and SpdyStream and send the request. |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url(kStreamUrl); |
- base::WeakPtr<SpdyStream> stream = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(stream.get() != NULL); |
- EXPECT_EQ(0u, stream->stream_id()); |
- |
- test::StreamDelegateSendImmediate delegate(stream, msg_data); |
- stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructPostHeaderBlock(url.spec(), msg_data_size)); |
- EXPECT_EQ(ERR_IO_PENDING, |
- stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); |
- EXPECT_TRUE(stream->HasUrlFromHeaders()); |
- |
- const int32 initial_window_size = |
- SpdySession::GetInitialWindowSize(GetParam()); |
- EXPECT_EQ(initial_window_size, session->session_send_window_size_); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(initial_window_size, session->session_send_window_size_); |
- |
- data.RunFor(1); |
- |
- EXPECT_TRUE(data.at_write_eof()); |
- EXPECT_TRUE(data.at_read_eof()); |
- |
- EXPECT_EQ(initial_window_size - msg_data_size, |
- session->session_send_window_size_); |
- |
- // Closing the stream should increase the session's send window. |
- stream->Close(); |
- EXPECT_EQ(NULL, stream.get()); |
- |
- EXPECT_EQ(initial_window_size, session->session_send_window_size_); |
- |
- EXPECT_EQ(OK, delegate.WaitForClose()); |
-} |
- |
-// Send data back and forth; the send and receive windows should |
-// change appropriately. |
-TEST_P(SpdySessionTest, SessionFlowControlEndToEnd) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- const char kStreamUrl[] = "http://www.google.com/"; |
- |
- const int32 msg_data_size = 100; |
- const std::string msg_data(msg_data_size, 'a'); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyPost( |
- kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0)); |
- scoped_ptr<SpdyFrame> msg( |
- spdy_util_.ConstructSpdyBodyFrame( |
- 1, msg_data.data(), msg_data_size, false)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), |
- CreateMockWrite(*msg, 2), |
- }; |
- |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- scoped_ptr<SpdyFrame> echo( |
- spdy_util_.ConstructSpdyBodyFrame( |
- 1, msg_data.data(), msg_data_size, false)); |
- scoped_ptr<SpdyFrame> window_update( |
- spdy_util_.ConstructSpdyWindowUpdate( |
- kSessionFlowControlStreamId, msg_data_size)); |
- MockRead reads[] = { |
- CreateMockRead(*resp, 1), |
- CreateMockRead(*echo, 3), |
- CreateMockRead(*window_update, 4), |
- MockRead(ASYNC, 0, 5) // EOF |
- }; |
- |
- // Create SpdySession and SpdyStream and send the request. |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url(kStreamUrl); |
- base::WeakPtr<SpdyStream> stream = |
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(stream.get() != NULL); |
- EXPECT_EQ(0u, stream->stream_id()); |
- |
- test::StreamDelegateSendImmediate delegate(stream, msg_data); |
- stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructPostHeaderBlock(url.spec(), msg_data_size)); |
- EXPECT_EQ(ERR_IO_PENDING, |
- stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); |
- EXPECT_TRUE(stream->HasUrlFromHeaders()); |
- |
- const int32 initial_window_size = |
- SpdySession::GetInitialWindowSize(GetParam()); |
- EXPECT_EQ(initial_window_size, session->session_send_window_size_); |
- EXPECT_EQ(initial_window_size, session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(initial_window_size, session->session_send_window_size_); |
- EXPECT_EQ(initial_window_size, session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(initial_window_size - msg_data_size, |
- session->session_send_window_size_); |
- EXPECT_EQ(initial_window_size, session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(initial_window_size - msg_data_size, |
- session->session_send_window_size_); |
- EXPECT_EQ(initial_window_size, session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(initial_window_size - msg_data_size, |
- session->session_send_window_size_); |
- EXPECT_EQ(initial_window_size - msg_data_size, |
- session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
- |
- data.RunFor(1); |
- |
- EXPECT_EQ(initial_window_size, session->session_send_window_size_); |
- EXPECT_EQ(initial_window_size - msg_data_size, |
- session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
- |
- EXPECT_TRUE(data.at_write_eof()); |
- EXPECT_TRUE(data.at_read_eof()); |
- |
- EXPECT_EQ(msg_data, delegate.TakeReceivedData()); |
- |
- // Draining the delegate's read queue should increase the session's |
- // receive window. |
- EXPECT_EQ(initial_window_size, session->session_send_window_size_); |
- EXPECT_EQ(initial_window_size, session->session_recv_window_size_); |
- EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); |
- |
- stream->Close(); |
- EXPECT_EQ(NULL, stream.get()); |
- |
- EXPECT_EQ(OK, delegate.WaitForClose()); |
- |
- EXPECT_EQ(initial_window_size, session->session_send_window_size_); |
- EXPECT_EQ(initial_window_size, session->session_recv_window_size_); |
- EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); |
-} |
- |
-// Given a stall function and an unstall function, runs a test to make |
-// sure that a stream resumes after unstall. |
-void SpdySessionTest::RunResumeAfterUnstallTest( |
- const base::Callback<void(SpdySession*, SpdyStream*)>& stall_function, |
- const base::Callback<void(SpdySession*, SpdyStream*, int32)>& |
- unstall_function) { |
- const char kStreamUrl[] = "http://www.google.com/"; |
- GURL url(kStreamUrl); |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyPost( |
- kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0)); |
- scoped_ptr<SpdyFrame> body( |
- spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), |
- CreateMockWrite(*body, 1), |
- }; |
- |
- scoped_ptr<SpdyFrame> resp( |
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- scoped_ptr<SpdyFrame> echo( |
- spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false)); |
- MockRead reads[] = { |
- CreateMockRead(*resp, 2), |
- MockRead(ASYNC, 0, 0, 3), // EOF |
- }; |
- |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
- session->flow_control_state()); |
- |
- base::WeakPtr<SpdyStream> stream = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(stream.get() != NULL); |
- |
- test::StreamDelegateWithBody delegate(stream, kBodyDataStringPiece); |
- stream->SetDelegate(&delegate); |
- |
- EXPECT_FALSE(stream->HasUrlFromHeaders()); |
- EXPECT_FALSE(stream->send_stalled_by_flow_control()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
- EXPECT_EQ(ERR_IO_PENDING, |
- stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); |
- EXPECT_TRUE(stream->HasUrlFromHeaders()); |
- EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); |
- |
- stall_function.Run(session.get(), stream.get()); |
- |
- data.RunFor(1); |
- |
- EXPECT_TRUE(stream->send_stalled_by_flow_control()); |
- |
- unstall_function.Run(session.get(), stream.get(), kBodyDataSize); |
- |
- EXPECT_FALSE(stream->send_stalled_by_flow_control()); |
- |
- data.RunFor(3); |
- |
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); |
- |
- EXPECT_TRUE(delegate.send_headers_completed()); |
- EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status")); |
- EXPECT_EQ(std::string(), delegate.TakeReceivedData()); |
- EXPECT_TRUE(data.at_write_eof()); |
-} |
- |
-// Run the resume-after-unstall test with all possible stall and |
-// unstall sequences. |
- |
-TEST_P(SpdySessionTest, ResumeAfterUnstallSession) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- RunResumeAfterUnstallTest( |
- base::Bind(&SpdySessionTest::StallSessionOnly, |
- base::Unretained(this)), |
- base::Bind(&SpdySessionTest::UnstallSessionOnly, |
- base::Unretained(this))); |
-} |
- |
-// Equivalent to |
-// SpdyStreamTest.ResumeAfterSendWindowSizeIncrease. |
-TEST_P(SpdySessionTest, ResumeAfterUnstallStream) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- RunResumeAfterUnstallTest( |
- base::Bind(&SpdySessionTest::StallStreamOnly, |
- base::Unretained(this)), |
- base::Bind(&SpdySessionTest::UnstallStreamOnly, |
- base::Unretained(this))); |
-} |
- |
-TEST_P(SpdySessionTest, StallSessionStreamResumeAfterUnstallSessionStream) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- RunResumeAfterUnstallTest( |
- base::Bind(&SpdySessionTest::StallSessionStream, |
- base::Unretained(this)), |
- base::Bind(&SpdySessionTest::UnstallSessionStream, |
- base::Unretained(this))); |
-} |
- |
-TEST_P(SpdySessionTest, StallStreamSessionResumeAfterUnstallSessionStream) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- RunResumeAfterUnstallTest( |
- base::Bind(&SpdySessionTest::StallStreamSession, |
- base::Unretained(this)), |
- base::Bind(&SpdySessionTest::UnstallSessionStream, |
- base::Unretained(this))); |
-} |
- |
-TEST_P(SpdySessionTest, StallStreamSessionResumeAfterUnstallStreamSession) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- RunResumeAfterUnstallTest( |
- base::Bind(&SpdySessionTest::StallStreamSession, |
- base::Unretained(this)), |
- base::Bind(&SpdySessionTest::UnstallStreamSession, |
- base::Unretained(this))); |
-} |
- |
-TEST_P(SpdySessionTest, StallSessionStreamResumeAfterUnstallStreamSession) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- RunResumeAfterUnstallTest( |
- base::Bind(&SpdySessionTest::StallSessionStream, |
- base::Unretained(this)), |
- base::Bind(&SpdySessionTest::UnstallStreamSession, |
- base::Unretained(this))); |
-} |
- |
-// Cause a stall by reducing the flow control send window to 0. The |
-// streams should resume in priority order when that window is then |
-// increased. |
-TEST_P(SpdySessionTest, ResumeByPriorityAfterSendWindowSizeIncrease) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- const char kStreamUrl[] = "http://www.google.com/"; |
- GURL url(kStreamUrl); |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyPost( |
- kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0)); |
- scoped_ptr<SpdyFrame> req2( |
- spdy_util_.ConstructSpdyPost( |
- kStreamUrl, 3, kBodyDataSize, MEDIUM, NULL, 0)); |
- scoped_ptr<SpdyFrame> body1( |
- spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, true)); |
- scoped_ptr<SpdyFrame> body2( |
- spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- CreateMockWrite(*req2, 1), |
- CreateMockWrite(*body2, 2), |
- CreateMockWrite(*body1, 3), |
- }; |
- |
- scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); |
- MockRead reads[] = { |
- CreateMockRead(*resp1, 4), |
- CreateMockRead(*resp2, 5), |
- MockRead(ASYNC, 0, 0, 6), // EOF |
- }; |
- |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
- session->flow_control_state()); |
- |
- base::WeakPtr<SpdyStream> stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(stream1.get() != NULL); |
- |
- test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece); |
- stream1->SetDelegate(&delegate1); |
- |
- EXPECT_FALSE(stream1->HasUrlFromHeaders()); |
- |
- base::WeakPtr<SpdyStream> stream2 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, MEDIUM, BoundNetLog()); |
- ASSERT_TRUE(stream2.get() != NULL); |
- |
- test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece); |
- stream2->SetDelegate(&delegate2); |
- |
- EXPECT_FALSE(stream2->HasUrlFromHeaders()); |
- |
- EXPECT_FALSE(stream1->send_stalled_by_flow_control()); |
- EXPECT_FALSE(stream2->send_stalled_by_flow_control()); |
- |
- StallSessionSend(session.get()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers1( |
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
- EXPECT_EQ(ERR_IO_PENDING, |
- stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND)); |
- EXPECT_TRUE(stream1->HasUrlFromHeaders()); |
- EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec()); |
- |
- data.RunFor(1); |
- EXPECT_EQ(1u, stream1->stream_id()); |
- EXPECT_TRUE(stream1->send_stalled_by_flow_control()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers2( |
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
- EXPECT_EQ(ERR_IO_PENDING, |
- stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND)); |
- EXPECT_TRUE(stream2->HasUrlFromHeaders()); |
- EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec()); |
- |
- data.RunFor(1); |
- EXPECT_EQ(3u, stream2->stream_id()); |
- EXPECT_TRUE(stream2->send_stalled_by_flow_control()); |
- |
- // This should unstall only stream2. |
- UnstallSessionSend(session.get(), kBodyDataSize); |
- |
- EXPECT_TRUE(stream1->send_stalled_by_flow_control()); |
- EXPECT_FALSE(stream2->send_stalled_by_flow_control()); |
- |
- data.RunFor(1); |
- |
- EXPECT_TRUE(stream1->send_stalled_by_flow_control()); |
- EXPECT_FALSE(stream2->send_stalled_by_flow_control()); |
- |
- // This should then unstall stream1. |
- UnstallSessionSend(session.get(), kBodyDataSize); |
- |
- EXPECT_FALSE(stream1->send_stalled_by_flow_control()); |
- EXPECT_FALSE(stream2->send_stalled_by_flow_control()); |
- |
- data.RunFor(4); |
- |
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); |
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); |
- |
- EXPECT_TRUE(delegate1.send_headers_completed()); |
- EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status")); |
- EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); |
- |
- EXPECT_TRUE(delegate2.send_headers_completed()); |
- EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); |
- EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); |
- |
- EXPECT_TRUE(data.at_write_eof()); |
-} |
- |
-// Delegate that closes a given stream after sending its body. |
-class StreamClosingDelegate : public test::StreamDelegateWithBody { |
- public: |
- StreamClosingDelegate(const base::WeakPtr<SpdyStream>& stream, |
- base::StringPiece data) |
- : StreamDelegateWithBody(stream, data) {} |
- |
- ~StreamClosingDelegate() override {} |
- |
- void set_stream_to_close(const base::WeakPtr<SpdyStream>& stream_to_close) { |
- stream_to_close_ = stream_to_close; |
- } |
- |
- void OnDataSent() override { |
- test::StreamDelegateWithBody::OnDataSent(); |
- if (stream_to_close_.get()) { |
- stream_to_close_->Close(); |
- EXPECT_EQ(NULL, stream_to_close_.get()); |
- } |
- } |
- |
- private: |
- base::WeakPtr<SpdyStream> stream_to_close_; |
-}; |
- |
-// Cause a stall by reducing the flow control send window to |
-// 0. Unstalling the session should properly handle deleted streams. |
-TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- const char kStreamUrl[] = "http://www.google.com/"; |
- GURL url(kStreamUrl); |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyPost( |
- kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0)); |
- scoped_ptr<SpdyFrame> req2( |
- spdy_util_.ConstructSpdyPost( |
- kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0)); |
- scoped_ptr<SpdyFrame> req3( |
- spdy_util_.ConstructSpdyPost( |
- kStreamUrl, 5, kBodyDataSize, LOWEST, NULL, 0)); |
- scoped_ptr<SpdyFrame> body2( |
- spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- CreateMockWrite(*req2, 1), |
- CreateMockWrite(*req3, 2), |
- CreateMockWrite(*body2, 3), |
- }; |
- |
- scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); |
- MockRead reads[] = { |
- CreateMockRead(*resp2, 4), |
- MockRead(ASYNC, 0, 0, 5), // EOF |
- }; |
- |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
- session->flow_control_state()); |
- |
- base::WeakPtr<SpdyStream> stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(stream1.get() != NULL); |
- |
- test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece); |
- stream1->SetDelegate(&delegate1); |
- |
- EXPECT_FALSE(stream1->HasUrlFromHeaders()); |
- |
- base::WeakPtr<SpdyStream> stream2 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(stream2.get() != NULL); |
- |
- StreamClosingDelegate delegate2(stream2, kBodyDataStringPiece); |
- stream2->SetDelegate(&delegate2); |
- |
- EXPECT_FALSE(stream2->HasUrlFromHeaders()); |
- |
- base::WeakPtr<SpdyStream> stream3 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(stream3.get() != NULL); |
- |
- test::StreamDelegateWithBody delegate3(stream3, kBodyDataStringPiece); |
- stream3->SetDelegate(&delegate3); |
- |
- EXPECT_FALSE(stream3->HasUrlFromHeaders()); |
- |
- EXPECT_FALSE(stream1->send_stalled_by_flow_control()); |
- EXPECT_FALSE(stream2->send_stalled_by_flow_control()); |
- EXPECT_FALSE(stream3->send_stalled_by_flow_control()); |
- |
- StallSessionSend(session.get()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers1( |
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
- EXPECT_EQ(ERR_IO_PENDING, |
- stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND)); |
- EXPECT_TRUE(stream1->HasUrlFromHeaders()); |
- EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec()); |
- |
- data.RunFor(1); |
- EXPECT_EQ(1u, stream1->stream_id()); |
- EXPECT_TRUE(stream1->send_stalled_by_flow_control()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers2( |
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
- EXPECT_EQ(ERR_IO_PENDING, |
- stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND)); |
- EXPECT_TRUE(stream2->HasUrlFromHeaders()); |
- EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec()); |
- |
- data.RunFor(1); |
- EXPECT_EQ(3u, stream2->stream_id()); |
- EXPECT_TRUE(stream2->send_stalled_by_flow_control()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers3( |
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
- EXPECT_EQ(ERR_IO_PENDING, |
- stream3->SendRequestHeaders(headers3.Pass(), MORE_DATA_TO_SEND)); |
- EXPECT_TRUE(stream3->HasUrlFromHeaders()); |
- EXPECT_EQ(kStreamUrl, stream3->GetUrlFromHeaders().spec()); |
- |
- data.RunFor(1); |
- EXPECT_EQ(5u, stream3->stream_id()); |
- EXPECT_TRUE(stream3->send_stalled_by_flow_control()); |
- |
- SpdyStreamId stream_id1 = stream1->stream_id(); |
- SpdyStreamId stream_id2 = stream2->stream_id(); |
- SpdyStreamId stream_id3 = stream3->stream_id(); |
- |
- // Close stream1 preemptively. |
- session->CloseActiveStream(stream_id1, ERR_CONNECTION_CLOSED); |
- EXPECT_EQ(NULL, stream1.get()); |
- |
- EXPECT_FALSE(session->IsStreamActive(stream_id1)); |
- EXPECT_TRUE(session->IsStreamActive(stream_id2)); |
- EXPECT_TRUE(session->IsStreamActive(stream_id3)); |
- |
- // Unstall stream2, which should then close stream3. |
- delegate2.set_stream_to_close(stream3); |
- UnstallSessionSend(session.get(), kBodyDataSize); |
- |
- data.RunFor(1); |
- EXPECT_EQ(NULL, stream3.get()); |
- |
- EXPECT_FALSE(stream2->send_stalled_by_flow_control()); |
- EXPECT_FALSE(session->IsStreamActive(stream_id1)); |
- EXPECT_TRUE(session->IsStreamActive(stream_id2)); |
- EXPECT_FALSE(session->IsStreamActive(stream_id3)); |
- |
- data.RunFor(2); |
- EXPECT_EQ(NULL, stream2.get()); |
- |
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); |
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); |
- EXPECT_EQ(OK, delegate3.WaitForClose()); |
- |
- EXPECT_TRUE(delegate1.send_headers_completed()); |
- EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); |
- |
- EXPECT_TRUE(delegate2.send_headers_completed()); |
- EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); |
- EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); |
- |
- EXPECT_TRUE(delegate3.send_headers_completed()); |
- EXPECT_EQ(std::string(), delegate3.TakeReceivedData()); |
- |
- EXPECT_TRUE(data.at_write_eof()); |
-} |
- |
-// Cause a stall by reducing the flow control send window to |
-// 0. Unstalling the session should properly handle the session itself |
-// being closed. |
-TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- const char kStreamUrl[] = "http://www.google.com/"; |
- GURL url(kStreamUrl); |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- scoped_ptr<SpdyFrame> req1( |
- spdy_util_.ConstructSpdyPost( |
- kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0)); |
- scoped_ptr<SpdyFrame> req2( |
- spdy_util_.ConstructSpdyPost( |
- kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0)); |
- scoped_ptr<SpdyFrame> body1( |
- spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req1, 0), |
- CreateMockWrite(*req2, 1), |
- }; |
- |
- MockRead reads[] = { |
- MockRead(ASYNC, 0, 0, 2), // EOF |
- }; |
- |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
- session->flow_control_state()); |
- |
- base::WeakPtr<SpdyStream> stream1 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(stream1.get() != NULL); |
- |
- test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece); |
- stream1->SetDelegate(&delegate1); |
- |
- EXPECT_FALSE(stream1->HasUrlFromHeaders()); |
- |
- base::WeakPtr<SpdyStream> stream2 = |
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session, url, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(stream2.get() != NULL); |
- |
- test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece); |
- stream2->SetDelegate(&delegate2); |
- |
- EXPECT_FALSE(stream2->HasUrlFromHeaders()); |
- |
- EXPECT_FALSE(stream1->send_stalled_by_flow_control()); |
- EXPECT_FALSE(stream2->send_stalled_by_flow_control()); |
- |
- StallSessionSend(session.get()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers1( |
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
- EXPECT_EQ(ERR_IO_PENDING, |
- stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND)); |
- EXPECT_TRUE(stream1->HasUrlFromHeaders()); |
- EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec()); |
- |
- data.RunFor(1); |
- EXPECT_EQ(1u, stream1->stream_id()); |
- EXPECT_TRUE(stream1->send_stalled_by_flow_control()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers2( |
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
- EXPECT_EQ(ERR_IO_PENDING, |
- stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND)); |
- EXPECT_TRUE(stream2->HasUrlFromHeaders()); |
- EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec()); |
- |
- data.RunFor(1); |
- EXPECT_EQ(3u, stream2->stream_id()); |
- EXPECT_TRUE(stream2->send_stalled_by_flow_control()); |
- |
- EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- // Unstall stream1. |
- UnstallSessionSend(session.get(), kBodyDataSize); |
- |
- // Close the session (since we can't do it from within the delegate |
- // method, since it's in the stream's loop). |
- session->CloseSessionOnError(ERR_CONNECTION_CLOSED, "Closing session"); |
- base::RunLoop().RunUntilIdle(); |
- EXPECT_TRUE(session == NULL); |
- |
- EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); |
- |
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); |
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); |
- |
- EXPECT_TRUE(delegate1.send_headers_completed()); |
- EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); |
- |
- EXPECT_TRUE(delegate2.send_headers_completed()); |
- EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); |
- |
- EXPECT_TRUE(data.at_write_eof()); |
-} |
- |
-TEST_P(SpdySessionTest, GoAwayOnSessionFlowControlError) { |
- if (GetParam() < kProtoSPDY31) |
- return; |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
- scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway( |
- 0, |
- GOAWAY_FLOW_CONTROL_ERROR, |
- "delta_window_size is 6 in DecreaseRecvWindowSize, which is larger than " |
- "the receive window size of 1")); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 3), |
- }; |
- |
- scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
- scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
- MockRead reads[] = { |
- CreateMockRead(*resp, 1), CreateMockRead(*body, 2), |
- }; |
- |
- DeterministicSocketData data( |
- reads, arraysize(reads), writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream.get() != NULL); |
- test::StreamDelegateDoNothing delegate(spdy_stream); |
- spdy_stream->SetDelegate(&delegate); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url.spec())); |
- spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- |
- data.RunFor(1); // Write request. |
- |
- // Put session on the edge of overflowing it's recv window. |
- session->session_recv_window_size_ = 1; |
- |
- // Read response headers & body. Body overflows the session window, and a |
- // goaway is written. |
- data.RunFor(3); |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- EXPECT_EQ(ERR_SPDY_FLOW_CONTROL_ERROR, delegate.WaitForClose()); |
- EXPECT_TRUE(session == NULL); |
-} |
- |
-TEST_P(SpdySessionTest, SplitHeaders) { |
- GURL kStreamUrl("http://www.google.com/foo.dat"); |
- SpdyHeaderBlock headers; |
- spdy_util_.AddUrlToHeaderBlock(kStreamUrl.spec(), &headers); |
- headers["alpha"] = "beta"; |
- |
- SpdyHeaderBlock request_headers; |
- SpdyHeaderBlock response_headers; |
- |
- SplitPushedHeadersToRequestAndResponse( |
- headers, spdy_util_.spdy_version(), &request_headers, &response_headers); |
- |
- SpdyHeaderBlock::const_iterator it = response_headers.find("alpha"); |
- std::string alpha_val = |
- (it == response_headers.end()) ? std::string() : it->second; |
- EXPECT_EQ("beta", alpha_val); |
- |
- GURL request_url = |
- GetUrlFromHeaderBlock(request_headers, spdy_util_.spdy_version(), true); |
- EXPECT_EQ(kStreamUrl, request_url); |
-} |
- |
-// Regression. Sorta. Push streams and client streams were sharing a single |
-// limit for a long time. |
-TEST_P(SpdySessionTest, PushedStreamShouldNotCountToClientConcurrencyLimit) { |
- SettingsMap new_settings; |
- new_settings[SETTINGS_MAX_CONCURRENT_STREAMS] = |
- SettingsFlagsAndValue(SETTINGS_FLAG_NONE, 2); |
- scoped_ptr<SpdyFrame> settings_frame( |
- spdy_util_.ConstructSpdySettings(new_settings)); |
- scoped_ptr<SpdyFrame> pushed(spdy_util_.ConstructSpdyPush( |
- NULL, 0, 2, 1, "http://www.google.com/a.dat")); |
- MockRead reads[] = { |
- CreateMockRead(*settings_frame), CreateMockRead(*pushed, 3), |
- MockRead(ASYNC, 0, 4), |
- }; |
- |
- scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
- MockWrite writes[] = { |
- CreateMockWrite(*settings_ack, 1), CreateMockWrite(*req, 2), |
- }; |
- |
- DeterministicSocketData data( |
- reads, arraysize(reads), writes, arraysize(writes)); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- // Read the settings frame. |
- data.RunFor(1); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url1, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(1u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->num_pushed_streams()); |
- EXPECT_EQ(0u, session->num_active_pushed_streams()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- // Run until 1st stream is activated. |
- EXPECT_EQ(0u, delegate1.stream_id()); |
- data.RunFor(2); |
- EXPECT_EQ(1u, delegate1.stream_id()); |
- EXPECT_EQ(1u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->num_pushed_streams()); |
- EXPECT_EQ(0u, session->num_active_pushed_streams()); |
- |
- // Run until pushed stream is created. |
- data.RunFor(1); |
- EXPECT_EQ(2u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->num_pushed_streams()); |
- EXPECT_EQ(1u, session->num_active_pushed_streams()); |
- |
- // Second stream should not be stalled, although we have 2 active streams, but |
- // one of them is push stream and should not be taken into account when we |
- // create streams on the client. |
- base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url1, LOWEST, BoundNetLog()); |
- EXPECT_TRUE(spdy_stream2.get() != NULL); |
- EXPECT_EQ(2u, session->num_active_streams()); |
- EXPECT_EQ(1u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->num_pushed_streams()); |
- EXPECT_EQ(1u, session->num_active_pushed_streams()); |
- |
- // Read EOF. |
- data.RunFor(1); |
-} |
- |
-TEST_P(SpdySessionTest, RejectPushedStreamExceedingConcurrencyLimit) { |
- scoped_ptr<SpdyFrame> push_a(spdy_util_.ConstructSpdyPush( |
- NULL, 0, 2, 1, "http://www.google.com/a.dat")); |
- scoped_ptr<SpdyFrame> push_b(spdy_util_.ConstructSpdyPush( |
- NULL, 0, 4, 1, "http://www.google.com/b.dat")); |
- MockRead reads[] = { |
- CreateMockRead(*push_a, 1), CreateMockRead(*push_b, 2), |
- MockRead(ASYNC, 0, 4), |
- }; |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
- scoped_ptr<SpdyFrame> rst( |
- spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_REFUSED_STREAM)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 3), |
- }; |
- |
- DeterministicSocketData data( |
- reads, arraysize(reads), writes, arraysize(writes)); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- session->set_max_concurrent_pushed_streams(1); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url1, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(1u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->num_pushed_streams()); |
- EXPECT_EQ(0u, session->num_active_pushed_streams()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- // Run until 1st stream is activated. |
- EXPECT_EQ(0u, delegate1.stream_id()); |
- data.RunFor(1); |
- EXPECT_EQ(1u, delegate1.stream_id()); |
- EXPECT_EQ(1u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->num_pushed_streams()); |
- EXPECT_EQ(0u, session->num_active_pushed_streams()); |
- |
- // Run until pushed stream is created. |
- data.RunFor(1); |
- EXPECT_EQ(2u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->num_pushed_streams()); |
- EXPECT_EQ(1u, session->num_active_pushed_streams()); |
- |
- // Reset incoming pushed stream. |
- data.RunFor(2); |
- EXPECT_EQ(2u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->num_pushed_streams()); |
- EXPECT_EQ(1u, session->num_active_pushed_streams()); |
- |
- // Read EOF. |
- data.RunFor(1); |
-} |
- |
-TEST_P(SpdySessionTest, IgnoreReservedRemoteStreamsCount) { |
- // Streams in reserved remote state exist only in SPDY4. |
- if (spdy_util_.spdy_version() < SPDY4) |
- return; |
- |
- scoped_ptr<SpdyFrame> push_a(spdy_util_.ConstructSpdyPush( |
- NULL, 0, 2, 1, "http://www.google.com/a.dat")); |
- scoped_ptr<SpdyHeaderBlock> push_headers(new SpdyHeaderBlock); |
- spdy_util_.AddUrlToHeaderBlock("http://www.google.com/b.dat", |
- push_headers.get()); |
- scoped_ptr<SpdyFrame> push_b( |
- spdy_util_.ConstructInitialSpdyPushFrame(push_headers.Pass(), 4, 1)); |
- scoped_ptr<SpdyFrame> headers_b( |
- spdy_util_.ConstructSpdyPushHeaders(4, NULL, 0)); |
- MockRead reads[] = { |
- CreateMockRead(*push_a, 1), CreateMockRead(*push_b, 2), |
- CreateMockRead(*headers_b, 3), MockRead(ASYNC, 0, 5), |
- }; |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
- scoped_ptr<SpdyFrame> rst( |
- spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_REFUSED_STREAM)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4), |
- }; |
- |
- DeterministicSocketData data( |
- reads, arraysize(reads), writes, arraysize(writes)); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- session->set_max_concurrent_pushed_streams(1); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url1, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(1u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->num_pushed_streams()); |
- EXPECT_EQ(0u, session->num_active_pushed_streams()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- // Run until 1st stream is activated. |
- EXPECT_EQ(0u, delegate1.stream_id()); |
- data.RunFor(1); |
- EXPECT_EQ(1u, delegate1.stream_id()); |
- EXPECT_EQ(1u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->num_pushed_streams()); |
- EXPECT_EQ(0u, session->num_active_pushed_streams()); |
- |
- // Run until pushed stream is created. |
- data.RunFor(1); |
- EXPECT_EQ(2u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->num_pushed_streams()); |
- EXPECT_EQ(1u, session->num_active_pushed_streams()); |
- |
- // Accept promised stream. It should not count towards pushed stream limit. |
- data.RunFor(1); |
- EXPECT_EQ(3u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(2u, session->num_pushed_streams()); |
- EXPECT_EQ(1u, session->num_active_pushed_streams()); |
- |
- // Reset last pushed stream upon headers reception as it is going to be 2nd, |
- // while we accept only one. |
- data.RunFor(2); |
- EXPECT_EQ(2u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->num_pushed_streams()); |
- EXPECT_EQ(1u, session->num_active_pushed_streams()); |
- |
- // Read EOF. |
- data.RunFor(1); |
-} |
- |
-TEST_P(SpdySessionTest, CancelReservedStreamOnHeadersReceived) { |
- // Streams in reserved remote state exist only in SPDY4. |
- if (spdy_util_.spdy_version() < SPDY4) |
- return; |
- |
- const char kPushedUrl[] = "http://www.google.com/a.dat"; |
- scoped_ptr<SpdyHeaderBlock> push_headers(new SpdyHeaderBlock); |
- spdy_util_.AddUrlToHeaderBlock(kPushedUrl, push_headers.get()); |
- scoped_ptr<SpdyFrame> push_promise( |
- spdy_util_.ConstructInitialSpdyPushFrame(push_headers.Pass(), 2, 1)); |
- scoped_ptr<SpdyFrame> headers_frame( |
- spdy_util_.ConstructSpdyPushHeaders(2, NULL, 0)); |
- MockRead reads[] = { |
- CreateMockRead(*push_promise, 1), CreateMockRead(*headers_frame, 2), |
- MockRead(ASYNC, 0, 4), |
- }; |
- |
- scoped_ptr<SpdyFrame> req( |
- spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
- scoped_ptr<SpdyFrame> rst( |
- spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL)); |
- MockWrite writes[] = { |
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 3), |
- }; |
- |
- DeterministicSocketData data( |
- reads, arraysize(reads), writes, arraysize(writes)); |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- |
- CreateDeterministicNetworkSession(); |
- |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- GURL url1(kDefaultURL); |
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously( |
- SPDY_REQUEST_RESPONSE_STREAM, session, url1, LOWEST, BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get() != NULL); |
- EXPECT_EQ(0u, spdy_stream1->stream_id()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
- |
- EXPECT_EQ(0u, session->num_active_streams()); |
- EXPECT_EQ(1u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->num_pushed_streams()); |
- EXPECT_EQ(0u, session->num_active_pushed_streams()); |
- |
- scoped_ptr<SpdyHeaderBlock> headers( |
- spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
- spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders()); |
- |
- // Run until 1st stream is activated. |
- EXPECT_EQ(0u, delegate1.stream_id()); |
- data.RunFor(1); |
- EXPECT_EQ(1u, delegate1.stream_id()); |
- EXPECT_EQ(1u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->num_pushed_streams()); |
- EXPECT_EQ(0u, session->num_active_pushed_streams()); |
- |
- // Run until pushed stream is created. |
- data.RunFor(1); |
- EXPECT_EQ(2u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(1u, session->num_pushed_streams()); |
- EXPECT_EQ(0u, session->num_active_pushed_streams()); |
- |
- base::WeakPtr<SpdyStream> pushed_stream; |
- int rv = |
- session->GetPushStream(GURL(kPushedUrl), &pushed_stream, BoundNetLog()); |
- ASSERT_EQ(OK, rv); |
- ASSERT_TRUE(pushed_stream.get() != NULL); |
- test::StreamDelegateCloseOnHeaders delegate2(pushed_stream); |
- pushed_stream->SetDelegate(&delegate2); |
- |
- // Receive headers for pushed stream. Delegate will cancel the stream, ensure |
- // that all our counters are in consistent state. |
- data.RunFor(1); |
- EXPECT_EQ(1u, session->num_active_streams()); |
- EXPECT_EQ(0u, session->num_created_streams()); |
- EXPECT_EQ(0u, session->num_pushed_streams()); |
- EXPECT_EQ(0u, session->num_active_pushed_streams()); |
- |
- // Read EOF. |
- data.RunFor(2); |
-} |
- |
-TEST_P(SpdySessionTest, RejectInvalidUnknownFrames) { |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
- }; |
- |
- StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- CreateNetworkSession(); |
- base::WeakPtr<SpdySession> session = |
- CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); |
- |
- session->stream_hi_water_mark_ = 5; |
- // Low client (odd) ids are fine. |
- EXPECT_TRUE(session->OnUnknownFrame(3, 0)); |
- // Client id exceeding watermark. |
- EXPECT_FALSE(session->OnUnknownFrame(9, 0)); |
- |
- session->last_accepted_push_stream_id_ = 6; |
- // Low server (even) ids are fine. |
- EXPECT_TRUE(session->OnUnknownFrame(2, 0)); |
- // Server id exceeding last accepted id. |
- EXPECT_FALSE(session->OnUnknownFrame(8, 0)); |
-} |
- |
-TEST(MapFramerErrorToProtocolError, MapsValues) { |
- CHECK_EQ( |
- SPDY_ERROR_INVALID_CONTROL_FRAME, |
- MapFramerErrorToProtocolError(SpdyFramer::SPDY_INVALID_CONTROL_FRAME)); |
- CHECK_EQ( |
- SPDY_ERROR_INVALID_DATA_FRAME_FLAGS, |
- MapFramerErrorToProtocolError(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS)); |
- CHECK_EQ( |
- SPDY_ERROR_GOAWAY_FRAME_CORRUPT, |
- MapFramerErrorToProtocolError(SpdyFramer::SPDY_GOAWAY_FRAME_CORRUPT)); |
- CHECK_EQ(SPDY_ERROR_UNEXPECTED_FRAME, |
- MapFramerErrorToProtocolError(SpdyFramer::SPDY_UNEXPECTED_FRAME)); |
-} |
- |
-TEST(MapFramerErrorToNetError, MapsValue) { |
- CHECK_EQ(ERR_SPDY_PROTOCOL_ERROR, |
- MapFramerErrorToNetError(SpdyFramer::SPDY_INVALID_CONTROL_FRAME)); |
- CHECK_EQ(ERR_SPDY_COMPRESSION_ERROR, |
- MapFramerErrorToNetError(SpdyFramer::SPDY_COMPRESS_FAILURE)); |
- CHECK_EQ(ERR_SPDY_COMPRESSION_ERROR, |
- MapFramerErrorToNetError(SpdyFramer::SPDY_DECOMPRESS_FAILURE)); |
- CHECK_EQ( |
- ERR_SPDY_FRAME_SIZE_ERROR, |
- MapFramerErrorToNetError(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE)); |
-} |
- |
-TEST(MapRstStreamStatusToProtocolError, MapsValues) { |
- CHECK_EQ(STATUS_CODE_PROTOCOL_ERROR, |
- MapRstStreamStatusToProtocolError(RST_STREAM_PROTOCOL_ERROR)); |
- CHECK_EQ(STATUS_CODE_FRAME_SIZE_ERROR, |
- MapRstStreamStatusToProtocolError(RST_STREAM_FRAME_SIZE_ERROR)); |
- CHECK_EQ(STATUS_CODE_ENHANCE_YOUR_CALM, |
- MapRstStreamStatusToProtocolError(RST_STREAM_ENHANCE_YOUR_CALM)); |
- CHECK_EQ(STATUS_CODE_INADEQUATE_SECURITY, |
- MapRstStreamStatusToProtocolError(RST_STREAM_INADEQUATE_SECURITY)); |
- CHECK_EQ(STATUS_CODE_HTTP_1_1_REQUIRED, |
- MapRstStreamStatusToProtocolError(RST_STREAM_HTTP_1_1_REQUIRED)); |
-} |
- |
-TEST(MapNetErrorToGoAwayStatus, MapsValue) { |
- CHECK_EQ(GOAWAY_INADEQUATE_SECURITY, |
- MapNetErrorToGoAwayStatus(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY)); |
- CHECK_EQ(GOAWAY_FLOW_CONTROL_ERROR, |
- MapNetErrorToGoAwayStatus(ERR_SPDY_FLOW_CONTROL_ERROR)); |
- CHECK_EQ(GOAWAY_PROTOCOL_ERROR, |
- MapNetErrorToGoAwayStatus(ERR_SPDY_PROTOCOL_ERROR)); |
- CHECK_EQ(GOAWAY_COMPRESSION_ERROR, |
- MapNetErrorToGoAwayStatus(ERR_SPDY_COMPRESSION_ERROR)); |
- CHECK_EQ(GOAWAY_FRAME_SIZE_ERROR, |
- MapNetErrorToGoAwayStatus(ERR_SPDY_FRAME_SIZE_ERROR)); |
- CHECK_EQ(GOAWAY_PROTOCOL_ERROR, MapNetErrorToGoAwayStatus(ERR_UNEXPECTED)); |
-} |
- |
-TEST(CanPoolTest, CanPool) { |
- // Load a cert that is valid for: |
- // www.example.org |
- // mail.example.org |
- // www.example.com |
- |
- TransportSecurityState tss; |
- SSLInfo ssl_info; |
- ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), |
- "spdy_pooling.pem"); |
- |
- EXPECT_TRUE(SpdySession::CanPool( |
- &tss, ssl_info, "www.example.org", "www.example.org")); |
- EXPECT_TRUE(SpdySession::CanPool( |
- &tss, ssl_info, "www.example.org", "mail.example.org")); |
- EXPECT_TRUE(SpdySession::CanPool( |
- &tss, ssl_info, "www.example.org", "mail.example.com")); |
- EXPECT_FALSE(SpdySession::CanPool( |
- &tss, ssl_info, "www.example.org", "mail.google.com")); |
-} |
- |
-TEST(CanPoolTest, CanNotPoolWithCertErrors) { |
- // Load a cert that is valid for: |
- // www.example.org |
- // mail.example.org |
- // www.example.com |
- |
- TransportSecurityState tss; |
- SSLInfo ssl_info; |
- ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), |
- "spdy_pooling.pem"); |
- ssl_info.cert_status = CERT_STATUS_REVOKED; |
- |
- EXPECT_FALSE(SpdySession::CanPool( |
- &tss, ssl_info, "www.example.org", "mail.example.org")); |
-} |
- |
-TEST(CanPoolTest, CanNotPoolWithClientCerts) { |
- // Load a cert that is valid for: |
- // www.example.org |
- // mail.example.org |
- // www.example.com |
- |
- TransportSecurityState tss; |
- SSLInfo ssl_info; |
- ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), |
- "spdy_pooling.pem"); |
- ssl_info.client_cert_sent = true; |
- |
- EXPECT_FALSE(SpdySession::CanPool( |
- &tss, ssl_info, "www.example.org", "mail.example.org")); |
-} |
- |
-TEST(CanPoolTest, CanNotPoolAcrossETLDsWithChannelID) { |
- // Load a cert that is valid for: |
- // www.example.org |
- // mail.example.org |
- // www.example.com |
- |
- TransportSecurityState tss; |
- SSLInfo ssl_info; |
- ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), |
- "spdy_pooling.pem"); |
- ssl_info.channel_id_sent = true; |
- |
- EXPECT_TRUE(SpdySession::CanPool( |
- &tss, ssl_info, "www.example.org", "mail.example.org")); |
- EXPECT_FALSE(SpdySession::CanPool( |
- &tss, ssl_info, "www.example.org", "www.example.com")); |
-} |
- |
-TEST(CanPoolTest, CanNotPoolWithBadPins) { |
- uint8 primary_pin = 1; |
- uint8 backup_pin = 2; |
- uint8 bad_pin = 3; |
- TransportSecurityState tss; |
- test::AddPin(&tss, "mail.example.org", primary_pin, backup_pin); |
- |
- SSLInfo ssl_info; |
- ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), |
- "spdy_pooling.pem"); |
- ssl_info.is_issued_by_known_root = true; |
- ssl_info.public_key_hashes.push_back(test::GetTestHashValue(bad_pin)); |
- |
- EXPECT_FALSE(SpdySession::CanPool( |
- &tss, ssl_info, "www.example.org", "mail.example.org")); |
-} |
- |
-TEST(CanPoolTest, CanPoolWithAcceptablePins) { |
- uint8 primary_pin = 1; |
- uint8 backup_pin = 2; |
- TransportSecurityState tss; |
- test::AddPin(&tss, "mail.example.org", primary_pin, backup_pin); |
- |
- SSLInfo ssl_info; |
- ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), |
- "spdy_pooling.pem"); |
- ssl_info.is_issued_by_known_root = true; |
- ssl_info.public_key_hashes.push_back(test::GetTestHashValue(primary_pin)); |
- |
- EXPECT_TRUE(SpdySession::CanPool( |
- &tss, ssl_info, "www.example.org", "mail.example.org")); |
-} |
- |
-} // namespace net |