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