diff options
Diffstat (limited to 'chromium/net/spdy/spdy_session_unittest.cc')
-rw-r--r-- | chromium/net/spdy/spdy_session_unittest.cc | 957 |
1 files changed, 705 insertions, 252 deletions
diff --git a/chromium/net/spdy/spdy_session_unittest.cc b/chromium/net/spdy/spdy_session_unittest.cc index 2f185c7c01a..7145fc81027 100644 --- a/chromium/net/spdy/spdy_session_unittest.cc +++ b/chromium/net/spdy/spdy_session_unittest.cc @@ -107,7 +107,7 @@ class SpdySessionTest : public PlatformTest, test_url_(kTestUrl), test_host_port_pair_(kTestHost, kTestPort), key_(test_host_port_pair_, ProxyServer::Direct(), - kPrivacyModeDisabled) { + PRIVACY_MODE_DISABLED) { } virtual ~SpdySessionTest() { @@ -182,16 +182,19 @@ INSTANTIATE_TEST_CASE_P( NextProto, SpdySessionTest, testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2, - kProtoHTTP2Draft04)); + kProtoSPDY3, kProtoSPDY31, kProtoSPDY4)); // Try to create a SPDY session that will fail during // initialization. Nothing should blow up. TEST_P(SpdySessionTest, InitialReadError) { CreateDeterministicNetworkSession(); - TryCreateFakeSpdySessionExpectingFailure( - spdy_session_pool_, key_, ERR_FAILED); + 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 { @@ -238,9 +241,6 @@ TEST_P(SpdySessionTest, PendingStreamCancellingAnother) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -280,12 +280,9 @@ TEST_P(SpdySessionTest, PendingStreamCancellingAnother) { session->CloseSessionOnError(ERR_ABORTED, "Aborting session"); EXPECT_EQ(ERR_ABORTED, callback1.WaitForResult()); - - data.RunFor(1); } -// A session receiving a GOAWAY frame with no active streams should -// immediately close. +// A session receiving a GOAWAY frame with no active streams should close. TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) { session_deps_.host_resolver->set_synchronous_mode(true); @@ -298,9 +295,6 @@ TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -312,9 +306,8 @@ TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) { // Read and process the GOAWAY frame. data.RunFor(1); - EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_)); - + base::RunLoop().RunUntilIdle(); EXPECT_TRUE(session == NULL); } @@ -332,16 +325,16 @@ TEST_P(SpdySessionTest, GoAwayImmediatelyWithNoActiveStreams) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); data.StopAfter(1); - TryCreateInsecureSpdySessionExpectingFailure( - http_session_, key_, ERR_CONNECTION_CLOSED, BoundNetLog()); + 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_)); } @@ -369,9 +362,6 @@ TEST_P(SpdySessionTest, GoAwayWithActiveStreams) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -379,7 +369,7 @@ TEST_P(SpdySessionTest, GoAwayWithActiveStreams) { EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion()); - GURL url("http://www.google.com"); + GURL url(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); @@ -417,12 +407,13 @@ TEST_P(SpdySessionTest, GoAwayWithActiveStreams) { EXPECT_EQ(NULL, spdy_stream2.get()); EXPECT_TRUE(session->IsStreamActive(1)); - EXPECT_FALSE(session->IsClosed()); + 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); } @@ -453,9 +444,6 @@ TEST_P(SpdySessionTest, GoAwayTwice) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -463,7 +451,7 @@ TEST_P(SpdySessionTest, GoAwayTwice) { EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion()); - GURL url("http://www.google.com"); + GURL url(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); @@ -500,13 +488,12 @@ TEST_P(SpdySessionTest, GoAwayTwice) { EXPECT_FALSE(session->IsStreamActive(3)); EXPECT_EQ(NULL, spdy_stream2.get()); EXPECT_TRUE(session->IsStreamActive(1)); - - EXPECT_FALSE(session->IsClosed()); + 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); } @@ -535,9 +522,6 @@ TEST_P(SpdySessionTest, GoAwayWithActiveStreamsThenClose) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -545,7 +529,7 @@ TEST_P(SpdySessionTest, GoAwayWithActiveStreamsThenClose) { EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion()); - GURL url("http://www.google.com"); + GURL url(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); @@ -582,19 +566,85 @@ TEST_P(SpdySessionTest, GoAwayWithActiveStreamsThenClose) { EXPECT_FALSE(session->IsStreamActive(3)); EXPECT_EQ(NULL, spdy_stream2.get()); EXPECT_TRUE(session->IsStreamActive(1)); - - EXPECT_FALSE(session->IsClosed()); + 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) { - const char kStreamUrl[] = "http://www.google.com"; session_deps_.host_resolver->set_synchronous_mode(true); MockConnect connect_data(SYNCHRONOUS, OK); @@ -613,9 +663,6 @@ TEST_P(SpdySessionTest, CreateStreamAfterGoAway) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -623,7 +670,7 @@ TEST_P(SpdySessionTest, CreateStreamAfterGoAway) { EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion()); - GURL url(kStreamUrl); + GURL url(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); @@ -662,13 +709,12 @@ TEST_P(SpdySessionTest, CreateStreamAfterGoAway) { // Receiving a SYN_STREAM frame after a GOAWAY frame should result in // the stream being refused. TEST_P(SpdySessionTest, SynStreamAfterGoAway) { - const char kStreamUrl[] = "http://www.google.com"; 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, kStreamUrl)); + push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kDefaultURL)); MockRead reads[] = { CreateMockRead(*goaway, 1), CreateMockRead(*push, 2), @@ -687,9 +733,6 @@ TEST_P(SpdySessionTest, SynStreamAfterGoAway) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -697,7 +740,7 @@ TEST_P(SpdySessionTest, SynStreamAfterGoAway) { EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion()); - GURL url(kStreamUrl); + GURL url(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); @@ -724,7 +767,75 @@ TEST_P(SpdySessionTest, SynStreamAfterGoAway) { // 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); } @@ -733,12 +844,12 @@ TEST_P(SpdySessionTest, ClientPing) { session_deps_.host_resolver->set_synchronous_mode(true); MockConnect connect_data(SYNCHRONOUS, OK); - scoped_ptr<SpdyFrame> read_ping(spdy_util_.ConstructSpdyPing(1)); + 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)); + scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false)); MockWrite writes[] = { CreateMockWrite(*write_ping, 0), }; @@ -747,9 +858,6 @@ TEST_P(SpdySessionTest, ClientPing) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -791,12 +899,12 @@ 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)); + 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)); + scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(2, true)); MockWrite writes[] = { CreateMockWrite(*write_ping), }; @@ -805,9 +913,6 @@ TEST_P(SpdySessionTest, ServerPing) { data.set_connect_data(connect_data); session_deps_.socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); - CreateNetworkSession(); base::WeakPtr<SpdySession> session = @@ -838,7 +943,7 @@ TEST_P(SpdySessionTest, PingAndWriteLoop) { session_deps_.time_func = TheNearFuture; MockConnect connect_data(SYNCHRONOUS, OK); - scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1)); + 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[] = { @@ -857,15 +962,12 @@ TEST_P(SpdySessionTest, PingAndWriteLoop) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url("http://www.google.com"); + GURL url(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog()); @@ -884,45 +986,245 @@ TEST_P(SpdySessionTest, PingAndWriteLoop) { session->CloseSessionOnError(ERR_ABORTED, "Aborting"); } -TEST_P(SpdySessionTest, DeleteExpiredPushStreams) { +TEST_P(SpdySessionTest, StreamIdSpaceExhausted) { + const SpdyStreamId kLastStreamId = 0x7fffffff; session_deps_.host_resolver->set_synchronous_mode(true); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); - session_deps_.time_func = TheNearFuture; + // 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)); + scoped_ptr<SpdyFrame> push_b(spdy_util_.ConstructSpdyPush( + NULL, 0, 4, 1, "http://www.google.com/b.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 = - CreateFakeSpdySession(spdy_session_pool_, key_); + CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - session->buffered_spdy_framer_.reset( - new BufferedSpdyFramer(spdy_util_.spdy_version(), false)); - - // Create the associated stream and add to active streams. - scoped_ptr<SpdyHeaderBlock> request_headers( - spdy_util_.ConstructGetHeaderBlock("http://www.google.com/")); - - scoped_ptr<SpdyStream> stream(new SpdyStream(SPDY_REQUEST_RESPONSE_STREAM, - session, - GURL(), - DEFAULT_PRIORITY, - kSpdyStreamInitialWindowSize, - kSpdyStreamInitialWindowSize, - session->net_log_)); - stream->SendRequestHeaders(request_headers.Pass(), NO_MORE_DATA_TO_SEND); - SpdyStream* stream_ptr = stream.get(); - session->InsertCreatedStream(stream.Pass()); - stream = session->ActivateCreatedStream(stream_ptr); - session->InsertActivatedStream(stream.Pass()); + // 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); - SpdyHeaderBlock headers; - spdy_util_.AddUrlToHeaderBlock("http://www.google.com/a.dat", &headers); + scoped_ptr<SpdyHeaderBlock> headers( + spdy_util_.ConstructGetHeaderBlock(url.spec())); + spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); - // OnSynStream() expects |in_io_loop_| to be true. - session->in_io_loop_ = true; - session->OnSynStream(2, 1, 0, 0, true, false, headers); - session->in_io_loop_ = false; + data.RunFor(3); // Verify that there is one unclaimed push stream. EXPECT_EQ(1u, session->num_unclaimed_pushed_streams()); @@ -931,19 +1233,37 @@ TEST_P(SpdySessionTest, DeleteExpiredPushStreams) { GURL("http://www.google.com/a.dat")); EXPECT_TRUE(session->unclaimed_pushed_streams_.end() != iter); - // Shift time to expire the push stream. - g_time_delta = base::TimeDelta::FromSeconds(301); + if (session->flow_control_state_ == + SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) { + // Unclaimed push body consumed bytes from the session window. + EXPECT_EQ(kSpdySessionInitialWindowSize - kUploadDataSize, + session->session_recv_window_size_); + EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); + } - spdy_util_.AddUrlToHeaderBlock("http://www.google.com/b.dat", &headers); - session->in_io_loop_ = true; - session->OnSynStream(4, 1, 0, 0, true, false, headers); - session->in_io_loop_ = false; + // 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/b.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(kSpdySessionInitialWindowSize, + 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) { @@ -951,17 +1271,18 @@ TEST_P(SpdySessionTest, FailedPing) { MockConnect connect_data(SYNCHRONOUS, OK); MockRead reads[] = { - MockRead(ASYNC, 0, 0, 0) // EOF + MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. }; - scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1)); - DeterministicSocketData data(reads, arraysize(reads), NULL, 0); + 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_.deterministic_socket_factory->AddSocketDataProvider(&data); - - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); + session_deps_.socket_factory->AddSocketDataProvider(&data); - CreateDeterministicNetworkSession(); + CreateNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); @@ -977,13 +1298,13 @@ TEST_P(SpdySessionTest, FailedPing) { session->set_hung_interval(base::TimeDelta::FromSeconds(0)); // Send a PING frame. - session->WritePingFrame(1); + session->WritePingFrame(1, false); EXPECT_LT(0, session->pings_in_flight()); EXPECT_GE(session->next_ping_id(), static_cast<uint32>(1)); EXPECT_TRUE(session->check_ping_status_pending()); // Assert session is not closed. - EXPECT_FALSE(session->IsClosed()); + EXPECT_TRUE(session->IsAvailable()); EXPECT_LT(0u, session->num_active_streams() + session->num_created_streams()); EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); @@ -992,11 +1313,10 @@ TEST_P(SpdySessionTest, FailedPing) { 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_)); - - data.RunFor(1); EXPECT_EQ(NULL, spdy_stream1.get()); } @@ -1020,14 +1340,17 @@ TEST_P(SpdySessionTest, OnSettings) { MockRead(ASYNC, 0, 1), }; - DeterministicSocketData data(reads, arraysize(reads), NULL, 0); + 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); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -1054,6 +1377,11 @@ TEST_P(SpdySessionTest, OnSettings) { 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); } @@ -1062,6 +1390,11 @@ TEST_P(SpdySessionTest, OnSettings) { // 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; @@ -1082,9 +1415,6 @@ TEST_P(SpdySessionTest, ClearSettings) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); // Initialize the SpdySetting with the default. @@ -1153,9 +1483,6 @@ TEST_P(SpdySessionTest, CancelPendingCreateStream) { data.set_connect_data(connect_data); session_deps_.socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); - CreateNetworkSession(); // Initialize the SpdySetting with 1 max concurrent streams. @@ -1229,7 +1556,7 @@ TEST_P(SpdySessionTest, SendInitialDataOnNewSession) { kSessionFlowControlStreamId, kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize)); std::vector<MockWrite> writes; - if (GetParam() == kProtoHTTP2Draft04) { + if (GetParam() == kProtoSPDY4) { writes.push_back( MockWrite(ASYNC, kHttp2ConnectionHeaderPrefix, @@ -1256,9 +1583,6 @@ TEST_P(SpdySessionTest, SendInitialDataOnNewSession) { data.set_connect_data(connect_data); session_deps_.socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); - CreateNetworkSession(); spdy_session_pool_->http_server_properties()->SetSpdySetting( @@ -1309,9 +1633,6 @@ TEST_P(SpdySessionTest, Initialize) { data.set_connect_data(connect_data); session_deps_.socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); - CreateNetworkSession(); base::WeakPtr<SpdySession> session = @@ -1340,7 +1661,7 @@ TEST_P(SpdySessionTest, Initialize) { EXPECT_NE(log.bound().source().id, socket_source.id); } -TEST_P(SpdySessionTest, CloseSessionOnError) { +TEST_P(SpdySessionTest, NetLogOnSessionGoaway) { session_deps_.host_resolver->set_synchronous_mode(true); MockConnect connect_data(SYNCHRONOUS, OK); @@ -1354,9 +1675,6 @@ TEST_P(SpdySessionTest, CloseSessionOnError) { data.set_connect_data(connect_data); session_deps_.socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); - CreateNetworkSession(); CapturingBoundNetLog log; @@ -1385,6 +1703,53 @@ TEST_P(SpdySessionTest, CloseSessionOnError) { 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(); @@ -1429,15 +1794,12 @@ TEST_P(SpdySessionTest, OutOfOrderSynStreams) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url("http://www.google.com"); + GURL url(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream_lowest = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, @@ -1502,15 +1864,12 @@ TEST_P(SpdySessionTest, CancelStream) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url1("http://www.google.com"); + GURL url1(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url1, HIGHEST, BoundNetLog()); @@ -1519,7 +1878,7 @@ TEST_P(SpdySessionTest, CancelStream) { test::StreamDelegateDoNothing delegate1(spdy_stream1); spdy_stream1->SetDelegate(&delegate1); - GURL url2("http://www.google.com"); + GURL url2(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url2, LOWEST, BoundNetLog()); @@ -1575,22 +1934,19 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url1("http://www.google.com"); + 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("http://www.google.com"); + GURL url2(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session, url2, LOWEST, BoundNetLog()); @@ -1626,6 +1982,7 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) { EXPECT_TRUE(delegate1.StreamIsClosed()); EXPECT_TRUE(delegate2.StreamIsClosed()); + base::MessageLoop::current()->RunUntilIdle(); EXPECT_TRUE(session == NULL); } @@ -1649,22 +2006,19 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url1("http://www.google.com"); + 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("http://www.google.com"); + GURL url2(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session, url2, LOWEST, BoundNetLog()); @@ -1702,6 +2056,7 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) { EXPECT_TRUE(delegate1.StreamIsClosed()); EXPECT_TRUE(delegate2.StreamIsClosed()); + base::MessageLoop::current()->RunUntilIdle(); EXPECT_TRUE(session == NULL); } @@ -1730,22 +2085,19 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url1("http://www.google.com"); + 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("http://www.google.com"); + GURL url2(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url2, MEDIUM, BoundNetLog()); @@ -1786,6 +2138,7 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) { EXPECT_TRUE(delegate1.StreamIsClosed()); EXPECT_TRUE(delegate2.StreamIsClosed()); + base::MessageLoop::current()->RunUntilIdle(); EXPECT_TRUE(session == NULL); } @@ -1814,22 +2167,19 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url1("http://www.google.com"); + 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("http://www.google.com"); + GURL url2(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url2, MEDIUM, BoundNetLog()); @@ -1872,6 +2222,7 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) { EXPECT_TRUE(delegate1.StreamIsClosed()); EXPECT_TRUE(delegate2.StreamIsClosed()); + base::MessageLoop::current()->RunUntilIdle(); EXPECT_TRUE(session == NULL); } @@ -1886,7 +2237,7 @@ class SessionClosingDelegate : public test::StreamDelegateDoNothing { virtual ~SessionClosingDelegate() {} virtual void OnClose(int status) OVERRIDE { - session_to_close_->CloseSessionOnError(ERR_ABORTED, "Aborted"); + session_to_close_->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Error"); } private: @@ -1902,27 +2253,31 @@ TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) { 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(*req, 0), CreateMockWrite(*goaway, 1), + CreateMockWrite(*rst, 2), }; MockRead reads[] = { - MockRead(ASYNC, 0, 1) // EOF + 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); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url("http://www.google.com"); + GURL url(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); @@ -1949,10 +2304,13 @@ TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) { 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) { +TEST_P(SpdySessionTest, DISABLED_VerifyDomainAuthentication) { session_deps_.host_resolver->set_synchronous_mode(true); MockConnect connect_data(SYNCHRONOUS, OK); @@ -1994,7 +2352,8 @@ TEST_P(SpdySessionTest, VerifyDomainAuthentication) { EXPECT_FALSE(session->VerifyDomainAuthentication("mail.google.com")); } -TEST_P(SpdySessionTest, ConnectionPooledWithTlsChannelId) { +// TODO(rch): re-enable this. +TEST_P(SpdySessionTest, DISABLED_ConnectionPooledWithTlsChannelId) { session_deps_.host_resolver->set_synchronous_mode(true); MockConnect connect_data(SYNCHRONOUS, OK); @@ -2048,6 +2407,7 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) { 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( @@ -2055,9 +2415,10 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) { scoped_ptr<SpdyFrame> req3( spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true)); MockWrite writes[] = { - CreateMockWrite(*req1, 1), - CreateMockWrite(*req2, 4), - CreateMockWrite(*req3, 7), + 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 @@ -2076,13 +2437,13 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) { MockRead reads[] = { CreateMockRead(*settings_frame), - CreateMockRead(*resp1, 2), - CreateMockRead(*body1, 3), - CreateMockRead(*resp2, 5), - CreateMockRead(*body2, 6), - CreateMockRead(*resp3, 8), - CreateMockRead(*body3, 9), - MockRead(ASYNC, 0, 10) // EOF + 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), @@ -2090,9 +2451,6 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -2101,7 +2459,7 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) { // Read the settings frame. data.RunFor(1); - GURL url1("http://www.google.com"); + GURL url1(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url1, LOWEST, BoundNetLog()); @@ -2111,7 +2469,7 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) { spdy_stream1->SetDelegate(&delegate1); TestCompletionCallback callback2; - GURL url2("http://www.google.com"); + GURL url2(kDefaultURL); SpdyStreamRequest request2; ASSERT_EQ(ERR_IO_PENDING, request2.StartRequest( @@ -2119,7 +2477,7 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) { session, url2, LOWEST, BoundNetLog(), callback2.callback())); TestCompletionCallback callback3; - GURL url3("http://www.google.com"); + GURL url3(kDefaultURL); SpdyStreamRequest request3; ASSERT_EQ(ERR_IO_PENDING, request3.StartRequest( @@ -2137,7 +2495,7 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) { // Run until 1st stream is activated and then closed. EXPECT_EQ(0u, delegate1.stream_id()); - data.RunFor(3); + data.RunFor(4); EXPECT_EQ(NULL, spdy_stream1.get()); EXPECT_EQ(1u, delegate1.stream_id()); @@ -2213,9 +2571,6 @@ TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) { data.set_connect_data(connect_data); session_deps_.socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); - CreateNetworkSession(); base::WeakPtr<SpdySession> session = @@ -2229,7 +2584,7 @@ TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) { ASSERT_TRUE(spdy_stream != NULL); } - GURL url1("http://www.google.com"); + GURL url1(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session, url1, LOWEST, BoundNetLog()); @@ -2237,7 +2592,7 @@ TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) { EXPECT_EQ(0u, spdy_stream1->stream_id()); TestCompletionCallback callback2; - GURL url2("http://www.google.com"); + GURL url2(kDefaultURL); SpdyStreamRequest request2; ASSERT_EQ(ERR_IO_PENDING, request2.StartRequest( @@ -2245,7 +2600,7 @@ TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) { callback2.callback())); TestCompletionCallback callback3; - GURL url3("http://www.google.com"); + GURL url3(kDefaultURL); SpdyStreamRequest request3; ASSERT_EQ(ERR_IO_PENDING, request3.StartRequest( @@ -2334,15 +2689,12 @@ TEST_P(SpdySessionTest, ReadDataWithoutYielding) { session_deps_.host_resolver->set_synchronous_mode(true); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url1("http://www.google.com"); + GURL url1(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url1, MEDIUM, BoundNetLog()); @@ -2428,15 +2780,12 @@ TEST_P(SpdySessionTest, TestYieldingDuringReadData) { session_deps_.host_resolver->set_synchronous_mode(true); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url1("http://www.google.com"); + GURL url1(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url1, MEDIUM, BoundNetLog()); @@ -2544,15 +2893,12 @@ TEST_P(SpdySessionTest, TestYieldingDuringAsyncReadData) { session_deps_.host_resolver->set_synchronous_mode(true); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url1("http://www.google.com"); + GURL url1(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url1, MEDIUM, BoundNetLog()); @@ -2618,15 +2964,12 @@ TEST_P(SpdySessionTest, GoAwayWhileInDoReadLoop) { session_deps_.host_resolver->set_synchronous_mode(true); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url1("http://www.google.com"); + GURL url1(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url1, MEDIUM, BoundNetLog()); @@ -2718,7 +3061,7 @@ TEST_P(SpdySessionTest, CloseOneIdleConnection) { // Create an idle SPDY session. SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), - kPrivacyModeDisabled); + PRIVACY_MODE_DISABLED); base::WeakPtr<SpdySession> session1 = CreateInsecureSpdySession(http_session_, key1, BoundNetLog()); EXPECT_FALSE(pool->IsStalled()); @@ -2778,14 +3121,14 @@ TEST_P(SpdySessionTest, CloseOneIdleConnectionWithAlias) { // Create an idle SPDY session. SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), - kPrivacyModeDisabled); + 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(), - kPrivacyModeDisabled); + PRIVACY_MODE_DISABLED); HostResolver::RequestInfo info(key2.host_port_pair()); AddressList addresses; // Pre-populate the DNS cache, since a synchronous resolution is required in @@ -2864,9 +3207,9 @@ TEST_P(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) { HttpNetworkSession::NORMAL_SOCKET_POOL); // Create a SPDY session. - GURL url1("http://www.google.com"); + GURL url1(kDefaultURL); SpdySessionKey key1(HostPortPair(url1.host(), 80), - ProxyServer::Direct(), kPrivacyModeDisabled); + ProxyServer::Direct(), PRIVACY_MODE_DISABLED); base::WeakPtr<SpdySession> session1 = CreateInsecureSpdySession(http_session_, key1, BoundNetLog()); EXPECT_FALSE(pool->IsStalled()); @@ -2927,9 +3270,9 @@ TEST_P(SpdySessionTest, SpdySessionKeyPrivacyMode) { HostPortPair host_port_pair("www.google.com", 443); SpdySessionKey key_privacy_enabled(host_port_pair, ProxyServer::Direct(), - kPrivacyModeEnabled); + PRIVACY_MODE_ENABLED); SpdySessionKey key_privacy_disabled(host_port_pair, ProxyServer::Direct(), - kPrivacyModeDisabled); + PRIVACY_MODE_DISABLED); EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled)); EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled)); @@ -2968,7 +3311,7 @@ class StreamCreatingDelegate : public test::StreamDelegateDoNothing { virtual ~StreamCreatingDelegate() {} virtual void OnClose(int status) OVERRIDE { - GURL url("http://www.google.com"); + GURL url(kDefaultURL); ignore_result( CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, url, MEDIUM, BoundNetLog())); @@ -3003,15 +3346,12 @@ TEST_P(SpdySessionTest, CreateStreamOnStreamReset) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); - GURL url("http://www.google.com"); + GURL url(kDefaultURL); base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog()); @@ -3065,15 +3405,17 @@ TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) { MockRead(ASYNC, 0, 1) // EOF }; - session_deps_.host_resolver->set_synchronous_mode(true); + scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); + MockWrite writes[] = { + CreateMockWrite(*settings_ack, 2), + }; - scoped_ptr<DeterministicSocketData> data( - new DeterministicSocketData(reads, arraysize(reads), NULL, 0)); - data->set_connect_data(connect_data); - session_deps_.deterministic_socket_factory->AddSocketDataProvider(data.get()); + session_deps_.host_resolver->set_synchronous_mode(true); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); + DeterministicSocketData data(reads, arraysize(reads), + writes, arraysize(writes)); + data.set_connect_data(connect_data); + session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); CreateDeterministicNetworkSession(); @@ -3086,7 +3428,7 @@ TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) { TestCompletionCallback callback1; EXPECT_NE(spdy_stream1->send_window_size(), window_size); - data->RunFor(1); // Process the SETTINGS frame, but not the EOF + 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); @@ -3134,9 +3476,6 @@ TEST_P(SpdySessionTest, AdjustRecvWindowSize) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); @@ -3224,9 +3563,6 @@ TEST_P(SpdySessionTest, SessionFlowControlInactiveStream) { data.set_connect_data(connect_data); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(http_session_, key_, BoundNetLog()); @@ -3302,9 +3638,6 @@ TEST_P(SpdySessionTest, SessionFlowControlNoReceiveLeaks) { session_deps_.host_resolver->set_synchronous_mode(true); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -3380,9 +3713,6 @@ TEST_P(SpdySessionTest, SessionFlowControlNoSendLeaks) { session_deps_.host_resolver->set_synchronous_mode(true); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -3472,9 +3802,6 @@ TEST_P(SpdySessionTest, SessionFlowControlEndToEnd) { session_deps_.host_resolver->set_synchronous_mode(true); session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); - CreateDeterministicNetworkSession(); base::WeakPtr<SpdySession> session = @@ -3633,7 +3960,6 @@ void SpdySessionTest::RunResumeAfterUnstallTest( EXPECT_TRUE(delegate.send_headers_completed()); EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status")); - EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version")); EXPECT_EQ(std::string(), delegate.TakeReceivedData()); EXPECT_TRUE(data.at_write_eof()); } @@ -3830,12 +4156,10 @@ TEST_P(SpdySessionTest, ResumeByPriorityAfterSendWindowSizeIncrease) { EXPECT_TRUE(delegate1.send_headers_completed()); EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status")); - EXPECT_EQ("HTTP/1.1", delegate1.GetResponseHeaderValue(":version")); EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); EXPECT_TRUE(delegate2.send_headers_completed()); EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); - EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); EXPECT_TRUE(data.at_write_eof()); @@ -4019,7 +4343,6 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) { EXPECT_TRUE(delegate2.send_headers_completed()); EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); - EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); EXPECT_TRUE(delegate3.send_headers_completed()); @@ -4125,6 +4448,7 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) { // 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_)); @@ -4141,4 +4465,133 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) { 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); +} + +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)); +} + +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)); +} + } // namespace net |