Index: net/spdy/spdy_session_unittest.cc |
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc |
index 9c516076110b775d3712b068595b6d110f7ea1dd..cce77ef1b197466cfb39aab31b16186299bdb2a5 100644 |
--- a/net/spdy/spdy_session_unittest.cc |
+++ b/net/spdy/spdy_session_unittest.cc |
@@ -2182,134 +2182,6 @@ TEST_P(SpdySessionTest, NeedsCredentials) { |
spdy_session_pool_->Remove(session); |
} |
-TEST_P(SpdySessionTest, SendCredentials) { |
- if (GetParam() < kProtoSPDY3) |
- return; |
- |
- MockConnect connect_data(SYNCHRONOUS, OK); |
- MockRead reads[] = { |
- MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
- }; |
- SettingsMap settings; |
- scoped_ptr<SpdyFrame> settings_frame( |
- spdy_util_.ConstructSpdySettings(settings)); |
- MockWrite writes[] = { |
- CreateMockWrite(*settings_frame), |
- }; |
- StaticSocketDataProvider data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
- data.set_connect_data(connect_data); |
- session_deps_.socket_factory->AddSocketDataProvider(&data); |
- |
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK); |
- ssl.channel_id_sent = true; |
- ssl.protocol_negotiated = GetParam(); |
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); |
- |
- CreateNetworkSession(); |
- |
- const GURL kTestUrl("https://www.foo.com"); |
- HostPortPair test_host_port_pair(kTestUrl.host(), 443); |
- SpdySessionKey key(test_host_port_pair, ProxyServer::Direct(), |
- kPrivacyModeDisabled); |
- |
- scoped_refptr<SpdySession> session = GetSession(key); |
- |
- SSLConfig ssl_config; |
- scoped_refptr<TransportSocketParams> transport_params( |
- new TransportSocketParams(test_host_port_pair, |
- MEDIUM, |
- false, |
- false, |
- OnHostResolutionCallback())); |
- scoped_refptr<SOCKSSocketParams> socks_params; |
- scoped_refptr<HttpProxySocketParams> http_proxy_params; |
- scoped_refptr<SSLSocketParams> ssl_params( |
- new SSLSocketParams(transport_params, |
- socks_params, |
- http_proxy_params, |
- ProxyServer::SCHEME_DIRECT, |
- test_host_port_pair, |
- ssl_config, |
- 0, |
- false, |
- false)); |
- scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); |
- EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), |
- ssl_params, MEDIUM, CompletionCallback(), |
- http_session_->GetSSLSocketPool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL), |
- BoundNetLog())); |
- |
- EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), true, OK)); |
- EXPECT_TRUE(session->NeedsCredentials()); |
- |
- // Flush the SpdySession::OnReadComplete() task. |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- spdy_session_pool_->Remove(session); |
- EXPECT_FALSE(spdy_session_pool_->HasSession(key)); |
-} |
- |
-TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) { |
- if (GetParam() < kProtoSPDY3) |
- return; |
- |
- // 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 |
- }; |
- |
- session_deps_.host_resolver->set_synchronous_mode(true); |
- |
- 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()); |
- |
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK); |
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); |
- |
- CreateDeterministicNetworkSession(); |
- |
- scoped_refptr<SpdySession> session = CreateInitializedSession(); |
- 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()); |
-} |
- |
// Test that SpdySession::DoRead 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. |
@@ -2718,95 +2590,557 @@ TEST_P(SpdySessionTest, ProtocolNegotiation) { |
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
} |
-// 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 delta_window_size = 100; |
+// 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(ASYNC, 0, 1) // EOF |
- }; |
- scoped_ptr<SpdyFrame> window_update( |
- spdy_util_.ConstructSpdyWindowUpdate( |
- kSessionFlowControlStreamId, |
- kSpdySessionInitialWindowSize + delta_window_size)); |
- MockWrite writes[] = { |
- CreateMockWrite(*window_update, 0), |
+ MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
}; |
- DeterministicSocketData data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
+ StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
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(); |
- scoped_refptr<SpdySession> session = GetSession(key_); |
- InitializeSession( |
- http_session_.get(), session.get(), test_host_port_pair_); |
- EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
- session->flow_control_state()); |
+ session_deps_.socket_factory->AddSocketDataProvider(&data); |
+ session_deps_.socket_factory->AddSocketDataProvider(&data); |
- EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
+ CreateNetworkSession(); |
- session->IncreaseRecvWindowSize(delta_window_size); |
- EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size, |
- session->session_recv_window_size_); |
- EXPECT_EQ(delta_window_size, session->session_unacked_recv_window_bytes_); |
+ TransportClientSocketPool* pool = |
+ http_session_->GetTransportSocketPool( |
+ HttpNetworkSession::NORMAL_SOCKET_POOL); |
- // Should trigger sending a WINDOW_UPDATE frame. |
- session->IncreaseRecvWindowSize(kSpdySessionInitialWindowSize); |
- EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size + |
- kSpdySessionInitialWindowSize, |
- session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
+ // Create an idle SPDY session. |
+ SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), |
+ kPrivacyModeDisabled); |
+ scoped_refptr<SpdySession> session1 = GetSession(key1); |
+ EXPECT_EQ( |
+ OK, |
+ InitializeSession(http_session_.get(), session1.get(), |
+ key1.host_port_pair())); |
+ EXPECT_FALSE(pool->IsStalled()); |
+ // Release the pointer to the session so it can be closed. |
+ session1 = NULL; |
- data.RunFor(1); |
+ // 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, DEFAULT_PRIORITY, false, false, |
+ OnHostResolutionCallback())); |
+ 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()); |
- session->DecreaseRecvWindowSize( |
- kSpdySessionInitialWindowSize + delta_window_size + |
- kSpdySessionInitialWindowSize); |
- EXPECT_EQ(0, session->session_recv_window_size_); |
- EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
+ // The socket pool should close the connection asynchronously and establish a |
+ // new connection. |
+ EXPECT_EQ(OK, callback2.WaitForResult()); |
+ EXPECT_FALSE(pool->IsStalled()); |
} |
-// 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); |
+// 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, 0, 0) // EOF |
+ 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(); |
- scoped_refptr<SpdySession> session = GetSession(key_); |
- InitializeSession( |
- http_session_.get(), session.get(), test_host_port_pair_); |
- EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
- session->flow_control_state()); |
+ 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()); |
- const int32 delta_window_size = 100; |
+ CreateNetworkSession(); |
- EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); |
+ TransportClientSocketPool* pool = |
+ http_session_->GetTransportSocketPool( |
+ HttpNetworkSession::NORMAL_SOCKET_POOL); |
+ |
+ // Create an idle SPDY session. |
+ SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), |
+ kPrivacyModeDisabled); |
+ scoped_refptr<SpdySession> session1 = GetSession(key1); |
+ EXPECT_EQ( |
+ OK, |
+ InitializeSession(http_session_.get(), session1.get(), |
+ key1.host_port_pair())); |
+ 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); |
+ SpdySessionPoolPeer pool_peer(spdy_session_pool_); |
+ 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, &addresses, CompletionCallback(), NULL, BoundNetLog()); |
+ // Add the alias for the first session's key. Has to be done manually since |
+ // the usual process is bypassed. |
+ pool_peer.AddAlias(addresses.front(), key1); |
+ // Get a session for |key2|, which should return the session created earlier. |
+ scoped_refptr<SpdySession> session2 = |
+ spdy_session_pool_->Get(key2, BoundNetLog()); |
+ ASSERT_EQ(session1.get(), session2.get()); |
+ EXPECT_FALSE(pool->IsStalled()); |
+ |
+ // Release both the pointers to the session so it can be closed. |
+ session1 = NULL; |
+ session2 = NULL; |
+ |
+ // 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, DEFAULT_PRIORITY, false, false, |
+ OnHostResolutionCallback())); |
+ 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()); |
+} |
+ |
+// Tests the case of a non-SPDY request closing an idle SPDY session when a |
+// pointer to the idle session is still held. |
+TEST_P(SpdySessionTest, CloseOneIdleConnectionSessionStillHeld) { |
+ 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(), |
+ kPrivacyModeDisabled); |
+ scoped_refptr<SpdySession> session1 = GetSession(key1); |
+ EXPECT_EQ( |
+ OK, |
+ InitializeSession(http_session_.get(), session1.get(), |
+ key1.host_port_pair())); |
+ 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, DEFAULT_PRIORITY, false, false, |
+ OnHostResolutionCallback())); |
+ 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 session to prepare to be closed, |
+ // but since there's still an outstanding reference, it should not be closed |
+ // yet. |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_TRUE(pool->IsStalled()); |
+ EXPECT_FALSE(callback2.have_result()); |
+ |
+ // Release the pointer to the session so it can be closed. |
+ session1 = NULL; |
+ EXPECT_EQ(OK, callback2.WaitForResult()); |
+ EXPECT_FALSE(pool->IsStalled()); |
+} |
+ |
+// Tests that a non-SPDY request can't close a SPDY session that's currently in |
+// use. |
+TEST_P(SpdySessionTest, CloseOneIdleConnectionFailsWhenSessionInUse) { |
+ 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); |
+ |
+ CreateNetworkSession(); |
+ |
+ TransportClientSocketPool* pool = |
+ http_session_->GetTransportSocketPool( |
+ HttpNetworkSession::NORMAL_SOCKET_POOL); |
+ |
+ // Create a SPDY session. |
+ GURL url1("http://www.google.com"); |
+ SpdySessionKey key1(HostPortPair(url1.host(), 80), |
+ ProxyServer::Direct(), kPrivacyModeDisabled); |
+ scoped_refptr<SpdySession> session1 = GetSession(key1); |
+ EXPECT_EQ( |
+ OK, |
+ InitializeSession(http_session_.get(), session1.get(), |
+ key1.host_port_pair())); |
+ 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->HasUrl()); |
+ |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ |
+ // Release the session, so holding onto a pointer here does not affect |
+ // anything. |
+ session1 = NULL; |
+ |
+ // 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, DEFAULT_PRIORITY, false, false, |
+ OnHostResolutionCallback())); |
+ 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 still not release the session's socket, |
+ // since the session is still kept alive by the SpdySessionPool. |
+ ASSERT_TRUE(spdy_stream1.get()); |
+ spdy_stream1->Cancel(); |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_TRUE(pool->IsStalled()); |
+ EXPECT_FALSE(callback2.have_result()); |
+} |
+ |
+// 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(), |
+ kPrivacyModeEnabled); |
+ SpdySessionKey key_privacy_disabled(host_port_pair, ProxyServer::Direct(), |
+ kPrivacyModeDisabled); |
+ |
+ EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
+ EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
+ |
+ // Add SpdySession with PrivacyMode Enabled to the pool. |
+ scoped_refptr<SpdySession> session_privacy_enabled = |
+ spdy_session_pool_->Get(key_privacy_enabled, BoundNetLog()); |
+ |
+ EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
+ EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
+ |
+ // Add SpdySession with PrivacyMode Disabled to the pool. |
+ scoped_refptr<SpdySession> session_privacy_disabled = |
+ spdy_session_pool_->Get(key_privacy_disabled, BoundNetLog()); |
+ |
+ EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
+ EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
+ |
+ spdy_session_pool_->Remove(session_privacy_enabled); |
+ EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
+ EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
+ |
+ spdy_session_pool_->Remove(session_privacy_disabled); |
+ EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
+ EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
+} |
+ |
+// The tests below are only for SPDY/3 and above. |
+ |
+TEST_P(SpdySessionTest, SendCredentials) { |
+ if (GetParam() < kProtoSPDY3) |
+ return; |
+ |
+ MockConnect connect_data(SYNCHRONOUS, OK); |
+ MockRead reads[] = { |
+ MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
+ }; |
+ SettingsMap settings; |
+ scoped_ptr<SpdyFrame> settings_frame( |
+ spdy_util_.ConstructSpdySettings(settings)); |
+ MockWrite writes[] = { |
+ CreateMockWrite(*settings_frame), |
+ }; |
+ StaticSocketDataProvider data(reads, arraysize(reads), |
+ writes, arraysize(writes)); |
+ data.set_connect_data(connect_data); |
+ session_deps_.socket_factory->AddSocketDataProvider(&data); |
+ |
+ SSLSocketDataProvider ssl(SYNCHRONOUS, OK); |
+ ssl.channel_id_sent = true; |
+ ssl.protocol_negotiated = GetParam(); |
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); |
+ |
+ CreateNetworkSession(); |
+ |
+ const GURL kTestUrl("https://www.foo.com"); |
+ HostPortPair test_host_port_pair(kTestUrl.host(), 443); |
+ SpdySessionKey key(test_host_port_pair, ProxyServer::Direct(), |
+ kPrivacyModeDisabled); |
+ |
+ scoped_refptr<SpdySession> session = GetSession(key); |
+ |
+ SSLConfig ssl_config; |
+ scoped_refptr<TransportSocketParams> transport_params( |
+ new TransportSocketParams(test_host_port_pair, |
+ MEDIUM, |
+ false, |
+ false, |
+ OnHostResolutionCallback())); |
+ scoped_refptr<SOCKSSocketParams> socks_params; |
+ scoped_refptr<HttpProxySocketParams> http_proxy_params; |
+ scoped_refptr<SSLSocketParams> ssl_params( |
+ new SSLSocketParams(transport_params, |
+ socks_params, |
+ http_proxy_params, |
+ ProxyServer::SCHEME_DIRECT, |
+ test_host_port_pair, |
+ ssl_config, |
+ 0, |
+ false, |
+ false)); |
+ scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); |
+ EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), |
+ ssl_params, MEDIUM, CompletionCallback(), |
+ http_session_->GetSSLSocketPool( |
+ HttpNetworkSession::NORMAL_SOCKET_POOL), |
+ BoundNetLog())); |
+ |
+ EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), true, OK)); |
+ EXPECT_TRUE(session->NeedsCredentials()); |
+ |
+ // Flush the SpdySession::OnReadComplete() task. |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ |
+ spdy_session_pool_->Remove(session); |
+ EXPECT_FALSE(spdy_session_pool_->HasSession(key)); |
+} |
+ |
+TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) { |
+ if (GetParam() < kProtoSPDY3) |
+ return; |
+ |
+ // 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 |
+ }; |
+ |
+ session_deps_.host_resolver->set_synchronous_mode(true); |
+ |
+ 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()); |
+ |
+ SSLSocketDataProvider ssl(SYNCHRONOUS, OK); |
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); |
+ |
+ CreateDeterministicNetworkSession(); |
+ |
+ scoped_refptr<SpdySession> session = CreateInitializedSession(); |
+ 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 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, |
+ kSpdySessionInitialWindowSize + 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); |
+ |
+ SSLSocketDataProvider ssl(SYNCHRONOUS, OK); |
+ session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); |
+ |
+ CreateDeterministicNetworkSession(); |
+ scoped_refptr<SpdySession> session = GetSession(key_); |
+ InitializeSession( |
+ http_session_.get(), session.get(), test_host_port_pair_); |
+ EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
+ session->flow_control_state()); |
+ |
+ EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); |
+ EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
+ |
+ session->IncreaseRecvWindowSize(delta_window_size); |
+ EXPECT_EQ(kSpdySessionInitialWindowSize + 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(kSpdySessionInitialWindowSize); |
+ EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size + |
+ kSpdySessionInitialWindowSize, |
+ session->session_recv_window_size_); |
+ EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
+ |
+ data.RunFor(1); |
+ |
+ session->DecreaseRecvWindowSize( |
+ kSpdySessionInitialWindowSize + delta_window_size + |
+ kSpdySessionInitialWindowSize); |
+ 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(); |
+ scoped_refptr<SpdySession> session = GetSession(key_); |
+ InitializeSession( |
+ http_session_.get(), session.get(), test_host_port_pair_); |
+ EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
+ session->flow_control_state()); |
+ |
+ const int32 delta_window_size = 100; |
+ |
+ EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); |
session->IncreaseSendWindowSize(delta_window_size); |
EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size, |
@@ -3425,205 +3759,20 @@ TEST_P(SpdySessionTest, ResumeByPriorityAfterSendWindowSizeIncrease) { |
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("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()); |
-} |
- |
-// 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) {} |
- |
- virtual ~StreamClosingDelegate() {} |
- |
- void set_stream_to_close(const base::WeakPtr<SpdyStream>& stream_to_close) { |
- stream_to_close_ = stream_to_close; |
- } |
- |
- virtual 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(); |
- scoped_refptr<SpdySession> session = GetSession(key_); |
- InitializeSession( |
- http_session_.get(), session.get(), test_host_port_pair_); |
- 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->HasUrl()); |
- |
- 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->HasUrl()); |
- |
- 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->HasUrl()); |
- |
- 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->HasUrl()); |
- EXPECT_EQ(kStreamUrl, stream1->GetUrl().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->HasUrl()); |
- EXPECT_EQ(kStreamUrl, stream2->GetUrl().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->HasUrl()); |
- EXPECT_EQ(kStreamUrl, stream3->GetUrl().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()); |
+ // 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()); |
- 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()); |
+ data.RunFor(4); |
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("200", delegate1.GetResponseHeaderValue(":status")); |
+ EXPECT_EQ("HTTP/1.1", delegate1.GetResponseHeaderValue(":version")); |
EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); |
EXPECT_TRUE(delegate2.send_headers_completed()); |
@@ -3631,16 +3780,37 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) { |
EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); |
EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); |
- EXPECT_TRUE(delegate3.send_headers_completed()); |
- EXPECT_EQ(std::string(), delegate3.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) {} |
+ |
+ virtual ~StreamClosingDelegate() {} |
+ |
+ void set_stream_to_close(const base::WeakPtr<SpdyStream>& stream_to_close) { |
+ stream_to_close_ = stream_to_close; |
+ } |
+ |
+ virtual 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 the session itself |
-// being closed. |
-TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) { |
+// 0. Unstalling the session should properly handle deleted streams. |
+TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) { |
if (GetParam() < kProtoSPDY31) |
return; |
@@ -3655,15 +3825,22 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) { |
scoped_ptr<SpdyFrame> req2( |
spdy_util_.ConstructSpdyPost( |
kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0)); |
- scoped_ptr<SpdyFrame> body1( |
- spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false)); |
+ 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[] = { |
- MockRead(ASYNC, 0, 0, 2), // EOF |
+ CreateMockRead(*resp2, 4), |
+ MockRead(ASYNC, 0, 0, 5), // EOF |
}; |
DeterministicSocketData data(reads, arraysize(reads), |
@@ -3695,13 +3872,24 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) { |
session, url, LOWEST, BoundNetLog()); |
ASSERT_TRUE(stream2.get() != NULL); |
- test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece); |
+ StreamClosingDelegate delegate2(stream2, kBodyDataStringPiece); |
stream2->SetDelegate(&delegate2); |
EXPECT_FALSE(stream2->HasUrl()); |
+ 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->HasUrl()); |
+ |
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()); |
@@ -3727,359 +3915,174 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) { |
EXPECT_EQ(3u, stream2->stream_id()); |
EXPECT_TRUE(stream2->send_stalled_by_flow_control()); |
- EXPECT_TRUE(spdy_session_pool_->HasSession(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, true, "Closing session"); |
- session = NULL; |
- |
- EXPECT_FALSE(spdy_session_pool_->HasSession(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()); |
-} |
- |
- |
-// 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(), |
- kPrivacyModeDisabled); |
- scoped_refptr<SpdySession> session1 = GetSession(key1); |
- EXPECT_EQ( |
- OK, |
- InitializeSession(http_session_.get(), session1.get(), |
- key1.host_port_pair())); |
- EXPECT_FALSE(pool->IsStalled()); |
- // Release the pointer to the session so it can be closed. |
- session1 = NULL; |
- |
- // 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, DEFAULT_PRIORITY, false, false, |
- OnHostResolutionCallback())); |
- scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle); |
+ scoped_ptr<SpdyHeaderBlock> headers3( |
+ spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
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()); |
-} |
- |
-// 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(), |
- kPrivacyModeDisabled); |
- scoped_refptr<SpdySession> session1 = GetSession(key1); |
- EXPECT_EQ( |
- OK, |
- InitializeSession(http_session_.get(), session1.get(), |
- key1.host_port_pair())); |
- 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); |
- SpdySessionPoolPeer pool_peer(spdy_session_pool_); |
- 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, &addresses, CompletionCallback(), NULL, BoundNetLog()); |
- // Add the alias for the first session's key. Has to be done manually since |
- // the usual process is bypassed. |
- pool_peer.AddAlias(addresses.front(), key1); |
- // Get a session for |key2|, which should return the session created earlier. |
- scoped_refptr<SpdySession> session2 = |
- spdy_session_pool_->Get(key2, BoundNetLog()); |
- ASSERT_EQ(session1.get(), session2.get()); |
- EXPECT_FALSE(pool->IsStalled()); |
+ stream3->SendRequestHeaders(headers3.Pass(), MORE_DATA_TO_SEND)); |
+ EXPECT_TRUE(stream3->HasUrl()); |
+ EXPECT_EQ(kStreamUrl, stream3->GetUrl().spec()); |
- // Release both the pointers to the session so it can be closed. |
- session1 = NULL; |
- session2 = NULL; |
+ data.RunFor(1); |
+ EXPECT_EQ(5u, stream3->stream_id()); |
+ EXPECT_TRUE(stream3->send_stalled_by_flow_control()); |
- // 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, DEFAULT_PRIORITY, false, false, |
- OnHostResolutionCallback())); |
- 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()); |
+ SpdyStreamId stream_id1 = stream1->stream_id(); |
+ SpdyStreamId stream_id2 = stream2->stream_id(); |
+ SpdyStreamId stream_id3 = stream3->stream_id(); |
- // The socket pool should close the connection asynchronously and establish a |
- // new connection. |
- EXPECT_EQ(OK, callback3.WaitForResult()); |
- EXPECT_FALSE(pool->IsStalled()); |
-} |
+ // Close stream1 preemptively. |
+ session->CloseActiveStream(stream_id1, ERR_CONNECTION_CLOSED); |
+ EXPECT_EQ(NULL, stream1.get()); |
-// Tests the case of a non-SPDY request closing an idle SPDY session when a |
-// pointer to the idle session is still held. |
-TEST_P(SpdySessionTest, CloseOneIdleConnectionSessionStillHeld) { |
- ClientSocketPoolManager::set_max_sockets_per_group( |
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
- ClientSocketPoolManager::set_max_sockets_per_pool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
+ EXPECT_FALSE(session->IsStreamActive(stream_id1)); |
+ EXPECT_TRUE(session->IsStreamActive(stream_id2)); |
+ EXPECT_TRUE(session->IsStreamActive(stream_id3)); |
- 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); |
+ // Unstall stream2, which should then close stream3. |
+ delegate2.set_stream_to_close(stream3); |
+ UnstallSessionSend(session.get(), kBodyDataSize); |
- CreateNetworkSession(); |
+ data.RunFor(1); |
+ EXPECT_EQ(NULL, stream3.get()); |
- TransportClientSocketPool* pool = |
- http_session_->GetTransportSocketPool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL); |
+ 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)); |
- // Create an idle SPDY session. |
- SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), |
- kPrivacyModeDisabled); |
- scoped_refptr<SpdySession> session1 = GetSession(key1); |
- EXPECT_EQ( |
- OK, |
- InitializeSession(http_session_.get(), session1.get(), |
- key1.host_port_pair())); |
- EXPECT_FALSE(pool->IsStalled()); |
+ data.RunFor(2); |
+ EXPECT_EQ(NULL, stream2.get()); |
- // 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, DEFAULT_PRIORITY, false, false, |
- OnHostResolutionCallback())); |
- 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()); |
+ EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); |
+ EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); |
+ EXPECT_EQ(OK, delegate3.WaitForClose()); |
- // Running the message loop should cause the session to prepare to be closed, |
- // but since there's still an outstanding reference, it should not be closed |
- // yet. |
- base::RunLoop().RunUntilIdle(); |
- EXPECT_TRUE(pool->IsStalled()); |
- EXPECT_FALSE(callback2.have_result()); |
+ EXPECT_TRUE(delegate1.send_headers_completed()); |
+ EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); |
- // Release the pointer to the session so it can be closed. |
- session1 = NULL; |
- EXPECT_EQ(OK, callback2.WaitForResult()); |
- EXPECT_FALSE(pool->IsStalled()); |
+ 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()); |
+ EXPECT_EQ(std::string(), delegate3.TakeReceivedData()); |
+ |
+ EXPECT_TRUE(data.at_write_eof()); |
} |
-// Tests that a non-SPDY request can't close a SPDY session that's currently in |
-// use. |
-TEST_P(SpdySessionTest, CloseOneIdleConnectionFailsWhenSessionInUse) { |
- ClientSocketPoolManager::set_max_sockets_per_group( |
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
- ClientSocketPoolManager::set_max_sockets_per_pool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
+// 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); |
- 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)); |
+ 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, 1), |
- CreateMockWrite(*cancel1, 1), |
+ CreateMockWrite(*req1, 0), |
+ CreateMockWrite(*req2, 1), |
}; |
- StaticSocketDataProvider data(reads, arraysize(reads), |
- writes, arraysize(writes)); |
+ |
+ 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_.socket_factory->AddSocketDataProvider(&data); |
- CreateNetworkSession(); |
+ session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
- TransportClientSocketPool* pool = |
- http_session_->GetTransportSocketPool( |
- HttpNetworkSession::NORMAL_SOCKET_POOL); |
+ CreateDeterministicNetworkSession(); |
+ scoped_refptr<SpdySession> session = GetSession(key_); |
+ InitializeSession( |
+ http_session_.get(), session.get(), test_host_port_pair_); |
+ EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
+ session->flow_control_state()); |
- // Create a SPDY session. |
- GURL url1("http://www.google.com"); |
- SpdySessionKey key1(HostPortPair(url1.host(), 80), |
- ProxyServer::Direct(), kPrivacyModeDisabled); |
- scoped_refptr<SpdySession> session1 = GetSession(key1); |
- EXPECT_EQ( |
- OK, |
- InitializeSession(http_session_.get(), session1.get(), |
- key1.host_port_pair())); |
- EXPECT_FALSE(pool->IsStalled()); |
+ base::WeakPtr<SpdyStream> stream1 = |
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
+ session, url, LOWEST, BoundNetLog()); |
+ ASSERT_TRUE(stream1.get() != NULL); |
- // Create a stream using the session, and send a request. |
+ test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece); |
+ stream1->SetDelegate(&delegate1); |
- TestCompletionCallback callback1; |
- base::WeakPtr<SpdyStream> spdy_stream1 = |
+ EXPECT_FALSE(stream1->HasUrl()); |
+ |
+ base::WeakPtr<SpdyStream> stream2 = |
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
- session1, url1, DEFAULT_PRIORITY, |
- BoundNetLog()); |
- ASSERT_TRUE(spdy_stream1.get()); |
- test::StreamDelegateDoNothing delegate1(spdy_stream1); |
- spdy_stream1->SetDelegate(&delegate1); |
+ session, url, LOWEST, BoundNetLog()); |
+ ASSERT_TRUE(stream2.get() != NULL); |
- 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->HasUrl()); |
+ test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece); |
+ stream2->SetDelegate(&delegate2); |
- base::MessageLoop::current()->RunUntilIdle(); |
+ EXPECT_FALSE(stream2->HasUrl()); |
- // Release the session, so holding onto a pointer here does not affect |
- // anything. |
- session1 = NULL; |
+ EXPECT_FALSE(stream1->send_stalled_by_flow_control()); |
+ EXPECT_FALSE(stream2->send_stalled_by_flow_control()); |
- // 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, DEFAULT_PRIORITY, false, false, |
- OnHostResolutionCallback())); |
- scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle); |
+ StallSessionSend(session.get()); |
+ |
+ scoped_ptr<SpdyHeaderBlock> headers1( |
+ spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
EXPECT_EQ(ERR_IO_PENDING, |
- connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, |
- callback2.callback(), pool, BoundNetLog())); |
- EXPECT_TRUE(pool->IsStalled()); |
+ stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND)); |
+ EXPECT_TRUE(stream1->HasUrl()); |
+ EXPECT_EQ(kStreamUrl, stream1->GetUrl().spec()); |
- // 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()); |
+ data.RunFor(1); |
+ EXPECT_EQ(1u, stream1->stream_id()); |
+ EXPECT_TRUE(stream1->send_stalled_by_flow_control()); |
- // Cancelling the request should still not release the session's socket, |
- // since the session is still kept alive by the SpdySessionPool. |
- ASSERT_TRUE(spdy_stream1.get()); |
- spdy_stream1->Cancel(); |
- base::RunLoop().RunUntilIdle(); |
- EXPECT_TRUE(pool->IsStalled()); |
- EXPECT_FALSE(callback2.have_result()); |
-} |
+ 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->HasUrl()); |
+ EXPECT_EQ(kStreamUrl, stream2->GetUrl().spec()); |
-// Verify that SpdySessionKey and therefore SpdySession is different when |
-// privacy mode is enabled or disabled. |
-TEST_P(SpdySessionTest, SpdySessionKeyPrivacyMode) { |
- CreateDeterministicNetworkSession(); |
+ data.RunFor(1); |
+ EXPECT_EQ(3u, stream2->stream_id()); |
+ EXPECT_TRUE(stream2->send_stalled_by_flow_control()); |
- HostPortPair host_port_pair("www.google.com", 443); |
- SpdySessionKey key_privacy_enabled(host_port_pair, ProxyServer::Direct(), |
- kPrivacyModeEnabled); |
- SpdySessionKey key_privacy_disabled(host_port_pair, ProxyServer::Direct(), |
- kPrivacyModeDisabled); |
+ EXPECT_TRUE(spdy_session_pool_->HasSession(key_)); |
- EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
- EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
+ // Unstall stream1. |
+ UnstallSessionSend(session.get(), kBodyDataSize); |
- // Add SpdySession with PrivacyMode Enabled to the pool. |
- scoped_refptr<SpdySession> session_privacy_enabled = |
- spdy_session_pool_->Get(key_privacy_enabled, BoundNetLog()); |
+ // 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, true, "Closing session"); |
+ session = NULL; |
- EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
- EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
+ EXPECT_FALSE(spdy_session_pool_->HasSession(key_)); |
- // Add SpdySession with PrivacyMode Disabled to the pool. |
- scoped_refptr<SpdySession> session_privacy_disabled = |
- spdy_session_pool_->Get(key_privacy_disabled, BoundNetLog()); |
+ EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); |
+ EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); |
- EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
- EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
+ EXPECT_TRUE(delegate1.send_headers_completed()); |
+ EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); |
- spdy_session_pool_->Remove(session_privacy_enabled); |
- EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
- EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
+ EXPECT_TRUE(delegate2.send_headers_completed()); |
+ EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); |
- spdy_session_pool_->Remove(session_privacy_disabled); |
- EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
- EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
+ EXPECT_TRUE(data.at_write_eof()); |
} |
} // namespace net |