OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/spdy/spdy_session.h" | 5 #include "net/spdy/spdy_session.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/run_loop.h" | 10 #include "base/run_loop.h" |
(...skipping 2164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2175 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), true, OK)); | 2175 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), true, OK)); |
2176 | 2176 |
2177 EXPECT_EQ(spdy_util_.spdy_version() >= SPDY3, session->NeedsCredentials()); | 2177 EXPECT_EQ(spdy_util_.spdy_version() >= SPDY3, session->NeedsCredentials()); |
2178 | 2178 |
2179 // Flush the SpdySession::OnReadComplete() task. | 2179 // Flush the SpdySession::OnReadComplete() task. |
2180 base::MessageLoop::current()->RunUntilIdle(); | 2180 base::MessageLoop::current()->RunUntilIdle(); |
2181 | 2181 |
2182 spdy_session_pool_->Remove(session); | 2182 spdy_session_pool_->Remove(session); |
2183 } | 2183 } |
2184 | 2184 |
2185 TEST_P(SpdySessionTest, SendCredentials) { | |
2186 if (GetParam() < kProtoSPDY3) | |
2187 return; | |
2188 | |
2189 MockConnect connect_data(SYNCHRONOUS, OK); | |
2190 MockRead reads[] = { | |
2191 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
2192 }; | |
2193 SettingsMap settings; | |
2194 scoped_ptr<SpdyFrame> settings_frame( | |
2195 spdy_util_.ConstructSpdySettings(settings)); | |
2196 MockWrite writes[] = { | |
2197 CreateMockWrite(*settings_frame), | |
2198 }; | |
2199 StaticSocketDataProvider data(reads, arraysize(reads), | |
2200 writes, arraysize(writes)); | |
2201 data.set_connect_data(connect_data); | |
2202 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
2203 | |
2204 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
2205 ssl.channel_id_sent = true; | |
2206 ssl.protocol_negotiated = GetParam(); | |
2207 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
2208 | |
2209 CreateNetworkSession(); | |
2210 | |
2211 const GURL kTestUrl("https://www.foo.com"); | |
2212 HostPortPair test_host_port_pair(kTestUrl.host(), 443); | |
2213 SpdySessionKey key(test_host_port_pair, ProxyServer::Direct(), | |
2214 kPrivacyModeDisabled); | |
2215 | |
2216 scoped_refptr<SpdySession> session = GetSession(key); | |
2217 | |
2218 SSLConfig ssl_config; | |
2219 scoped_refptr<TransportSocketParams> transport_params( | |
2220 new TransportSocketParams(test_host_port_pair, | |
2221 MEDIUM, | |
2222 false, | |
2223 false, | |
2224 OnHostResolutionCallback())); | |
2225 scoped_refptr<SOCKSSocketParams> socks_params; | |
2226 scoped_refptr<HttpProxySocketParams> http_proxy_params; | |
2227 scoped_refptr<SSLSocketParams> ssl_params( | |
2228 new SSLSocketParams(transport_params, | |
2229 socks_params, | |
2230 http_proxy_params, | |
2231 ProxyServer::SCHEME_DIRECT, | |
2232 test_host_port_pair, | |
2233 ssl_config, | |
2234 0, | |
2235 false, | |
2236 false)); | |
2237 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
2238 EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), | |
2239 ssl_params, MEDIUM, CompletionCallback(), | |
2240 http_session_->GetSSLSocketPool( | |
2241 HttpNetworkSession::NORMAL_SOCKET_POOL), | |
2242 BoundNetLog())); | |
2243 | |
2244 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), true, OK)); | |
2245 EXPECT_TRUE(session->NeedsCredentials()); | |
2246 | |
2247 // Flush the SpdySession::OnReadComplete() task. | |
2248 base::MessageLoop::current()->RunUntilIdle(); | |
2249 | |
2250 spdy_session_pool_->Remove(session); | |
2251 EXPECT_FALSE(spdy_session_pool_->HasSession(key)); | |
2252 } | |
2253 | |
2254 TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) { | |
2255 if (GetParam() < kProtoSPDY3) | |
2256 return; | |
2257 | |
2258 // Set SETTINGS_INITIAL_WINDOW_SIZE to a small number so that WINDOW_UPDATE | |
2259 // gets sent. | |
2260 SettingsMap new_settings; | |
2261 int32 window_size = 1; | |
2262 new_settings[SETTINGS_INITIAL_WINDOW_SIZE] = | |
2263 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, window_size); | |
2264 | |
2265 // Set up the socket so we read a SETTINGS frame that sets | |
2266 // INITIAL_WINDOW_SIZE. | |
2267 MockConnect connect_data(SYNCHRONOUS, OK); | |
2268 scoped_ptr<SpdyFrame> settings_frame( | |
2269 spdy_util_.ConstructSpdySettings(new_settings)); | |
2270 MockRead reads[] = { | |
2271 CreateMockRead(*settings_frame, 0), | |
2272 MockRead(ASYNC, 0, 1) // EOF | |
2273 }; | |
2274 | |
2275 session_deps_.host_resolver->set_synchronous_mode(true); | |
2276 | |
2277 scoped_ptr<DeterministicSocketData> data( | |
2278 new DeterministicSocketData(reads, arraysize(reads), NULL, 0)); | |
2279 data->set_connect_data(connect_data); | |
2280 session_deps_.deterministic_socket_factory->AddSocketDataProvider(data.get()); | |
2281 | |
2282 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
2283 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
2284 | |
2285 CreateDeterministicNetworkSession(); | |
2286 | |
2287 scoped_refptr<SpdySession> session = CreateInitializedSession(); | |
2288 base::WeakPtr<SpdyStream> spdy_stream1 = | |
2289 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, | |
2290 session, test_url_, MEDIUM, BoundNetLog()); | |
2291 ASSERT_TRUE(spdy_stream1.get() != NULL); | |
2292 TestCompletionCallback callback1; | |
2293 EXPECT_NE(spdy_stream1->send_window_size(), window_size); | |
2294 | |
2295 data->RunFor(1); // Process the SETTINGS frame, but not the EOF | |
2296 base::MessageLoop::current()->RunUntilIdle(); | |
2297 EXPECT_EQ(session->stream_initial_send_window_size(), window_size); | |
2298 EXPECT_EQ(spdy_stream1->send_window_size(), window_size); | |
2299 | |
2300 // Release the first one, this will allow the second to be created. | |
2301 spdy_stream1->Cancel(); | |
2302 EXPECT_EQ(NULL, spdy_stream1.get()); | |
2303 | |
2304 base::WeakPtr<SpdyStream> spdy_stream2 = | |
2305 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, | |
2306 session, test_url_, MEDIUM, BoundNetLog()); | |
2307 ASSERT_TRUE(spdy_stream2.get() != NULL); | |
2308 EXPECT_EQ(spdy_stream2->send_window_size(), window_size); | |
2309 spdy_stream2->Cancel(); | |
2310 EXPECT_EQ(NULL, spdy_stream2.get()); | |
2311 } | |
2312 | |
2313 // Test that SpdySession::DoRead reads data from the socket without yielding. | 2185 // Test that SpdySession::DoRead reads data from the socket without yielding. |
2314 // This test makes 32k - 1 bytes of data available on the socket for reading. It | 2186 // This test makes 32k - 1 bytes of data available on the socket for reading. It |
2315 // then verifies that it has read all the available data without yielding. | 2187 // then verifies that it has read all the available data without yielding. |
2316 TEST_P(SpdySessionTest, ReadDataWithoutYielding) { | 2188 TEST_P(SpdySessionTest, ReadDataWithoutYielding) { |
2317 MockConnect connect_data(SYNCHRONOUS, OK); | 2189 MockConnect connect_data(SYNCHRONOUS, OK); |
2318 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | 2190 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
2319 | 2191 |
2320 scoped_ptr<SpdyFrame> req1( | 2192 scoped_ptr<SpdyFrame> req1( |
2321 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); | 2193 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true)); |
2322 MockWrite writes[] = { | 2194 MockWrite writes[] = { |
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2711 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, | 2583 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
2712 session->flow_control_state()); | 2584 session->flow_control_state()); |
2713 EXPECT_EQ(kSpdySessionInitialWindowSize, | 2585 EXPECT_EQ(kSpdySessionInitialWindowSize, |
2714 session->session_send_window_size_); | 2586 session->session_send_window_size_); |
2715 EXPECT_EQ(kSpdySessionInitialWindowSize, | 2587 EXPECT_EQ(kSpdySessionInitialWindowSize, |
2716 session->session_recv_window_size_); | 2588 session->session_recv_window_size_); |
2717 } | 2589 } |
2718 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); | 2590 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); |
2719 } | 2591 } |
2720 | 2592 |
| 2593 // Tests the case of a non-SPDY request closing an idle SPDY session when no |
| 2594 // pointers to the idle session are currently held. |
| 2595 TEST_P(SpdySessionTest, CloseOneIdleConnection) { |
| 2596 ClientSocketPoolManager::set_max_sockets_per_group( |
| 2597 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
| 2598 ClientSocketPoolManager::set_max_sockets_per_pool( |
| 2599 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
| 2600 |
| 2601 MockConnect connect_data(SYNCHRONOUS, OK); |
| 2602 MockRead reads[] = { |
| 2603 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
| 2604 }; |
| 2605 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
| 2606 data.set_connect_data(connect_data); |
| 2607 session_deps_.socket_factory->AddSocketDataProvider(&data); |
| 2608 session_deps_.socket_factory->AddSocketDataProvider(&data); |
| 2609 |
| 2610 CreateNetworkSession(); |
| 2611 |
| 2612 TransportClientSocketPool* pool = |
| 2613 http_session_->GetTransportSocketPool( |
| 2614 HttpNetworkSession::NORMAL_SOCKET_POOL); |
| 2615 |
| 2616 // Create an idle SPDY session. |
| 2617 SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), |
| 2618 kPrivacyModeDisabled); |
| 2619 scoped_refptr<SpdySession> session1 = GetSession(key1); |
| 2620 EXPECT_EQ( |
| 2621 OK, |
| 2622 InitializeSession(http_session_.get(), session1.get(), |
| 2623 key1.host_port_pair())); |
| 2624 EXPECT_FALSE(pool->IsStalled()); |
| 2625 // Release the pointer to the session so it can be closed. |
| 2626 session1 = NULL; |
| 2627 |
| 2628 // Trying to create a new connection should cause the pool to be stalled, and |
| 2629 // post a task asynchronously to try and close the session. |
| 2630 TestCompletionCallback callback2; |
| 2631 HostPortPair host_port2("2.com", 80); |
| 2632 scoped_refptr<TransportSocketParams> params2( |
| 2633 new TransportSocketParams(host_port2, DEFAULT_PRIORITY, false, false, |
| 2634 OnHostResolutionCallback())); |
| 2635 scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle); |
| 2636 EXPECT_EQ(ERR_IO_PENDING, |
| 2637 connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, |
| 2638 callback2.callback(), pool, BoundNetLog())); |
| 2639 EXPECT_TRUE(pool->IsStalled()); |
| 2640 |
| 2641 // The socket pool should close the connection asynchronously and establish a |
| 2642 // new connection. |
| 2643 EXPECT_EQ(OK, callback2.WaitForResult()); |
| 2644 EXPECT_FALSE(pool->IsStalled()); |
| 2645 } |
| 2646 |
| 2647 // Tests the case of a non-SPDY request closing an idle SPDY session when no |
| 2648 // pointers to the idle session are currently held, in the case the SPDY session |
| 2649 // has an alias. |
| 2650 TEST_P(SpdySessionTest, CloseOneIdleConnectionWithAlias) { |
| 2651 ClientSocketPoolManager::set_max_sockets_per_group( |
| 2652 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
| 2653 ClientSocketPoolManager::set_max_sockets_per_pool( |
| 2654 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
| 2655 |
| 2656 MockConnect connect_data(SYNCHRONOUS, OK); |
| 2657 MockRead reads[] = { |
| 2658 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
| 2659 }; |
| 2660 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
| 2661 data.set_connect_data(connect_data); |
| 2662 session_deps_.socket_factory->AddSocketDataProvider(&data); |
| 2663 session_deps_.socket_factory->AddSocketDataProvider(&data); |
| 2664 |
| 2665 session_deps_.host_resolver->set_synchronous_mode(true); |
| 2666 session_deps_.host_resolver->rules()->AddIPLiteralRule( |
| 2667 "1.com", "192.168.0.2", std::string()); |
| 2668 session_deps_.host_resolver->rules()->AddIPLiteralRule( |
| 2669 "2.com", "192.168.0.2", std::string()); |
| 2670 // Not strictly needed. |
| 2671 session_deps_.host_resolver->rules()->AddIPLiteralRule( |
| 2672 "3.com", "192.168.0.3", std::string()); |
| 2673 |
| 2674 CreateNetworkSession(); |
| 2675 |
| 2676 TransportClientSocketPool* pool = |
| 2677 http_session_->GetTransportSocketPool( |
| 2678 HttpNetworkSession::NORMAL_SOCKET_POOL); |
| 2679 |
| 2680 // Create an idle SPDY session. |
| 2681 SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), |
| 2682 kPrivacyModeDisabled); |
| 2683 scoped_refptr<SpdySession> session1 = GetSession(key1); |
| 2684 EXPECT_EQ( |
| 2685 OK, |
| 2686 InitializeSession(http_session_.get(), session1.get(), |
| 2687 key1.host_port_pair())); |
| 2688 EXPECT_FALSE(pool->IsStalled()); |
| 2689 |
| 2690 // Set up an alias for the idle SPDY session, increasing its ref count to 2. |
| 2691 SpdySessionKey key2(HostPortPair("2.com", 80), ProxyServer::Direct(), |
| 2692 kPrivacyModeDisabled); |
| 2693 SpdySessionPoolPeer pool_peer(spdy_session_pool_); |
| 2694 HostResolver::RequestInfo info(key2.host_port_pair()); |
| 2695 AddressList addresses; |
| 2696 // Pre-populate the DNS cache, since a synchronous resolution is required in |
| 2697 // order to create the alias. |
| 2698 session_deps_.host_resolver->Resolve( |
| 2699 info, &addresses, CompletionCallback(), NULL, BoundNetLog()); |
| 2700 // Add the alias for the first session's key. Has to be done manually since |
| 2701 // the usual process is bypassed. |
| 2702 pool_peer.AddAlias(addresses.front(), key1); |
| 2703 // Get a session for |key2|, which should return the session created earlier. |
| 2704 scoped_refptr<SpdySession> session2 = |
| 2705 spdy_session_pool_->Get(key2, BoundNetLog()); |
| 2706 ASSERT_EQ(session1.get(), session2.get()); |
| 2707 EXPECT_FALSE(pool->IsStalled()); |
| 2708 |
| 2709 // Release both the pointers to the session so it can be closed. |
| 2710 session1 = NULL; |
| 2711 session2 = NULL; |
| 2712 |
| 2713 // Trying to create a new connection should cause the pool to be stalled, and |
| 2714 // post a task asynchronously to try and close the session. |
| 2715 TestCompletionCallback callback3; |
| 2716 HostPortPair host_port3("3.com", 80); |
| 2717 scoped_refptr<TransportSocketParams> params3( |
| 2718 new TransportSocketParams(host_port3, DEFAULT_PRIORITY, false, false, |
| 2719 OnHostResolutionCallback())); |
| 2720 scoped_ptr<ClientSocketHandle> connection3(new ClientSocketHandle); |
| 2721 EXPECT_EQ(ERR_IO_PENDING, |
| 2722 connection3->Init(host_port3.ToString(), params3, DEFAULT_PRIORITY, |
| 2723 callback3.callback(), pool, BoundNetLog())); |
| 2724 EXPECT_TRUE(pool->IsStalled()); |
| 2725 |
| 2726 // The socket pool should close the connection asynchronously and establish a |
| 2727 // new connection. |
| 2728 EXPECT_EQ(OK, callback3.WaitForResult()); |
| 2729 EXPECT_FALSE(pool->IsStalled()); |
| 2730 } |
| 2731 |
| 2732 // Tests the case of a non-SPDY request closing an idle SPDY session when a |
| 2733 // pointer to the idle session is still held. |
| 2734 TEST_P(SpdySessionTest, CloseOneIdleConnectionSessionStillHeld) { |
| 2735 ClientSocketPoolManager::set_max_sockets_per_group( |
| 2736 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
| 2737 ClientSocketPoolManager::set_max_sockets_per_pool( |
| 2738 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
| 2739 |
| 2740 MockConnect connect_data(SYNCHRONOUS, OK); |
| 2741 MockRead reads[] = { |
| 2742 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
| 2743 }; |
| 2744 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
| 2745 data.set_connect_data(connect_data); |
| 2746 session_deps_.socket_factory->AddSocketDataProvider(&data); |
| 2747 session_deps_.socket_factory->AddSocketDataProvider(&data); |
| 2748 |
| 2749 CreateNetworkSession(); |
| 2750 |
| 2751 TransportClientSocketPool* pool = |
| 2752 http_session_->GetTransportSocketPool( |
| 2753 HttpNetworkSession::NORMAL_SOCKET_POOL); |
| 2754 |
| 2755 // Create an idle SPDY session. |
| 2756 SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), |
| 2757 kPrivacyModeDisabled); |
| 2758 scoped_refptr<SpdySession> session1 = GetSession(key1); |
| 2759 EXPECT_EQ( |
| 2760 OK, |
| 2761 InitializeSession(http_session_.get(), session1.get(), |
| 2762 key1.host_port_pair())); |
| 2763 EXPECT_FALSE(pool->IsStalled()); |
| 2764 |
| 2765 // Trying to create a new connection should cause the pool to be stalled, and |
| 2766 // post a task asynchronously to try and close the session. |
| 2767 TestCompletionCallback callback2; |
| 2768 HostPortPair host_port2("2.com", 80); |
| 2769 scoped_refptr<TransportSocketParams> params2( |
| 2770 new TransportSocketParams(host_port2, DEFAULT_PRIORITY, false, false, |
| 2771 OnHostResolutionCallback())); |
| 2772 scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle); |
| 2773 EXPECT_EQ(ERR_IO_PENDING, |
| 2774 connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, |
| 2775 callback2.callback(), pool, BoundNetLog())); |
| 2776 EXPECT_TRUE(pool->IsStalled()); |
| 2777 |
| 2778 // Running the message loop should cause the session to prepare to be closed, |
| 2779 // but since there's still an outstanding reference, it should not be closed |
| 2780 // yet. |
| 2781 base::RunLoop().RunUntilIdle(); |
| 2782 EXPECT_TRUE(pool->IsStalled()); |
| 2783 EXPECT_FALSE(callback2.have_result()); |
| 2784 |
| 2785 // Release the pointer to the session so it can be closed. |
| 2786 session1 = NULL; |
| 2787 EXPECT_EQ(OK, callback2.WaitForResult()); |
| 2788 EXPECT_FALSE(pool->IsStalled()); |
| 2789 } |
| 2790 |
| 2791 // Tests that a non-SPDY request can't close a SPDY session that's currently in |
| 2792 // use. |
| 2793 TEST_P(SpdySessionTest, CloseOneIdleConnectionFailsWhenSessionInUse) { |
| 2794 ClientSocketPoolManager::set_max_sockets_per_group( |
| 2795 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
| 2796 ClientSocketPoolManager::set_max_sockets_per_pool( |
| 2797 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); |
| 2798 |
| 2799 MockConnect connect_data(SYNCHRONOUS, OK); |
| 2800 MockRead reads[] = { |
| 2801 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
| 2802 }; |
| 2803 scoped_ptr<SpdyFrame> req1( |
| 2804 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
| 2805 scoped_ptr<SpdyFrame> cancel1( |
| 2806 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); |
| 2807 MockWrite writes[] = { |
| 2808 CreateMockWrite(*req1, 1), |
| 2809 CreateMockWrite(*cancel1, 1), |
| 2810 }; |
| 2811 StaticSocketDataProvider data(reads, arraysize(reads), |
| 2812 writes, arraysize(writes)); |
| 2813 data.set_connect_data(connect_data); |
| 2814 session_deps_.socket_factory->AddSocketDataProvider(&data); |
| 2815 |
| 2816 CreateNetworkSession(); |
| 2817 |
| 2818 TransportClientSocketPool* pool = |
| 2819 http_session_->GetTransportSocketPool( |
| 2820 HttpNetworkSession::NORMAL_SOCKET_POOL); |
| 2821 |
| 2822 // Create a SPDY session. |
| 2823 GURL url1("http://www.google.com"); |
| 2824 SpdySessionKey key1(HostPortPair(url1.host(), 80), |
| 2825 ProxyServer::Direct(), kPrivacyModeDisabled); |
| 2826 scoped_refptr<SpdySession> session1 = GetSession(key1); |
| 2827 EXPECT_EQ( |
| 2828 OK, |
| 2829 InitializeSession(http_session_.get(), session1.get(), |
| 2830 key1.host_port_pair())); |
| 2831 EXPECT_FALSE(pool->IsStalled()); |
| 2832 |
| 2833 // Create a stream using the session, and send a request. |
| 2834 |
| 2835 TestCompletionCallback callback1; |
| 2836 base::WeakPtr<SpdyStream> spdy_stream1 = |
| 2837 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
| 2838 session1, url1, DEFAULT_PRIORITY, |
| 2839 BoundNetLog()); |
| 2840 ASSERT_TRUE(spdy_stream1.get()); |
| 2841 test::StreamDelegateDoNothing delegate1(spdy_stream1); |
| 2842 spdy_stream1->SetDelegate(&delegate1); |
| 2843 |
| 2844 scoped_ptr<SpdyHeaderBlock> headers1( |
| 2845 spdy_util_.ConstructGetHeaderBlock(url1.spec())); |
| 2846 EXPECT_EQ(ERR_IO_PENDING, |
| 2847 spdy_stream1->SendRequestHeaders( |
| 2848 headers1.Pass(), NO_MORE_DATA_TO_SEND)); |
| 2849 EXPECT_TRUE(spdy_stream1->HasUrl()); |
| 2850 |
| 2851 base::MessageLoop::current()->RunUntilIdle(); |
| 2852 |
| 2853 // Release the session, so holding onto a pointer here does not affect |
| 2854 // anything. |
| 2855 session1 = NULL; |
| 2856 |
| 2857 // Trying to create a new connection should cause the pool to be stalled, and |
| 2858 // post a task asynchronously to try and close the session. |
| 2859 TestCompletionCallback callback2; |
| 2860 HostPortPair host_port2("2.com", 80); |
| 2861 scoped_refptr<TransportSocketParams> params2( |
| 2862 new TransportSocketParams(host_port2, DEFAULT_PRIORITY, false, false, |
| 2863 OnHostResolutionCallback())); |
| 2864 scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle); |
| 2865 EXPECT_EQ(ERR_IO_PENDING, |
| 2866 connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, |
| 2867 callback2.callback(), pool, BoundNetLog())); |
| 2868 EXPECT_TRUE(pool->IsStalled()); |
| 2869 |
| 2870 // Running the message loop should cause the socket pool to ask the SPDY |
| 2871 // session to close an idle socket, but since the socket is in use, nothing |
| 2872 // happens. |
| 2873 base::RunLoop().RunUntilIdle(); |
| 2874 EXPECT_TRUE(pool->IsStalled()); |
| 2875 EXPECT_FALSE(callback2.have_result()); |
| 2876 |
| 2877 // Cancelling the request should still not release the session's socket, |
| 2878 // since the session is still kept alive by the SpdySessionPool. |
| 2879 ASSERT_TRUE(spdy_stream1.get()); |
| 2880 spdy_stream1->Cancel(); |
| 2881 base::RunLoop().RunUntilIdle(); |
| 2882 EXPECT_TRUE(pool->IsStalled()); |
| 2883 EXPECT_FALSE(callback2.have_result()); |
| 2884 } |
| 2885 |
| 2886 // Verify that SpdySessionKey and therefore SpdySession is different when |
| 2887 // privacy mode is enabled or disabled. |
| 2888 TEST_P(SpdySessionTest, SpdySessionKeyPrivacyMode) { |
| 2889 CreateDeterministicNetworkSession(); |
| 2890 |
| 2891 HostPortPair host_port_pair("www.google.com", 443); |
| 2892 SpdySessionKey key_privacy_enabled(host_port_pair, ProxyServer::Direct(), |
| 2893 kPrivacyModeEnabled); |
| 2894 SpdySessionKey key_privacy_disabled(host_port_pair, ProxyServer::Direct(), |
| 2895 kPrivacyModeDisabled); |
| 2896 |
| 2897 EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
| 2898 EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
| 2899 |
| 2900 // Add SpdySession with PrivacyMode Enabled to the pool. |
| 2901 scoped_refptr<SpdySession> session_privacy_enabled = |
| 2902 spdy_session_pool_->Get(key_privacy_enabled, BoundNetLog()); |
| 2903 |
| 2904 EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
| 2905 EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
| 2906 |
| 2907 // Add SpdySession with PrivacyMode Disabled to the pool. |
| 2908 scoped_refptr<SpdySession> session_privacy_disabled = |
| 2909 spdy_session_pool_->Get(key_privacy_disabled, BoundNetLog()); |
| 2910 |
| 2911 EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
| 2912 EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
| 2913 |
| 2914 spdy_session_pool_->Remove(session_privacy_enabled); |
| 2915 EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
| 2916 EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
| 2917 |
| 2918 spdy_session_pool_->Remove(session_privacy_disabled); |
| 2919 EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_enabled)); |
| 2920 EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_disabled)); |
| 2921 } |
| 2922 |
| 2923 // The tests below are only for SPDY/3 and above. |
| 2924 |
| 2925 TEST_P(SpdySessionTest, SendCredentials) { |
| 2926 if (GetParam() < kProtoSPDY3) |
| 2927 return; |
| 2928 |
| 2929 MockConnect connect_data(SYNCHRONOUS, OK); |
| 2930 MockRead reads[] = { |
| 2931 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
| 2932 }; |
| 2933 SettingsMap settings; |
| 2934 scoped_ptr<SpdyFrame> settings_frame( |
| 2935 spdy_util_.ConstructSpdySettings(settings)); |
| 2936 MockWrite writes[] = { |
| 2937 CreateMockWrite(*settings_frame), |
| 2938 }; |
| 2939 StaticSocketDataProvider data(reads, arraysize(reads), |
| 2940 writes, arraysize(writes)); |
| 2941 data.set_connect_data(connect_data); |
| 2942 session_deps_.socket_factory->AddSocketDataProvider(&data); |
| 2943 |
| 2944 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); |
| 2945 ssl.channel_id_sent = true; |
| 2946 ssl.protocol_negotiated = GetParam(); |
| 2947 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); |
| 2948 |
| 2949 CreateNetworkSession(); |
| 2950 |
| 2951 const GURL kTestUrl("https://www.foo.com"); |
| 2952 HostPortPair test_host_port_pair(kTestUrl.host(), 443); |
| 2953 SpdySessionKey key(test_host_port_pair, ProxyServer::Direct(), |
| 2954 kPrivacyModeDisabled); |
| 2955 |
| 2956 scoped_refptr<SpdySession> session = GetSession(key); |
| 2957 |
| 2958 SSLConfig ssl_config; |
| 2959 scoped_refptr<TransportSocketParams> transport_params( |
| 2960 new TransportSocketParams(test_host_port_pair, |
| 2961 MEDIUM, |
| 2962 false, |
| 2963 false, |
| 2964 OnHostResolutionCallback())); |
| 2965 scoped_refptr<SOCKSSocketParams> socks_params; |
| 2966 scoped_refptr<HttpProxySocketParams> http_proxy_params; |
| 2967 scoped_refptr<SSLSocketParams> ssl_params( |
| 2968 new SSLSocketParams(transport_params, |
| 2969 socks_params, |
| 2970 http_proxy_params, |
| 2971 ProxyServer::SCHEME_DIRECT, |
| 2972 test_host_port_pair, |
| 2973 ssl_config, |
| 2974 0, |
| 2975 false, |
| 2976 false)); |
| 2977 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); |
| 2978 EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), |
| 2979 ssl_params, MEDIUM, CompletionCallback(), |
| 2980 http_session_->GetSSLSocketPool( |
| 2981 HttpNetworkSession::NORMAL_SOCKET_POOL), |
| 2982 BoundNetLog())); |
| 2983 |
| 2984 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), true, OK)); |
| 2985 EXPECT_TRUE(session->NeedsCredentials()); |
| 2986 |
| 2987 // Flush the SpdySession::OnReadComplete() task. |
| 2988 base::MessageLoop::current()->RunUntilIdle(); |
| 2989 |
| 2990 spdy_session_pool_->Remove(session); |
| 2991 EXPECT_FALSE(spdy_session_pool_->HasSession(key)); |
| 2992 } |
| 2993 |
| 2994 TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) { |
| 2995 if (GetParam() < kProtoSPDY3) |
| 2996 return; |
| 2997 |
| 2998 // Set SETTINGS_INITIAL_WINDOW_SIZE to a small number so that WINDOW_UPDATE |
| 2999 // gets sent. |
| 3000 SettingsMap new_settings; |
| 3001 int32 window_size = 1; |
| 3002 new_settings[SETTINGS_INITIAL_WINDOW_SIZE] = |
| 3003 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, window_size); |
| 3004 |
| 3005 // Set up the socket so we read a SETTINGS frame that sets |
| 3006 // INITIAL_WINDOW_SIZE. |
| 3007 MockConnect connect_data(SYNCHRONOUS, OK); |
| 3008 scoped_ptr<SpdyFrame> settings_frame( |
| 3009 spdy_util_.ConstructSpdySettings(new_settings)); |
| 3010 MockRead reads[] = { |
| 3011 CreateMockRead(*settings_frame, 0), |
| 3012 MockRead(ASYNC, 0, 1) // EOF |
| 3013 }; |
| 3014 |
| 3015 session_deps_.host_resolver->set_synchronous_mode(true); |
| 3016 |
| 3017 scoped_ptr<DeterministicSocketData> data( |
| 3018 new DeterministicSocketData(reads, arraysize(reads), NULL, 0)); |
| 3019 data->set_connect_data(connect_data); |
| 3020 session_deps_.deterministic_socket_factory->AddSocketDataProvider(data.get()); |
| 3021 |
| 3022 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); |
| 3023 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); |
| 3024 |
| 3025 CreateDeterministicNetworkSession(); |
| 3026 |
| 3027 scoped_refptr<SpdySession> session = CreateInitializedSession(); |
| 3028 base::WeakPtr<SpdyStream> spdy_stream1 = |
| 3029 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
| 3030 session, test_url_, MEDIUM, BoundNetLog()); |
| 3031 ASSERT_TRUE(spdy_stream1.get() != NULL); |
| 3032 TestCompletionCallback callback1; |
| 3033 EXPECT_NE(spdy_stream1->send_window_size(), window_size); |
| 3034 |
| 3035 data->RunFor(1); // Process the SETTINGS frame, but not the EOF |
| 3036 base::MessageLoop::current()->RunUntilIdle(); |
| 3037 EXPECT_EQ(session->stream_initial_send_window_size(), window_size); |
| 3038 EXPECT_EQ(spdy_stream1->send_window_size(), window_size); |
| 3039 |
| 3040 // Release the first one, this will allow the second to be created. |
| 3041 spdy_stream1->Cancel(); |
| 3042 EXPECT_EQ(NULL, spdy_stream1.get()); |
| 3043 |
| 3044 base::WeakPtr<SpdyStream> spdy_stream2 = |
| 3045 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, |
| 3046 session, test_url_, MEDIUM, BoundNetLog()); |
| 3047 ASSERT_TRUE(spdy_stream2.get() != NULL); |
| 3048 EXPECT_EQ(spdy_stream2->send_window_size(), window_size); |
| 3049 spdy_stream2->Cancel(); |
| 3050 EXPECT_EQ(NULL, spdy_stream2.get()); |
| 3051 } |
| 3052 |
| 3053 // The tests below are only for SPDY/3.1 and above. |
| 3054 |
2721 // SpdySession::{Increase,Decrease}RecvWindowSize should properly | 3055 // SpdySession::{Increase,Decrease}RecvWindowSize should properly |
2722 // adjust the session receive window size for SPDY 3.1 and higher. In | 3056 // adjust the session receive window size for SPDY 3.1 and higher. In |
2723 // addition, SpdySession::IncreaseRecvWindowSize should trigger | 3057 // addition, SpdySession::IncreaseRecvWindowSize should trigger |
2724 // sending a WINDOW_UPDATE frame for a large enough delta. | 3058 // sending a WINDOW_UPDATE frame for a large enough delta. |
2725 TEST_P(SpdySessionTest, AdjustRecvWindowSize) { | 3059 TEST_P(SpdySessionTest, AdjustRecvWindowSize) { |
2726 if (GetParam() < kProtoSPDY31) | 3060 if (GetParam() < kProtoSPDY31) |
2727 return; | 3061 return; |
2728 | 3062 |
2729 session_deps_.host_resolver->set_synchronous_mode(true); | 3063 session_deps_.host_resolver->set_synchronous_mode(true); |
2730 | 3064 |
(...skipping 704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3435 | 3769 |
3436 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); | 3770 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); |
3437 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); | 3771 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); |
3438 | 3772 |
3439 EXPECT_TRUE(delegate1.send_headers_completed()); | 3773 EXPECT_TRUE(delegate1.send_headers_completed()); |
3440 EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status")); | 3774 EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status")); |
3441 EXPECT_EQ("HTTP/1.1", delegate1.GetResponseHeaderValue(":version")); | 3775 EXPECT_EQ("HTTP/1.1", delegate1.GetResponseHeaderValue(":version")); |
3442 EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); | 3776 EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); |
3443 | 3777 |
3444 EXPECT_TRUE(delegate2.send_headers_completed()); | 3778 EXPECT_TRUE(delegate2.send_headers_completed()); |
3445 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); | |
3446 EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); | |
3447 EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); | |
3448 | |
3449 EXPECT_TRUE(data.at_write_eof()); | |
3450 } | |
3451 | |
3452 // Delegate that closes a given stream after sending its body. | |
3453 class StreamClosingDelegate : public test::StreamDelegateWithBody { | |
3454 public: | |
3455 StreamClosingDelegate(const base::WeakPtr<SpdyStream>& stream, | |
3456 base::StringPiece data) | |
3457 : StreamDelegateWithBody(stream, data) {} | |
3458 | |
3459 virtual ~StreamClosingDelegate() {} | |
3460 | |
3461 void set_stream_to_close(const base::WeakPtr<SpdyStream>& stream_to_close) { | |
3462 stream_to_close_ = stream_to_close; | |
3463 } | |
3464 | |
3465 virtual void OnDataSent() OVERRIDE { | |
3466 test::StreamDelegateWithBody::OnDataSent(); | |
3467 if (stream_to_close_.get()) { | |
3468 stream_to_close_->Close(); | |
3469 EXPECT_EQ(NULL, stream_to_close_.get()); | |
3470 } | |
3471 } | |
3472 | |
3473 private: | |
3474 base::WeakPtr<SpdyStream> stream_to_close_; | |
3475 }; | |
3476 | |
3477 // Cause a stall by reducing the flow control send window to | |
3478 // 0. Unstalling the session should properly handle deleted streams. | |
3479 TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) { | |
3480 if (GetParam() < kProtoSPDY31) | |
3481 return; | |
3482 | |
3483 const char kStreamUrl[] = "http://www.google.com/"; | |
3484 GURL url(kStreamUrl); | |
3485 | |
3486 session_deps_.host_resolver->set_synchronous_mode(true); | |
3487 | |
3488 scoped_ptr<SpdyFrame> req1( | |
3489 spdy_util_.ConstructSpdyPost( | |
3490 kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0)); | |
3491 scoped_ptr<SpdyFrame> req2( | |
3492 spdy_util_.ConstructSpdyPost( | |
3493 kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0)); | |
3494 scoped_ptr<SpdyFrame> req3( | |
3495 spdy_util_.ConstructSpdyPost( | |
3496 kStreamUrl, 5, kBodyDataSize, LOWEST, NULL, 0)); | |
3497 scoped_ptr<SpdyFrame> body2( | |
3498 spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true)); | |
3499 MockWrite writes[] = { | |
3500 CreateMockWrite(*req1, 0), | |
3501 CreateMockWrite(*req2, 1), | |
3502 CreateMockWrite(*req3, 2), | |
3503 CreateMockWrite(*body2, 3), | |
3504 }; | |
3505 | |
3506 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
3507 MockRead reads[] = { | |
3508 CreateMockRead(*resp2, 4), | |
3509 MockRead(ASYNC, 0, 0, 5), // EOF | |
3510 }; | |
3511 | |
3512 DeterministicSocketData data(reads, arraysize(reads), | |
3513 writes, arraysize(writes)); | |
3514 MockConnect connect_data(SYNCHRONOUS, OK); | |
3515 data.set_connect_data(connect_data); | |
3516 | |
3517 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); | |
3518 | |
3519 CreateDeterministicNetworkSession(); | |
3520 scoped_refptr<SpdySession> session = GetSession(key_); | |
3521 InitializeSession( | |
3522 http_session_.get(), session.get(), test_host_port_pair_); | |
3523 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, | |
3524 session->flow_control_state()); | |
3525 | |
3526 base::WeakPtr<SpdyStream> stream1 = | |
3527 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, | |
3528 session, url, LOWEST, BoundNetLog()); | |
3529 ASSERT_TRUE(stream1.get() != NULL); | |
3530 | |
3531 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece); | |
3532 stream1->SetDelegate(&delegate1); | |
3533 | |
3534 EXPECT_FALSE(stream1->HasUrl()); | |
3535 | |
3536 base::WeakPtr<SpdyStream> stream2 = | |
3537 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, | |
3538 session, url, LOWEST, BoundNetLog()); | |
3539 ASSERT_TRUE(stream2.get() != NULL); | |
3540 | |
3541 StreamClosingDelegate delegate2(stream2, kBodyDataStringPiece); | |
3542 stream2->SetDelegate(&delegate2); | |
3543 | |
3544 EXPECT_FALSE(stream2->HasUrl()); | |
3545 | |
3546 base::WeakPtr<SpdyStream> stream3 = | |
3547 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, | |
3548 session, url, LOWEST, BoundNetLog()); | |
3549 ASSERT_TRUE(stream3.get() != NULL); | |
3550 | |
3551 test::StreamDelegateWithBody delegate3(stream3, kBodyDataStringPiece); | |
3552 stream3->SetDelegate(&delegate3); | |
3553 | |
3554 EXPECT_FALSE(stream3->HasUrl()); | |
3555 | |
3556 EXPECT_FALSE(stream1->send_stalled_by_flow_control()); | |
3557 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); | |
3558 EXPECT_FALSE(stream3->send_stalled_by_flow_control()); | |
3559 | |
3560 StallSessionSend(session.get()); | |
3561 | |
3562 scoped_ptr<SpdyHeaderBlock> headers1( | |
3563 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); | |
3564 EXPECT_EQ(ERR_IO_PENDING, | |
3565 stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND)); | |
3566 EXPECT_TRUE(stream1->HasUrl()); | |
3567 EXPECT_EQ(kStreamUrl, stream1->GetUrl().spec()); | |
3568 | |
3569 data.RunFor(1); | |
3570 EXPECT_EQ(1u, stream1->stream_id()); | |
3571 EXPECT_TRUE(stream1->send_stalled_by_flow_control()); | |
3572 | |
3573 scoped_ptr<SpdyHeaderBlock> headers2( | |
3574 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); | |
3575 EXPECT_EQ(ERR_IO_PENDING, | |
3576 stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND)); | |
3577 EXPECT_TRUE(stream2->HasUrl()); | |
3578 EXPECT_EQ(kStreamUrl, stream2->GetUrl().spec()); | |
3579 | |
3580 data.RunFor(1); | |
3581 EXPECT_EQ(3u, stream2->stream_id()); | |
3582 EXPECT_TRUE(stream2->send_stalled_by_flow_control()); | |
3583 | |
3584 scoped_ptr<SpdyHeaderBlock> headers3( | |
3585 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); | |
3586 EXPECT_EQ(ERR_IO_PENDING, | |
3587 stream3->SendRequestHeaders(headers3.Pass(), MORE_DATA_TO_SEND)); | |
3588 EXPECT_TRUE(stream3->HasUrl()); | |
3589 EXPECT_EQ(kStreamUrl, stream3->GetUrl().spec()); | |
3590 | |
3591 data.RunFor(1); | |
3592 EXPECT_EQ(5u, stream3->stream_id()); | |
3593 EXPECT_TRUE(stream3->send_stalled_by_flow_control()); | |
3594 | |
3595 SpdyStreamId stream_id1 = stream1->stream_id(); | |
3596 SpdyStreamId stream_id2 = stream2->stream_id(); | |
3597 SpdyStreamId stream_id3 = stream3->stream_id(); | |
3598 | |
3599 // Close stream1 preemptively. | |
3600 session->CloseActiveStream(stream_id1, ERR_CONNECTION_CLOSED); | |
3601 EXPECT_EQ(NULL, stream1.get()); | |
3602 | |
3603 EXPECT_FALSE(session->IsStreamActive(stream_id1)); | |
3604 EXPECT_TRUE(session->IsStreamActive(stream_id2)); | |
3605 EXPECT_TRUE(session->IsStreamActive(stream_id3)); | |
3606 | |
3607 // Unstall stream2, which should then close stream3. | |
3608 delegate2.set_stream_to_close(stream3); | |
3609 UnstallSessionSend(session.get(), kBodyDataSize); | |
3610 | |
3611 data.RunFor(1); | |
3612 EXPECT_EQ(NULL, stream3.get()); | |
3613 | |
3614 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); | |
3615 EXPECT_FALSE(session->IsStreamActive(stream_id1)); | |
3616 EXPECT_TRUE(session->IsStreamActive(stream_id2)); | |
3617 EXPECT_FALSE(session->IsStreamActive(stream_id3)); | |
3618 | |
3619 data.RunFor(2); | |
3620 EXPECT_EQ(NULL, stream2.get()); | |
3621 | |
3622 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); | |
3623 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); | |
3624 EXPECT_EQ(OK, delegate3.WaitForClose()); | |
3625 | |
3626 EXPECT_TRUE(delegate1.send_headers_completed()); | |
3627 EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); | |
3628 | |
3629 EXPECT_TRUE(delegate2.send_headers_completed()); | |
3630 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); | 3779 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); |
3631 EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); | 3780 EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); |
3632 EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); | 3781 EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); |
3633 | 3782 |
3634 EXPECT_TRUE(delegate3.send_headers_completed()); | |
3635 EXPECT_EQ(std::string(), delegate3.TakeReceivedData()); | |
3636 | |
3637 EXPECT_TRUE(data.at_write_eof()); | 3783 EXPECT_TRUE(data.at_write_eof()); |
3638 } | 3784 } |
3639 | 3785 |
| 3786 // Delegate that closes a given stream after sending its body. |
| 3787 class StreamClosingDelegate : public test::StreamDelegateWithBody { |
| 3788 public: |
| 3789 StreamClosingDelegate(const base::WeakPtr<SpdyStream>& stream, |
| 3790 base::StringPiece data) |
| 3791 : StreamDelegateWithBody(stream, data) {} |
| 3792 |
| 3793 virtual ~StreamClosingDelegate() {} |
| 3794 |
| 3795 void set_stream_to_close(const base::WeakPtr<SpdyStream>& stream_to_close) { |
| 3796 stream_to_close_ = stream_to_close; |
| 3797 } |
| 3798 |
| 3799 virtual void OnDataSent() OVERRIDE { |
| 3800 test::StreamDelegateWithBody::OnDataSent(); |
| 3801 if (stream_to_close_.get()) { |
| 3802 stream_to_close_->Close(); |
| 3803 EXPECT_EQ(NULL, stream_to_close_.get()); |
| 3804 } |
| 3805 } |
| 3806 |
| 3807 private: |
| 3808 base::WeakPtr<SpdyStream> stream_to_close_; |
| 3809 }; |
| 3810 |
3640 // Cause a stall by reducing the flow control send window to | 3811 // Cause a stall by reducing the flow control send window to |
3641 // 0. Unstalling the session should properly handle the session itself | 3812 // 0. Unstalling the session should properly handle deleted streams. |
3642 // being closed. | 3813 TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) { |
3643 TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) { | |
3644 if (GetParam() < kProtoSPDY31) | 3814 if (GetParam() < kProtoSPDY31) |
3645 return; | 3815 return; |
3646 | 3816 |
3647 const char kStreamUrl[] = "http://www.google.com/"; | 3817 const char kStreamUrl[] = "http://www.google.com/"; |
3648 GURL url(kStreamUrl); | 3818 GURL url(kStreamUrl); |
3649 | 3819 |
3650 session_deps_.host_resolver->set_synchronous_mode(true); | 3820 session_deps_.host_resolver->set_synchronous_mode(true); |
3651 | 3821 |
3652 scoped_ptr<SpdyFrame> req1( | 3822 scoped_ptr<SpdyFrame> req1( |
3653 spdy_util_.ConstructSpdyPost( | 3823 spdy_util_.ConstructSpdyPost( |
3654 kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0)); | 3824 kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0)); |
3655 scoped_ptr<SpdyFrame> req2( | 3825 scoped_ptr<SpdyFrame> req2( |
3656 spdy_util_.ConstructSpdyPost( | 3826 spdy_util_.ConstructSpdyPost( |
3657 kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0)); | 3827 kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0)); |
3658 scoped_ptr<SpdyFrame> body1( | 3828 scoped_ptr<SpdyFrame> req3( |
3659 spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false)); | 3829 spdy_util_.ConstructSpdyPost( |
| 3830 kStreamUrl, 5, kBodyDataSize, LOWEST, NULL, 0)); |
| 3831 scoped_ptr<SpdyFrame> body2( |
| 3832 spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true)); |
3660 MockWrite writes[] = { | 3833 MockWrite writes[] = { |
3661 CreateMockWrite(*req1, 0), | 3834 CreateMockWrite(*req1, 0), |
3662 CreateMockWrite(*req2, 1), | 3835 CreateMockWrite(*req2, 1), |
| 3836 CreateMockWrite(*req3, 2), |
| 3837 CreateMockWrite(*body2, 3), |
3663 }; | 3838 }; |
3664 | 3839 |
| 3840 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); |
3665 MockRead reads[] = { | 3841 MockRead reads[] = { |
3666 MockRead(ASYNC, 0, 0, 2), // EOF | 3842 CreateMockRead(*resp2, 4), |
| 3843 MockRead(ASYNC, 0, 0, 5), // EOF |
3667 }; | 3844 }; |
3668 | 3845 |
3669 DeterministicSocketData data(reads, arraysize(reads), | 3846 DeterministicSocketData data(reads, arraysize(reads), |
3670 writes, arraysize(writes)); | 3847 writes, arraysize(writes)); |
3671 MockConnect connect_data(SYNCHRONOUS, OK); | 3848 MockConnect connect_data(SYNCHRONOUS, OK); |
3672 data.set_connect_data(connect_data); | 3849 data.set_connect_data(connect_data); |
3673 | 3850 |
3674 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); | 3851 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
3675 | 3852 |
3676 CreateDeterministicNetworkSession(); | 3853 CreateDeterministicNetworkSession(); |
(...skipping 11 matching lines...) Expand all Loading... |
3688 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece); | 3865 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece); |
3689 stream1->SetDelegate(&delegate1); | 3866 stream1->SetDelegate(&delegate1); |
3690 | 3867 |
3691 EXPECT_FALSE(stream1->HasUrl()); | 3868 EXPECT_FALSE(stream1->HasUrl()); |
3692 | 3869 |
3693 base::WeakPtr<SpdyStream> stream2 = | 3870 base::WeakPtr<SpdyStream> stream2 = |
3694 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, | 3871 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
3695 session, url, LOWEST, BoundNetLog()); | 3872 session, url, LOWEST, BoundNetLog()); |
3696 ASSERT_TRUE(stream2.get() != NULL); | 3873 ASSERT_TRUE(stream2.get() != NULL); |
3697 | 3874 |
3698 test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece); | 3875 StreamClosingDelegate delegate2(stream2, kBodyDataStringPiece); |
3699 stream2->SetDelegate(&delegate2); | 3876 stream2->SetDelegate(&delegate2); |
3700 | 3877 |
3701 EXPECT_FALSE(stream2->HasUrl()); | 3878 EXPECT_FALSE(stream2->HasUrl()); |
3702 | 3879 |
| 3880 base::WeakPtr<SpdyStream> stream3 = |
| 3881 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
| 3882 session, url, LOWEST, BoundNetLog()); |
| 3883 ASSERT_TRUE(stream3.get() != NULL); |
| 3884 |
| 3885 test::StreamDelegateWithBody delegate3(stream3, kBodyDataStringPiece); |
| 3886 stream3->SetDelegate(&delegate3); |
| 3887 |
| 3888 EXPECT_FALSE(stream3->HasUrl()); |
| 3889 |
3703 EXPECT_FALSE(stream1->send_stalled_by_flow_control()); | 3890 EXPECT_FALSE(stream1->send_stalled_by_flow_control()); |
3704 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); | 3891 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); |
| 3892 EXPECT_FALSE(stream3->send_stalled_by_flow_control()); |
3705 | 3893 |
3706 StallSessionSend(session.get()); | 3894 StallSessionSend(session.get()); |
3707 | 3895 |
3708 scoped_ptr<SpdyHeaderBlock> headers1( | 3896 scoped_ptr<SpdyHeaderBlock> headers1( |
3709 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); | 3897 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
3710 EXPECT_EQ(ERR_IO_PENDING, | 3898 EXPECT_EQ(ERR_IO_PENDING, |
3711 stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND)); | 3899 stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND)); |
3712 EXPECT_TRUE(stream1->HasUrl()); | 3900 EXPECT_TRUE(stream1->HasUrl()); |
3713 EXPECT_EQ(kStreamUrl, stream1->GetUrl().spec()); | 3901 EXPECT_EQ(kStreamUrl, stream1->GetUrl().spec()); |
3714 | 3902 |
3715 data.RunFor(1); | 3903 data.RunFor(1); |
3716 EXPECT_EQ(1u, stream1->stream_id()); | 3904 EXPECT_EQ(1u, stream1->stream_id()); |
3717 EXPECT_TRUE(stream1->send_stalled_by_flow_control()); | 3905 EXPECT_TRUE(stream1->send_stalled_by_flow_control()); |
3718 | 3906 |
3719 scoped_ptr<SpdyHeaderBlock> headers2( | 3907 scoped_ptr<SpdyHeaderBlock> headers2( |
3720 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); | 3908 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
3721 EXPECT_EQ(ERR_IO_PENDING, | 3909 EXPECT_EQ(ERR_IO_PENDING, |
3722 stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND)); | 3910 stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND)); |
3723 EXPECT_TRUE(stream2->HasUrl()); | 3911 EXPECT_TRUE(stream2->HasUrl()); |
3724 EXPECT_EQ(kStreamUrl, stream2->GetUrl().spec()); | 3912 EXPECT_EQ(kStreamUrl, stream2->GetUrl().spec()); |
3725 | 3913 |
3726 data.RunFor(1); | 3914 data.RunFor(1); |
3727 EXPECT_EQ(3u, stream2->stream_id()); | 3915 EXPECT_EQ(3u, stream2->stream_id()); |
3728 EXPECT_TRUE(stream2->send_stalled_by_flow_control()); | 3916 EXPECT_TRUE(stream2->send_stalled_by_flow_control()); |
3729 | 3917 |
| 3918 scoped_ptr<SpdyHeaderBlock> headers3( |
| 3919 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
| 3920 EXPECT_EQ(ERR_IO_PENDING, |
| 3921 stream3->SendRequestHeaders(headers3.Pass(), MORE_DATA_TO_SEND)); |
| 3922 EXPECT_TRUE(stream3->HasUrl()); |
| 3923 EXPECT_EQ(kStreamUrl, stream3->GetUrl().spec()); |
| 3924 |
| 3925 data.RunFor(1); |
| 3926 EXPECT_EQ(5u, stream3->stream_id()); |
| 3927 EXPECT_TRUE(stream3->send_stalled_by_flow_control()); |
| 3928 |
| 3929 SpdyStreamId stream_id1 = stream1->stream_id(); |
| 3930 SpdyStreamId stream_id2 = stream2->stream_id(); |
| 3931 SpdyStreamId stream_id3 = stream3->stream_id(); |
| 3932 |
| 3933 // Close stream1 preemptively. |
| 3934 session->CloseActiveStream(stream_id1, ERR_CONNECTION_CLOSED); |
| 3935 EXPECT_EQ(NULL, stream1.get()); |
| 3936 |
| 3937 EXPECT_FALSE(session->IsStreamActive(stream_id1)); |
| 3938 EXPECT_TRUE(session->IsStreamActive(stream_id2)); |
| 3939 EXPECT_TRUE(session->IsStreamActive(stream_id3)); |
| 3940 |
| 3941 // Unstall stream2, which should then close stream3. |
| 3942 delegate2.set_stream_to_close(stream3); |
| 3943 UnstallSessionSend(session.get(), kBodyDataSize); |
| 3944 |
| 3945 data.RunFor(1); |
| 3946 EXPECT_EQ(NULL, stream3.get()); |
| 3947 |
| 3948 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); |
| 3949 EXPECT_FALSE(session->IsStreamActive(stream_id1)); |
| 3950 EXPECT_TRUE(session->IsStreamActive(stream_id2)); |
| 3951 EXPECT_FALSE(session->IsStreamActive(stream_id3)); |
| 3952 |
| 3953 data.RunFor(2); |
| 3954 EXPECT_EQ(NULL, stream2.get()); |
| 3955 |
| 3956 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); |
| 3957 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); |
| 3958 EXPECT_EQ(OK, delegate3.WaitForClose()); |
| 3959 |
| 3960 EXPECT_TRUE(delegate1.send_headers_completed()); |
| 3961 EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); |
| 3962 |
| 3963 EXPECT_TRUE(delegate2.send_headers_completed()); |
| 3964 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status")); |
| 3965 EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version")); |
| 3966 EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); |
| 3967 |
| 3968 EXPECT_TRUE(delegate3.send_headers_completed()); |
| 3969 EXPECT_EQ(std::string(), delegate3.TakeReceivedData()); |
| 3970 |
| 3971 EXPECT_TRUE(data.at_write_eof()); |
| 3972 } |
| 3973 |
| 3974 // Cause a stall by reducing the flow control send window to |
| 3975 // 0. Unstalling the session should properly handle the session itself |
| 3976 // being closed. |
| 3977 TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) { |
| 3978 if (GetParam() < kProtoSPDY31) |
| 3979 return; |
| 3980 |
| 3981 const char kStreamUrl[] = "http://www.google.com/"; |
| 3982 GURL url(kStreamUrl); |
| 3983 |
| 3984 session_deps_.host_resolver->set_synchronous_mode(true); |
| 3985 |
| 3986 scoped_ptr<SpdyFrame> req1( |
| 3987 spdy_util_.ConstructSpdyPost( |
| 3988 kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0)); |
| 3989 scoped_ptr<SpdyFrame> req2( |
| 3990 spdy_util_.ConstructSpdyPost( |
| 3991 kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0)); |
| 3992 scoped_ptr<SpdyFrame> body1( |
| 3993 spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false)); |
| 3994 MockWrite writes[] = { |
| 3995 CreateMockWrite(*req1, 0), |
| 3996 CreateMockWrite(*req2, 1), |
| 3997 }; |
| 3998 |
| 3999 MockRead reads[] = { |
| 4000 MockRead(ASYNC, 0, 0, 2), // EOF |
| 4001 }; |
| 4002 |
| 4003 DeterministicSocketData data(reads, arraysize(reads), |
| 4004 writes, arraysize(writes)); |
| 4005 MockConnect connect_data(SYNCHRONOUS, OK); |
| 4006 data.set_connect_data(connect_data); |
| 4007 |
| 4008 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
| 4009 |
| 4010 CreateDeterministicNetworkSession(); |
| 4011 scoped_refptr<SpdySession> session = GetSession(key_); |
| 4012 InitializeSession( |
| 4013 http_session_.get(), session.get(), test_host_port_pair_); |
| 4014 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, |
| 4015 session->flow_control_state()); |
| 4016 |
| 4017 base::WeakPtr<SpdyStream> stream1 = |
| 4018 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
| 4019 session, url, LOWEST, BoundNetLog()); |
| 4020 ASSERT_TRUE(stream1.get() != NULL); |
| 4021 |
| 4022 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece); |
| 4023 stream1->SetDelegate(&delegate1); |
| 4024 |
| 4025 EXPECT_FALSE(stream1->HasUrl()); |
| 4026 |
| 4027 base::WeakPtr<SpdyStream> stream2 = |
| 4028 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, |
| 4029 session, url, LOWEST, BoundNetLog()); |
| 4030 ASSERT_TRUE(stream2.get() != NULL); |
| 4031 |
| 4032 test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece); |
| 4033 stream2->SetDelegate(&delegate2); |
| 4034 |
| 4035 EXPECT_FALSE(stream2->HasUrl()); |
| 4036 |
| 4037 EXPECT_FALSE(stream1->send_stalled_by_flow_control()); |
| 4038 EXPECT_FALSE(stream2->send_stalled_by_flow_control()); |
| 4039 |
| 4040 StallSessionSend(session.get()); |
| 4041 |
| 4042 scoped_ptr<SpdyHeaderBlock> headers1( |
| 4043 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
| 4044 EXPECT_EQ(ERR_IO_PENDING, |
| 4045 stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND)); |
| 4046 EXPECT_TRUE(stream1->HasUrl()); |
| 4047 EXPECT_EQ(kStreamUrl, stream1->GetUrl().spec()); |
| 4048 |
| 4049 data.RunFor(1); |
| 4050 EXPECT_EQ(1u, stream1->stream_id()); |
| 4051 EXPECT_TRUE(stream1->send_stalled_by_flow_control()); |
| 4052 |
| 4053 scoped_ptr<SpdyHeaderBlock> headers2( |
| 4054 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize)); |
| 4055 EXPECT_EQ(ERR_IO_PENDING, |
| 4056 stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND)); |
| 4057 EXPECT_TRUE(stream2->HasUrl()); |
| 4058 EXPECT_EQ(kStreamUrl, stream2->GetUrl().spec()); |
| 4059 |
| 4060 data.RunFor(1); |
| 4061 EXPECT_EQ(3u, stream2->stream_id()); |
| 4062 EXPECT_TRUE(stream2->send_stalled_by_flow_control()); |
| 4063 |
3730 EXPECT_TRUE(spdy_session_pool_->HasSession(key_)); | 4064 EXPECT_TRUE(spdy_session_pool_->HasSession(key_)); |
3731 | 4065 |
3732 // Unstall stream1. | 4066 // Unstall stream1. |
3733 UnstallSessionSend(session.get(), kBodyDataSize); | 4067 UnstallSessionSend(session.get(), kBodyDataSize); |
3734 | 4068 |
3735 // Close the session (since we can't do it from within the delegate | 4069 // Close the session (since we can't do it from within the delegate |
3736 // method, since it's in the stream's loop). | 4070 // method, since it's in the stream's loop). |
3737 session->CloseSessionOnError(ERR_CONNECTION_CLOSED, true, "Closing session"); | 4071 session->CloseSessionOnError(ERR_CONNECTION_CLOSED, true, "Closing session"); |
3738 session = NULL; | 4072 session = NULL; |
3739 | 4073 |
3740 EXPECT_FALSE(spdy_session_pool_->HasSession(key_)); | 4074 EXPECT_FALSE(spdy_session_pool_->HasSession(key_)); |
3741 | 4075 |
3742 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); | 4076 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose()); |
3743 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); | 4077 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose()); |
3744 | 4078 |
3745 EXPECT_TRUE(delegate1.send_headers_completed()); | 4079 EXPECT_TRUE(delegate1.send_headers_completed()); |
3746 EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); | 4080 EXPECT_EQ(std::string(), delegate1.TakeReceivedData()); |
3747 | 4081 |
3748 EXPECT_TRUE(delegate2.send_headers_completed()); | 4082 EXPECT_TRUE(delegate2.send_headers_completed()); |
3749 EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); | 4083 EXPECT_EQ(std::string(), delegate2.TakeReceivedData()); |
3750 | 4084 |
3751 EXPECT_TRUE(data.at_write_eof()); | 4085 EXPECT_TRUE(data.at_write_eof()); |
3752 } | 4086 } |
3753 | 4087 |
3754 | |
3755 // Tests the case of a non-SPDY request closing an idle SPDY session when no | |
3756 // pointers to the idle session are currently held. | |
3757 TEST_P(SpdySessionTest, CloseOneIdleConnection) { | |
3758 ClientSocketPoolManager::set_max_sockets_per_group( | |
3759 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3760 ClientSocketPoolManager::set_max_sockets_per_pool( | |
3761 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3762 | |
3763 MockConnect connect_data(SYNCHRONOUS, OK); | |
3764 MockRead reads[] = { | |
3765 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
3766 }; | |
3767 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); | |
3768 data.set_connect_data(connect_data); | |
3769 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3770 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3771 | |
3772 CreateNetworkSession(); | |
3773 | |
3774 TransportClientSocketPool* pool = | |
3775 http_session_->GetTransportSocketPool( | |
3776 HttpNetworkSession::NORMAL_SOCKET_POOL); | |
3777 | |
3778 // Create an idle SPDY session. | |
3779 SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), | |
3780 kPrivacyModeDisabled); | |
3781 scoped_refptr<SpdySession> session1 = GetSession(key1); | |
3782 EXPECT_EQ( | |
3783 OK, | |
3784 InitializeSession(http_session_.get(), session1.get(), | |
3785 key1.host_port_pair())); | |
3786 EXPECT_FALSE(pool->IsStalled()); | |
3787 // Release the pointer to the session so it can be closed. | |
3788 session1 = NULL; | |
3789 | |
3790 // Trying to create a new connection should cause the pool to be stalled, and | |
3791 // post a task asynchronously to try and close the session. | |
3792 TestCompletionCallback callback2; | |
3793 HostPortPair host_port2("2.com", 80); | |
3794 scoped_refptr<TransportSocketParams> params2( | |
3795 new TransportSocketParams(host_port2, DEFAULT_PRIORITY, false, false, | |
3796 OnHostResolutionCallback())); | |
3797 scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle); | |
3798 EXPECT_EQ(ERR_IO_PENDING, | |
3799 connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, | |
3800 callback2.callback(), pool, BoundNetLog())); | |
3801 EXPECT_TRUE(pool->IsStalled()); | |
3802 | |
3803 // The socket pool should close the connection asynchronously and establish a | |
3804 // new connection. | |
3805 EXPECT_EQ(OK, callback2.WaitForResult()); | |
3806 EXPECT_FALSE(pool->IsStalled()); | |
3807 } | |
3808 | |
3809 // Tests the case of a non-SPDY request closing an idle SPDY session when no | |
3810 // pointers to the idle session are currently held, in the case the SPDY session | |
3811 // has an alias. | |
3812 TEST_P(SpdySessionTest, CloseOneIdleConnectionWithAlias) { | |
3813 ClientSocketPoolManager::set_max_sockets_per_group( | |
3814 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3815 ClientSocketPoolManager::set_max_sockets_per_pool( | |
3816 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3817 | |
3818 MockConnect connect_data(SYNCHRONOUS, OK); | |
3819 MockRead reads[] = { | |
3820 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
3821 }; | |
3822 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); | |
3823 data.set_connect_data(connect_data); | |
3824 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3825 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3826 | |
3827 session_deps_.host_resolver->set_synchronous_mode(true); | |
3828 session_deps_.host_resolver->rules()->AddIPLiteralRule( | |
3829 "1.com", "192.168.0.2", std::string()); | |
3830 session_deps_.host_resolver->rules()->AddIPLiteralRule( | |
3831 "2.com", "192.168.0.2", std::string()); | |
3832 // Not strictly needed. | |
3833 session_deps_.host_resolver->rules()->AddIPLiteralRule( | |
3834 "3.com", "192.168.0.3", std::string()); | |
3835 | |
3836 CreateNetworkSession(); | |
3837 | |
3838 TransportClientSocketPool* pool = | |
3839 http_session_->GetTransportSocketPool( | |
3840 HttpNetworkSession::NORMAL_SOCKET_POOL); | |
3841 | |
3842 // Create an idle SPDY session. | |
3843 SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), | |
3844 kPrivacyModeDisabled); | |
3845 scoped_refptr<SpdySession> session1 = GetSession(key1); | |
3846 EXPECT_EQ( | |
3847 OK, | |
3848 InitializeSession(http_session_.get(), session1.get(), | |
3849 key1.host_port_pair())); | |
3850 EXPECT_FALSE(pool->IsStalled()); | |
3851 | |
3852 // Set up an alias for the idle SPDY session, increasing its ref count to 2. | |
3853 SpdySessionKey key2(HostPortPair("2.com", 80), ProxyServer::Direct(), | |
3854 kPrivacyModeDisabled); | |
3855 SpdySessionPoolPeer pool_peer(spdy_session_pool_); | |
3856 HostResolver::RequestInfo info(key2.host_port_pair()); | |
3857 AddressList addresses; | |
3858 // Pre-populate the DNS cache, since a synchronous resolution is required in | |
3859 // order to create the alias. | |
3860 session_deps_.host_resolver->Resolve( | |
3861 info, &addresses, CompletionCallback(), NULL, BoundNetLog()); | |
3862 // Add the alias for the first session's key. Has to be done manually since | |
3863 // the usual process is bypassed. | |
3864 pool_peer.AddAlias(addresses.front(), key1); | |
3865 // Get a session for |key2|, which should return the session created earlier. | |
3866 scoped_refptr<SpdySession> session2 = | |
3867 spdy_session_pool_->Get(key2, BoundNetLog()); | |
3868 ASSERT_EQ(session1.get(), session2.get()); | |
3869 EXPECT_FALSE(pool->IsStalled()); | |
3870 | |
3871 // Release both the pointers to the session so it can be closed. | |
3872 session1 = NULL; | |
3873 session2 = NULL; | |
3874 | |
3875 // Trying to create a new connection should cause the pool to be stalled, and | |
3876 // post a task asynchronously to try and close the session. | |
3877 TestCompletionCallback callback3; | |
3878 HostPortPair host_port3("3.com", 80); | |
3879 scoped_refptr<TransportSocketParams> params3( | |
3880 new TransportSocketParams(host_port3, DEFAULT_PRIORITY, false, false, | |
3881 OnHostResolutionCallback())); | |
3882 scoped_ptr<ClientSocketHandle> connection3(new ClientSocketHandle); | |
3883 EXPECT_EQ(ERR_IO_PENDING, | |
3884 connection3->Init(host_port3.ToString(), params3, DEFAULT_PRIORITY, | |
3885 callback3.callback(), pool, BoundNetLog())); | |
3886 EXPECT_TRUE(pool->IsStalled()); | |
3887 | |
3888 // The socket pool should close the connection asynchronously and establish a | |
3889 // new connection. | |
3890 EXPECT_EQ(OK, callback3.WaitForResult()); | |
3891 EXPECT_FALSE(pool->IsStalled()); | |
3892 } | |
3893 | |
3894 // Tests the case of a non-SPDY request closing an idle SPDY session when a | |
3895 // pointer to the idle session is still held. | |
3896 TEST_P(SpdySessionTest, CloseOneIdleConnectionSessionStillHeld) { | |
3897 ClientSocketPoolManager::set_max_sockets_per_group( | |
3898 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3899 ClientSocketPoolManager::set_max_sockets_per_pool( | |
3900 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3901 | |
3902 MockConnect connect_data(SYNCHRONOUS, OK); | |
3903 MockRead reads[] = { | |
3904 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
3905 }; | |
3906 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); | |
3907 data.set_connect_data(connect_data); | |
3908 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3909 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3910 | |
3911 CreateNetworkSession(); | |
3912 | |
3913 TransportClientSocketPool* pool = | |
3914 http_session_->GetTransportSocketPool( | |
3915 HttpNetworkSession::NORMAL_SOCKET_POOL); | |
3916 | |
3917 // Create an idle SPDY session. | |
3918 SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(), | |
3919 kPrivacyModeDisabled); | |
3920 scoped_refptr<SpdySession> session1 = GetSession(key1); | |
3921 EXPECT_EQ( | |
3922 OK, | |
3923 InitializeSession(http_session_.get(), session1.get(), | |
3924 key1.host_port_pair())); | |
3925 EXPECT_FALSE(pool->IsStalled()); | |
3926 | |
3927 // Trying to create a new connection should cause the pool to be stalled, and | |
3928 // post a task asynchronously to try and close the session. | |
3929 TestCompletionCallback callback2; | |
3930 HostPortPair host_port2("2.com", 80); | |
3931 scoped_refptr<TransportSocketParams> params2( | |
3932 new TransportSocketParams(host_port2, DEFAULT_PRIORITY, false, false, | |
3933 OnHostResolutionCallback())); | |
3934 scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle); | |
3935 EXPECT_EQ(ERR_IO_PENDING, | |
3936 connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, | |
3937 callback2.callback(), pool, BoundNetLog())); | |
3938 EXPECT_TRUE(pool->IsStalled()); | |
3939 | |
3940 // Running the message loop should cause the session to prepare to be closed, | |
3941 // but since there's still an outstanding reference, it should not be closed | |
3942 // yet. | |
3943 base::RunLoop().RunUntilIdle(); | |
3944 EXPECT_TRUE(pool->IsStalled()); | |
3945 EXPECT_FALSE(callback2.have_result()); | |
3946 | |
3947 // Release the pointer to the session so it can be closed. | |
3948 session1 = NULL; | |
3949 EXPECT_EQ(OK, callback2.WaitForResult()); | |
3950 EXPECT_FALSE(pool->IsStalled()); | |
3951 } | |
3952 | |
3953 // Tests that a non-SPDY request can't close a SPDY session that's currently in | |
3954 // use. | |
3955 TEST_P(SpdySessionTest, CloseOneIdleConnectionFailsWhenSessionInUse) { | |
3956 ClientSocketPoolManager::set_max_sockets_per_group( | |
3957 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3958 ClientSocketPoolManager::set_max_sockets_per_pool( | |
3959 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
3960 | |
3961 MockConnect connect_data(SYNCHRONOUS, OK); | |
3962 MockRead reads[] = { | |
3963 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
3964 }; | |
3965 scoped_ptr<SpdyFrame> req1( | |
3966 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3967 scoped_ptr<SpdyFrame> cancel1( | |
3968 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
3969 MockWrite writes[] = { | |
3970 CreateMockWrite(*req1, 1), | |
3971 CreateMockWrite(*cancel1, 1), | |
3972 }; | |
3973 StaticSocketDataProvider data(reads, arraysize(reads), | |
3974 writes, arraysize(writes)); | |
3975 data.set_connect_data(connect_data); | |
3976 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
3977 | |
3978 CreateNetworkSession(); | |
3979 | |
3980 TransportClientSocketPool* pool = | |
3981 http_session_->GetTransportSocketPool( | |
3982 HttpNetworkSession::NORMAL_SOCKET_POOL); | |
3983 | |
3984 // Create a SPDY session. | |
3985 GURL url1("http://www.google.com"); | |
3986 SpdySessionKey key1(HostPortPair(url1.host(), 80), | |
3987 ProxyServer::Direct(), kPrivacyModeDisabled); | |
3988 scoped_refptr<SpdySession> session1 = GetSession(key1); | |
3989 EXPECT_EQ( | |
3990 OK, | |
3991 InitializeSession(http_session_.get(), session1.get(), | |
3992 key1.host_port_pair())); | |
3993 EXPECT_FALSE(pool->IsStalled()); | |
3994 | |
3995 // Create a stream using the session, and send a request. | |
3996 | |
3997 TestCompletionCallback callback1; | |
3998 base::WeakPtr<SpdyStream> spdy_stream1 = | |
3999 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, | |
4000 session1, url1, DEFAULT_PRIORITY, | |
4001 BoundNetLog()); | |
4002 ASSERT_TRUE(spdy_stream1.get()); | |
4003 test::StreamDelegateDoNothing delegate1(spdy_stream1); | |
4004 spdy_stream1->SetDelegate(&delegate1); | |
4005 | |
4006 scoped_ptr<SpdyHeaderBlock> headers1( | |
4007 spdy_util_.ConstructGetHeaderBlock(url1.spec())); | |
4008 EXPECT_EQ(ERR_IO_PENDING, | |
4009 spdy_stream1->SendRequestHeaders( | |
4010 headers1.Pass(), NO_MORE_DATA_TO_SEND)); | |
4011 EXPECT_TRUE(spdy_stream1->HasUrl()); | |
4012 | |
4013 base::MessageLoop::current()->RunUntilIdle(); | |
4014 | |
4015 // Release the session, so holding onto a pointer here does not affect | |
4016 // anything. | |
4017 session1 = NULL; | |
4018 | |
4019 // Trying to create a new connection should cause the pool to be stalled, and | |
4020 // post a task asynchronously to try and close the session. | |
4021 TestCompletionCallback callback2; | |
4022 HostPortPair host_port2("2.com", 80); | |
4023 scoped_refptr<TransportSocketParams> params2( | |
4024 new TransportSocketParams(host_port2, DEFAULT_PRIORITY, false, false, | |
4025 OnHostResolutionCallback())); | |
4026 scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle); | |
4027 EXPECT_EQ(ERR_IO_PENDING, | |
4028 connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, | |
4029 callback2.callback(), pool, BoundNetLog())); | |
4030 EXPECT_TRUE(pool->IsStalled()); | |
4031 | |
4032 // Running the message loop should cause the socket pool to ask the SPDY | |
4033 // session to close an idle socket, but since the socket is in use, nothing | |
4034 // happens. | |
4035 base::RunLoop().RunUntilIdle(); | |
4036 EXPECT_TRUE(pool->IsStalled()); | |
4037 EXPECT_FALSE(callback2.have_result()); | |
4038 | |
4039 // Cancelling the request should still not release the session's socket, | |
4040 // since the session is still kept alive by the SpdySessionPool. | |
4041 ASSERT_TRUE(spdy_stream1.get()); | |
4042 spdy_stream1->Cancel(); | |
4043 base::RunLoop().RunUntilIdle(); | |
4044 EXPECT_TRUE(pool->IsStalled()); | |
4045 EXPECT_FALSE(callback2.have_result()); | |
4046 } | |
4047 | |
4048 // Verify that SpdySessionKey and therefore SpdySession is different when | |
4049 // privacy mode is enabled or disabled. | |
4050 TEST_P(SpdySessionTest, SpdySessionKeyPrivacyMode) { | |
4051 CreateDeterministicNetworkSession(); | |
4052 | |
4053 HostPortPair host_port_pair("www.google.com", 443); | |
4054 SpdySessionKey key_privacy_enabled(host_port_pair, ProxyServer::Direct(), | |
4055 kPrivacyModeEnabled); | |
4056 SpdySessionKey key_privacy_disabled(host_port_pair, ProxyServer::Direct(), | |
4057 kPrivacyModeDisabled); | |
4058 | |
4059 EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_enabled)); | |
4060 EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_disabled)); | |
4061 | |
4062 // Add SpdySession with PrivacyMode Enabled to the pool. | |
4063 scoped_refptr<SpdySession> session_privacy_enabled = | |
4064 spdy_session_pool_->Get(key_privacy_enabled, BoundNetLog()); | |
4065 | |
4066 EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_enabled)); | |
4067 EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_disabled)); | |
4068 | |
4069 // Add SpdySession with PrivacyMode Disabled to the pool. | |
4070 scoped_refptr<SpdySession> session_privacy_disabled = | |
4071 spdy_session_pool_->Get(key_privacy_disabled, BoundNetLog()); | |
4072 | |
4073 EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_enabled)); | |
4074 EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_disabled)); | |
4075 | |
4076 spdy_session_pool_->Remove(session_privacy_enabled); | |
4077 EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_enabled)); | |
4078 EXPECT_TRUE(spdy_session_pool_->HasSession(key_privacy_disabled)); | |
4079 | |
4080 spdy_session_pool_->Remove(session_privacy_disabled); | |
4081 EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_enabled)); | |
4082 EXPECT_FALSE(spdy_session_pool_->HasSession(key_privacy_disabled)); | |
4083 } | |
4084 | |
4085 } // namespace net | 4088 } // namespace net |
OLD | NEW |