• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/spdy/spdy_session_pool.h"
6 
7 #include <cstddef>
8 #include <string>
9 
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "net/dns/host_cache.h"
13 #include "net/http/http_network_session.h"
14 #include "net/socket/client_socket_handle.h"
15 #include "net/socket/transport_client_socket_pool.h"
16 #include "net/spdy/spdy_session.h"
17 #include "net/spdy/spdy_stream_test_util.h"
18 #include "net/spdy/spdy_test_util_common.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 namespace net {
22 
23 namespace {
24 
25 class SpdySessionPoolTest : public ::testing::Test,
26                             public ::testing::WithParamInterface<NextProto> {
27  protected:
28   // Used by RunIPPoolingTest().
29   enum SpdyPoolCloseSessionsType {
30     SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
31     SPDY_POOL_CLOSE_CURRENT_SESSIONS,
32     SPDY_POOL_CLOSE_IDLE_SESSIONS,
33   };
34 
SpdySessionPoolTest()35   SpdySessionPoolTest()
36       : session_deps_(GetParam()),
37         spdy_session_pool_(NULL) {}
38 
CreateNetworkSession()39   void CreateNetworkSession() {
40     http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
41     spdy_session_pool_ = http_session_->spdy_session_pool();
42   }
43 
44   void RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type);
45 
46   SpdySessionDependencies session_deps_;
47   scoped_refptr<HttpNetworkSession> http_session_;
48   SpdySessionPool* spdy_session_pool_;
49 };
50 
51 INSTANTIATE_TEST_CASE_P(
52     NextProto,
53     SpdySessionPoolTest,
54     testing::Values(kProtoDeprecatedSPDY2,
55                     kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
56 
57 // A delegate that opens a new session when it is closed.
58 class SessionOpeningDelegate : public SpdyStream::Delegate {
59  public:
SessionOpeningDelegate(SpdySessionPool * spdy_session_pool,const SpdySessionKey & key)60   SessionOpeningDelegate(SpdySessionPool* spdy_session_pool,
61                          const SpdySessionKey& key)
62       : spdy_session_pool_(spdy_session_pool),
63         key_(key) {}
64 
~SessionOpeningDelegate()65   virtual ~SessionOpeningDelegate() {}
66 
OnRequestHeadersSent()67   virtual void OnRequestHeadersSent() OVERRIDE {}
68 
OnResponseHeadersUpdated(const SpdyHeaderBlock & response_headers)69   virtual SpdyResponseHeadersStatus OnResponseHeadersUpdated(
70       const SpdyHeaderBlock& response_headers) OVERRIDE {
71     return RESPONSE_HEADERS_ARE_COMPLETE;
72   }
73 
OnDataReceived(scoped_ptr<SpdyBuffer> buffer)74   virtual void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) OVERRIDE {}
75 
OnDataSent()76   virtual void OnDataSent() OVERRIDE {}
77 
OnClose(int status)78   virtual void OnClose(int status) OVERRIDE {
79     ignore_result(CreateFakeSpdySession(spdy_session_pool_, key_));
80   }
81 
82  private:
83   SpdySessionPool* const spdy_session_pool_;
84   const SpdySessionKey key_;
85 };
86 
87 // Set up a SpdyStream to create a new session when it is closed.
88 // CloseCurrentSessions should not close the newly-created session.
TEST_P(SpdySessionPoolTest,CloseCurrentSessions)89 TEST_P(SpdySessionPoolTest, CloseCurrentSessions) {
90   const char kTestHost[] = "www.foo.com";
91   const int kTestPort = 80;
92 
93   session_deps_.host_resolver->set_synchronous_mode(true);
94 
95   HostPortPair test_host_port_pair(kTestHost, kTestPort);
96   SpdySessionKey test_key =
97       SpdySessionKey(
98           test_host_port_pair, ProxyServer::Direct(),
99           PRIVACY_MODE_DISABLED);
100 
101   MockConnect connect_data(SYNCHRONOUS, OK);
102   MockRead reads[] = {
103     MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
104   };
105 
106   StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
107   data.set_connect_data(connect_data);
108   session_deps_.socket_factory->AddSocketDataProvider(&data);
109 
110   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
111   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
112 
113   CreateNetworkSession();
114 
115   // Setup the first session to the first host.
116   base::WeakPtr<SpdySession> session =
117       CreateInsecureSpdySession(http_session_, test_key, BoundNetLog());
118 
119   // Flush the SpdySession::OnReadComplete() task.
120   base::MessageLoop::current()->RunUntilIdle();
121 
122   // Verify that we have sessions for everything.
123   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
124 
125   // Set the stream to create a new session when it is closed.
126   base::WeakPtr<SpdyStream> spdy_stream =
127       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
128                                 session, GURL("http://www.foo.com"),
129                                 MEDIUM, BoundNetLog());
130   SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
131   spdy_stream->SetDelegate(&delegate);
132 
133   // Close the current session.
134   spdy_session_pool_->CloseCurrentSessions(net::ERR_ABORTED);
135 
136   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
137 }
138 
TEST_P(SpdySessionPoolTest,CloseCurrentIdleSessions)139 TEST_P(SpdySessionPoolTest, CloseCurrentIdleSessions) {
140   MockConnect connect_data(SYNCHRONOUS, OK);
141   MockRead reads[] = {
142       MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
143   };
144 
145   session_deps_.host_resolver->set_synchronous_mode(true);
146 
147   StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
148   data.set_connect_data(connect_data);
149   session_deps_.socket_factory->AddSocketDataProvider(&data);
150 
151   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
152   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
153 
154   CreateNetworkSession();
155 
156   // Set up session 1
157   const std::string kTestHost1("http://www.a.com");
158   HostPortPair test_host_port_pair1(kTestHost1, 80);
159   SpdySessionKey key1(test_host_port_pair1, ProxyServer::Direct(),
160                       PRIVACY_MODE_DISABLED);
161   base::WeakPtr<SpdySession> session1 =
162       CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
163   GURL url1(kTestHost1);
164   base::WeakPtr<SpdyStream> spdy_stream1 =
165       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
166                                 session1, url1, MEDIUM, BoundNetLog());
167   ASSERT_TRUE(spdy_stream1.get() != NULL);
168 
169   // Set up session 2
170   session_deps_.socket_factory->AddSocketDataProvider(&data);
171   const std::string kTestHost2("http://www.b.com");
172   HostPortPair test_host_port_pair2(kTestHost2, 80);
173   SpdySessionKey key2(test_host_port_pair2, ProxyServer::Direct(),
174                       PRIVACY_MODE_DISABLED);
175   base::WeakPtr<SpdySession> session2 =
176       CreateInsecureSpdySession(http_session_, key2, BoundNetLog());
177   GURL url2(kTestHost2);
178   base::WeakPtr<SpdyStream> spdy_stream2 =
179       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
180                                 session2, url2, MEDIUM, BoundNetLog());
181   ASSERT_TRUE(spdy_stream2.get() != NULL);
182 
183   // Set up session 3
184   session_deps_.socket_factory->AddSocketDataProvider(&data);
185   const std::string kTestHost3("http://www.c.com");
186   HostPortPair test_host_port_pair3(kTestHost3, 80);
187   SpdySessionKey key3(test_host_port_pair3, ProxyServer::Direct(),
188                       PRIVACY_MODE_DISABLED);
189   base::WeakPtr<SpdySession> session3 =
190       CreateInsecureSpdySession(http_session_, key3, BoundNetLog());
191   GURL url3(kTestHost3);
192   base::WeakPtr<SpdyStream> spdy_stream3 =
193       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
194                                 session3, url3, MEDIUM, BoundNetLog());
195   ASSERT_TRUE(spdy_stream3.get() != NULL);
196 
197   // All sessions are active and not closed
198   EXPECT_TRUE(session1->is_active());
199   EXPECT_TRUE(session1->IsAvailable());
200   EXPECT_TRUE(session2->is_active());
201   EXPECT_TRUE(session2->IsAvailable());
202   EXPECT_TRUE(session3->is_active());
203   EXPECT_TRUE(session3->IsAvailable());
204 
205   // Should not do anything, all are active
206   spdy_session_pool_->CloseCurrentIdleSessions();
207   EXPECT_TRUE(session1->is_active());
208   EXPECT_TRUE(session1->IsAvailable());
209   EXPECT_TRUE(session2->is_active());
210   EXPECT_TRUE(session2->IsAvailable());
211   EXPECT_TRUE(session3->is_active());
212   EXPECT_TRUE(session3->IsAvailable());
213 
214   // Make sessions 1 and 3 inactive, but keep them open.
215   // Session 2 still open and active
216   session1->CloseCreatedStream(spdy_stream1, OK);
217   EXPECT_EQ(NULL, spdy_stream1.get());
218   session3->CloseCreatedStream(spdy_stream3, OK);
219   EXPECT_EQ(NULL, spdy_stream3.get());
220   EXPECT_FALSE(session1->is_active());
221   EXPECT_TRUE(session1->IsAvailable());
222   EXPECT_TRUE(session2->is_active());
223   EXPECT_TRUE(session2->IsAvailable());
224   EXPECT_FALSE(session3->is_active());
225   EXPECT_TRUE(session3->IsAvailable());
226 
227   // Should close session 1 and 3, 2 should be left open
228   spdy_session_pool_->CloseCurrentIdleSessions();
229   base::MessageLoop::current()->RunUntilIdle();
230 
231   EXPECT_TRUE(session1 == NULL);
232   EXPECT_TRUE(session2->is_active());
233   EXPECT_TRUE(session2->IsAvailable());
234   EXPECT_TRUE(session3 == NULL);
235 
236   // Should not do anything
237   spdy_session_pool_->CloseCurrentIdleSessions();
238   base::MessageLoop::current()->RunUntilIdle();
239 
240   EXPECT_TRUE(session2->is_active());
241   EXPECT_TRUE(session2->IsAvailable());
242 
243   // Make 2 not active
244   session2->CloseCreatedStream(spdy_stream2, OK);
245   base::MessageLoop::current()->RunUntilIdle();
246 
247   EXPECT_EQ(NULL, spdy_stream2.get());
248   EXPECT_FALSE(session2->is_active());
249   EXPECT_TRUE(session2->IsAvailable());
250 
251   // This should close session 2
252   spdy_session_pool_->CloseCurrentIdleSessions();
253   base::MessageLoop::current()->RunUntilIdle();
254 
255   EXPECT_TRUE(session2 == NULL);
256 }
257 
258 // Set up a SpdyStream to create a new session when it is closed.
259 // CloseAllSessions should close the newly-created session.
TEST_P(SpdySessionPoolTest,CloseAllSessions)260 TEST_P(SpdySessionPoolTest, CloseAllSessions) {
261   const char kTestHost[] = "www.foo.com";
262   const int kTestPort = 80;
263 
264   session_deps_.host_resolver->set_synchronous_mode(true);
265 
266   HostPortPair test_host_port_pair(kTestHost, kTestPort);
267   SpdySessionKey test_key =
268       SpdySessionKey(
269           test_host_port_pair, ProxyServer::Direct(),
270           PRIVACY_MODE_DISABLED);
271 
272   MockConnect connect_data(SYNCHRONOUS, OK);
273   MockRead reads[] = {
274     MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
275   };
276 
277   StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
278   data.set_connect_data(connect_data);
279   session_deps_.socket_factory->AddSocketDataProvider(&data);
280 
281   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
282   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
283 
284   CreateNetworkSession();
285 
286   // Setup the first session to the first host.
287   base::WeakPtr<SpdySession> session =
288       CreateInsecureSpdySession(http_session_, test_key, BoundNetLog());
289 
290   // Flush the SpdySession::OnReadComplete() task.
291   base::MessageLoop::current()->RunUntilIdle();
292 
293   // Verify that we have sessions for everything.
294   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
295 
296   // Set the stream to create a new session when it is closed.
297   base::WeakPtr<SpdyStream> spdy_stream =
298       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
299                                 session, GURL("http://www.foo.com"),
300                                 MEDIUM, BoundNetLog());
301   SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
302   spdy_stream->SetDelegate(&delegate);
303 
304   // Close the current session.
305   spdy_session_pool_->CloseAllSessions();
306 
307   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_key));
308 }
309 
310 // This test has three variants, one for each style of closing the connection.
311 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
312 // the sessions are closed manually, calling SpdySessionPool::Remove() directly.
313 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_CURRENT_SESSIONS,
314 // sessions are closed with SpdySessionPool::CloseCurrentSessions().
315 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_IDLE_SESSIONS,
316 // sessions are closed with SpdySessionPool::CloseIdleSessions().
RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type)317 void SpdySessionPoolTest::RunIPPoolingTest(
318     SpdyPoolCloseSessionsType close_sessions_type) {
319   const int kTestPort = 80;
320   struct TestHosts {
321     std::string url;
322     std::string name;
323     std::string iplist;
324     SpdySessionKey key;
325     AddressList addresses;
326   } test_hosts[] = {
327     { "http:://www.foo.com",
328       "www.foo.com",
329       "192.0.2.33,192.168.0.1,192.168.0.5"
330     },
331     { "http://js.foo.com",
332       "js.foo.com",
333       "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"
334     },
335     { "http://images.foo.com",
336       "images.foo.com",
337       "192.168.0.4,192.168.0.3"
338     },
339   };
340 
341   session_deps_.host_resolver->set_synchronous_mode(true);
342   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_hosts); i++) {
343     session_deps_.host_resolver->rules()->AddIPLiteralRule(
344         test_hosts[i].name, test_hosts[i].iplist, std::string());
345 
346     // This test requires that the HostResolver cache be populated.  Normal
347     // code would have done this already, but we do it manually.
348     HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
349     session_deps_.host_resolver->Resolve(info,
350                                          DEFAULT_PRIORITY,
351                                          &test_hosts[i].addresses,
352                                          CompletionCallback(),
353                                          NULL,
354                                          BoundNetLog());
355 
356     // Setup a SpdySessionKey
357     test_hosts[i].key = SpdySessionKey(
358         HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct(),
359         PRIVACY_MODE_DISABLED);
360   }
361 
362   MockConnect connect_data(SYNCHRONOUS, OK);
363   MockRead reads[] = {
364     MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
365   };
366 
367   StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
368   data.set_connect_data(connect_data);
369   session_deps_.socket_factory->AddSocketDataProvider(&data);
370 
371   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
372   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
373 
374   CreateNetworkSession();
375 
376   // Setup the first session to the first host.
377   base::WeakPtr<SpdySession> session =
378       CreateInsecureSpdySession(
379           http_session_, test_hosts[0].key, BoundNetLog());
380 
381   // Flush the SpdySession::OnReadComplete() task.
382   base::MessageLoop::current()->RunUntilIdle();
383 
384   // The third host has no overlap with the first, so it can't pool IPs.
385   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
386 
387   // The second host overlaps with the first, and should IP pool.
388   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
389 
390   // Verify that the second host, through a proxy, won't share the IP.
391   SpdySessionKey proxy_key(test_hosts[1].key.host_port_pair(),
392       ProxyServer::FromPacString("HTTP http://proxy.foo.com/"),
393       PRIVACY_MODE_DISABLED);
394   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, proxy_key));
395 
396   // Overlap between 2 and 3 does is not transitive to 1.
397   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
398 
399   // Create a new session to host 2.
400   session_deps_.socket_factory->AddSocketDataProvider(&data);
401   base::WeakPtr<SpdySession> session2 =
402       CreateInsecureSpdySession(
403           http_session_, test_hosts[2].key, BoundNetLog());
404 
405   // Verify that we have sessions for everything.
406   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
407   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
408   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
409 
410   // Grab the session to host 1 and verify that it is the same session
411   // we got with host 0, and that is a different from host 2's session.
412   base::WeakPtr<SpdySession> session1 =
413       spdy_session_pool_->FindAvailableSession(
414           test_hosts[1].key, BoundNetLog());
415   EXPECT_EQ(session.get(), session1.get());
416   EXPECT_NE(session2.get(), session1.get());
417 
418   // Remove the aliases and observe that we still have a session for host1.
419   SpdySessionPoolPeer pool_peer(spdy_session_pool_);
420   pool_peer.RemoveAliases(test_hosts[0].key);
421   pool_peer.RemoveAliases(test_hosts[1].key);
422   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
423 
424   // Expire the host cache
425   session_deps_.host_resolver->GetHostCache()->clear();
426   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
427 
428   // Cleanup the sessions.
429   switch (close_sessions_type) {
430     case SPDY_POOL_CLOSE_SESSIONS_MANUALLY:
431       session->CloseSessionOnError(ERR_ABORTED, std::string());
432       session2->CloseSessionOnError(ERR_ABORTED, std::string());
433       base::MessageLoop::current()->RunUntilIdle();
434       EXPECT_TRUE(session == NULL);
435       EXPECT_TRUE(session2 == NULL);
436       break;
437     case SPDY_POOL_CLOSE_CURRENT_SESSIONS:
438       spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
439       break;
440     case SPDY_POOL_CLOSE_IDLE_SESSIONS:
441       GURL url(test_hosts[0].url);
442       base::WeakPtr<SpdyStream> spdy_stream =
443           CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
444                                     session, url, MEDIUM, BoundNetLog());
445       GURL url1(test_hosts[1].url);
446       base::WeakPtr<SpdyStream> spdy_stream1 =
447           CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
448                                     session1, url1, MEDIUM, BoundNetLog());
449       GURL url2(test_hosts[2].url);
450       base::WeakPtr<SpdyStream> spdy_stream2 =
451           CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
452                                     session2, url2, MEDIUM, BoundNetLog());
453 
454       // Close streams to make spdy_session and spdy_session1 inactive.
455       session->CloseCreatedStream(spdy_stream, OK);
456       EXPECT_EQ(NULL, spdy_stream.get());
457       session1->CloseCreatedStream(spdy_stream1, OK);
458       EXPECT_EQ(NULL, spdy_stream1.get());
459 
460       // Check spdy_session and spdy_session1 are not closed.
461       EXPECT_FALSE(session->is_active());
462       EXPECT_TRUE(session->IsAvailable());
463       EXPECT_FALSE(session1->is_active());
464       EXPECT_TRUE(session1->IsAvailable());
465       EXPECT_TRUE(session2->is_active());
466       EXPECT_TRUE(session2->IsAvailable());
467 
468       // Test that calling CloseIdleSessions, does not cause a crash.
469       // http://crbug.com/181400
470       spdy_session_pool_->CloseCurrentIdleSessions();
471       base::MessageLoop::current()->RunUntilIdle();
472 
473       // Verify spdy_session and spdy_session1 are closed.
474       EXPECT_TRUE(session == NULL);
475       EXPECT_TRUE(session1 == NULL);
476       EXPECT_TRUE(session2->is_active());
477       EXPECT_TRUE(session2->IsAvailable());
478 
479       spdy_stream2->Cancel();
480       EXPECT_EQ(NULL, spdy_stream.get());
481       EXPECT_EQ(NULL, spdy_stream1.get());
482       EXPECT_EQ(NULL, spdy_stream2.get());
483 
484       session2->CloseSessionOnError(ERR_ABORTED, std::string());
485       base::MessageLoop::current()->RunUntilIdle();
486       EXPECT_TRUE(session2 == NULL);
487       break;
488   }
489 
490   // Verify that the map is all cleaned up.
491   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
492   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
493   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
494 }
495 
TEST_P(SpdySessionPoolTest,IPPooling)496 TEST_P(SpdySessionPoolTest, IPPooling) {
497   RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY);
498 }
499 
TEST_P(SpdySessionPoolTest,IPPoolingCloseCurrentSessions)500 TEST_P(SpdySessionPoolTest, IPPoolingCloseCurrentSessions) {
501   RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS);
502 }
503 
TEST_P(SpdySessionPoolTest,IPPoolingCloseIdleSessions)504 TEST_P(SpdySessionPoolTest, IPPoolingCloseIdleSessions) {
505   RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS);
506 }
507 
508 // Construct a Pool with SpdySessions in various availability states. Simulate
509 // an IP address change. Ensure sessions gracefully shut down. Regression test
510 // for crbug.com/379469.
TEST_P(SpdySessionPoolTest,IPAddressChanged)511 TEST_P(SpdySessionPoolTest, IPAddressChanged) {
512   MockConnect connect_data(SYNCHRONOUS, OK);
513   session_deps_.host_resolver->set_synchronous_mode(true);
514   SpdyTestUtil spdy_util(GetParam());
515 
516   MockRead reads[] = {
517       MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
518   };
519   scoped_ptr<SpdyFrame> req(
520       spdy_util.ConstructSpdyGet("http://www.a.com", false, 1, MEDIUM));
521   MockWrite writes[] = {CreateMockWrite(*req, 1)};
522 
523   DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
524   data.set_connect_data(connect_data);
525   session_deps_.socket_factory->AddSocketDataProvider(&data);
526 
527   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
528   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
529 
530   CreateNetworkSession();
531 
532   // Set up session A: Going away, but with an active stream.
533   session_deps_.socket_factory->AddSocketDataProvider(&data);
534   const std::string kTestHostA("http://www.a.com");
535   HostPortPair test_host_port_pairA(kTestHostA, 80);
536   SpdySessionKey keyA(
537       test_host_port_pairA, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
538   base::WeakPtr<SpdySession> sessionA =
539       CreateInsecureSpdySession(http_session_, keyA, BoundNetLog());
540 
541   GURL urlA(kTestHostA);
542   base::WeakPtr<SpdyStream> spdy_streamA = CreateStreamSynchronously(
543       SPDY_BIDIRECTIONAL_STREAM, sessionA, urlA, MEDIUM, BoundNetLog());
544   test::StreamDelegateDoNothing delegateA(spdy_streamA);
545   spdy_streamA->SetDelegate(&delegateA);
546 
547   scoped_ptr<SpdyHeaderBlock> headers(
548       spdy_util.ConstructGetHeaderBlock(urlA.spec()));
549   spdy_streamA->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
550   EXPECT_TRUE(spdy_streamA->HasUrlFromHeaders());
551 
552   base::MessageLoop::current()->RunUntilIdle();  // Allow headers to write.
553   EXPECT_TRUE(delegateA.send_headers_completed());
554 
555   sessionA->MakeUnavailable();
556   EXPECT_TRUE(sessionA->IsGoingAway());
557   EXPECT_FALSE(delegateA.StreamIsClosed());
558 
559   // Set up session B: Available, with a created stream.
560   const std::string kTestHostB("http://www.b.com");
561   HostPortPair test_host_port_pairB(kTestHostB, 80);
562   SpdySessionKey keyB(
563       test_host_port_pairB, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
564   base::WeakPtr<SpdySession> sessionB =
565       CreateInsecureSpdySession(http_session_, keyB, BoundNetLog());
566   EXPECT_TRUE(sessionB->IsAvailable());
567 
568   GURL urlB(kTestHostB);
569   base::WeakPtr<SpdyStream> spdy_streamB = CreateStreamSynchronously(
570       SPDY_BIDIRECTIONAL_STREAM, sessionB, urlB, MEDIUM, BoundNetLog());
571   test::StreamDelegateDoNothing delegateB(spdy_streamB);
572   spdy_streamB->SetDelegate(&delegateB);
573 
574   // Set up session C: Draining.
575   session_deps_.socket_factory->AddSocketDataProvider(&data);
576   const std::string kTestHostC("http://www.c.com");
577   HostPortPair test_host_port_pairC(kTestHostC, 80);
578   SpdySessionKey keyC(
579       test_host_port_pairC, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
580   base::WeakPtr<SpdySession> sessionC =
581       CreateInsecureSpdySession(http_session_, keyC, BoundNetLog());
582 
583   sessionC->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Error!");
584   EXPECT_TRUE(sessionC->IsDraining());
585 
586   spdy_session_pool_->OnIPAddressChanged();
587 
588 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
589   EXPECT_TRUE(sessionA->IsGoingAway());
590   EXPECT_TRUE(sessionB->IsDraining());
591   EXPECT_TRUE(sessionC->IsDraining());
592 
593   EXPECT_EQ(1u,
594             sessionA->num_active_streams());  // Active stream is still active.
595   EXPECT_FALSE(delegateA.StreamIsClosed());
596 
597   EXPECT_TRUE(delegateB.StreamIsClosed());  // Created stream was closed.
598   EXPECT_EQ(ERR_NETWORK_CHANGED, delegateB.WaitForClose());
599 
600   sessionA->CloseSessionOnError(ERR_ABORTED, "Closing");
601   sessionB->CloseSessionOnError(ERR_ABORTED, "Closing");
602 
603   EXPECT_TRUE(delegateA.StreamIsClosed());
604   EXPECT_EQ(ERR_ABORTED, delegateA.WaitForClose());
605 #else
606   EXPECT_TRUE(sessionA->IsDraining());
607   EXPECT_TRUE(sessionB->IsDraining());
608   EXPECT_TRUE(sessionC->IsDraining());
609 
610   // Both streams were closed with an error.
611   EXPECT_TRUE(delegateA.StreamIsClosed());
612   EXPECT_EQ(ERR_NETWORK_CHANGED, delegateA.WaitForClose());
613   EXPECT_TRUE(delegateB.StreamIsClosed());
614   EXPECT_EQ(ERR_NETWORK_CHANGED, delegateB.WaitForClose());
615 #endif  // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
616 }
617 
618 }  // namespace
619 
620 }  // namespace net
621