Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: net/spdy/spdy_session_pool_unittest.cc

Issue 2832973003: Split net/spdy into core and chromium subdirectories. (Closed)
Patch Set: Fix some more build rules. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/spdy/spdy_session_pool.cc ('k') | net/spdy/spdy_session_test_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 <memory>
9 #include <utility>
10
11 #include "base/memory/ptr_util.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/run_loop.h"
14 #include "base/test/histogram_tester.h"
15 #include "base/trace_event/memory_allocator_dump.h"
16 #include "base/trace_event/process_memory_dump.h"
17 #include "base/trace_event/trace_event_argument.h"
18 #include "net/dns/host_cache.h"
19 #include "net/http/http_network_session.h"
20 #include "net/log/net_log_with_source.h"
21 #include "net/log/test_net_log.h"
22 #include "net/log/test_net_log_entry.h"
23 #include "net/socket/client_socket_handle.h"
24 #include "net/socket/transport_client_socket_pool.h"
25 #include "net/spdy/spdy_session.h"
26 #include "net/spdy/spdy_stream_test_util.h"
27 #include "net/spdy/spdy_test_util_common.h"
28 #include "net/test/cert_test_util.h"
29 #include "net/test/gtest_util.h"
30 #include "net/test/test_data_directory.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33
34 using net::test::IsError;
35 using net::test::IsOk;
36
37 namespace net {
38
39 class SpdySessionPoolTest : public ::testing::Test {
40 protected:
41 // Used by RunIPPoolingTest().
42 enum SpdyPoolCloseSessionsType {
43 SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
44 SPDY_POOL_CLOSE_CURRENT_SESSIONS,
45 SPDY_POOL_CLOSE_IDLE_SESSIONS,
46 };
47
48 SpdySessionPoolTest() : spdy_session_pool_(NULL) {}
49
50 void CreateNetworkSession() {
51 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
52 spdy_session_pool_ = http_session_->spdy_session_pool();
53 }
54
55 void AddSSLSocketData() {
56 auto ssl = base::MakeUnique<SSLSocketDataProvider>(SYNCHRONOUS, OK);
57 ssl->cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
58 ASSERT_TRUE(ssl->cert);
59 session_deps_.socket_factory->AddSSLSocketDataProvider(ssl.get());
60 ssl_data_vector_.push_back(std::move(ssl));
61 }
62
63 void RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type);
64
65 SpdySessionDependencies session_deps_;
66 std::unique_ptr<HttpNetworkSession> http_session_;
67 SpdySessionPool* spdy_session_pool_;
68 std::vector<std::unique_ptr<SSLSocketDataProvider>> ssl_data_vector_;
69 };
70
71 // A delegate that opens a new session when it is closed.
72 class SessionOpeningDelegate : public SpdyStream::Delegate {
73 public:
74 SessionOpeningDelegate(SpdySessionPool* spdy_session_pool,
75 const SpdySessionKey& key)
76 : spdy_session_pool_(spdy_session_pool),
77 key_(key) {}
78
79 ~SessionOpeningDelegate() override {}
80
81 void OnHeadersSent() override {}
82
83 void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {}
84
85 void OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) override {}
86
87 void OnDataSent() override {}
88
89 void OnTrailers(const SpdyHeaderBlock& trailers) override {}
90
91 void OnClose(int status) override {
92 ignore_result(CreateFakeSpdySession(spdy_session_pool_, key_));
93 }
94
95 NetLogSource source_dependency() const override { return NetLogSource(); }
96
97 private:
98 SpdySessionPool* const spdy_session_pool_;
99 const SpdySessionKey key_;
100 };
101
102 // Set up a SpdyStream to create a new session when it is closed.
103 // CloseCurrentSessions should not close the newly-created session.
104 TEST_F(SpdySessionPoolTest, CloseCurrentSessions) {
105 const char kTestHost[] = "www.foo.com";
106 const int kTestPort = 80;
107
108 session_deps_.host_resolver->set_synchronous_mode(true);
109
110 HostPortPair test_host_port_pair(kTestHost, kTestPort);
111 SpdySessionKey test_key =
112 SpdySessionKey(
113 test_host_port_pair, ProxyServer::Direct(),
114 PRIVACY_MODE_DISABLED);
115
116 MockConnect connect_data(SYNCHRONOUS, OK);
117 MockRead reads[] = {
118 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
119 };
120
121 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
122 data.set_connect_data(connect_data);
123 session_deps_.socket_factory->AddSocketDataProvider(&data);
124
125 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
126 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
127
128 CreateNetworkSession();
129
130 // Setup the first session to the first host.
131 base::WeakPtr<SpdySession> session = CreateSecureSpdySession(
132 http_session_.get(), test_key, NetLogWithSource());
133
134 // Flush the SpdySession::OnReadComplete() task.
135 base::RunLoop().RunUntilIdle();
136
137 // Verify that we have sessions for everything.
138 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
139
140 // Set the stream to create a new session when it is closed.
141 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
142 SPDY_BIDIRECTIONAL_STREAM, session, GURL("http://www.foo.com"), MEDIUM,
143 NetLogWithSource());
144 SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
145 spdy_stream->SetDelegate(&delegate);
146
147 // Close the current session.
148 spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
149
150 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
151 }
152
153 TEST_F(SpdySessionPoolTest, CloseCurrentIdleSessions) {
154 MockConnect connect_data(SYNCHRONOUS, OK);
155 MockRead reads[] = {
156 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
157 };
158
159 session_deps_.host_resolver->set_synchronous_mode(true);
160
161 StaticSocketDataProvider data1(reads, arraysize(reads), nullptr, 0);
162 data1.set_connect_data(connect_data);
163 session_deps_.socket_factory->AddSocketDataProvider(&data1);
164
165 AddSSLSocketData();
166 AddSSLSocketData();
167 AddSSLSocketData();
168
169 CreateNetworkSession();
170
171 // Set up session 1
172 const SpdyString kTestHost1("www.example.org");
173 HostPortPair test_host_port_pair1(kTestHost1, 80);
174 SpdySessionKey key1(test_host_port_pair1, ProxyServer::Direct(),
175 PRIVACY_MODE_DISABLED);
176 base::WeakPtr<SpdySession> session1 =
177 CreateSecureSpdySession(http_session_.get(), key1, NetLogWithSource());
178 GURL url1(kTestHost1);
179 base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
180 SPDY_BIDIRECTIONAL_STREAM, session1, url1, MEDIUM, NetLogWithSource());
181 ASSERT_TRUE(spdy_stream1);
182
183 // Set up session 2
184 StaticSocketDataProvider data2(reads, arraysize(reads), nullptr, 0);
185 data2.set_connect_data(connect_data);
186 session_deps_.socket_factory->AddSocketDataProvider(&data2);
187 const SpdyString kTestHost2("mail.example.org");
188 HostPortPair test_host_port_pair2(kTestHost2, 80);
189 SpdySessionKey key2(test_host_port_pair2, ProxyServer::Direct(),
190 PRIVACY_MODE_DISABLED);
191 base::WeakPtr<SpdySession> session2 =
192 CreateSecureSpdySession(http_session_.get(), key2, NetLogWithSource());
193 GURL url2(kTestHost2);
194 base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
195 SPDY_BIDIRECTIONAL_STREAM, session2, url2, MEDIUM, NetLogWithSource());
196 ASSERT_TRUE(spdy_stream2);
197
198 // Set up session 3
199 StaticSocketDataProvider data3(reads, arraysize(reads), nullptr, 0);
200 data3.set_connect_data(connect_data);
201 session_deps_.socket_factory->AddSocketDataProvider(&data3);
202 const SpdyString kTestHost3("mail.example.com");
203 HostPortPair test_host_port_pair3(kTestHost3, 80);
204 SpdySessionKey key3(test_host_port_pair3, ProxyServer::Direct(),
205 PRIVACY_MODE_DISABLED);
206 base::WeakPtr<SpdySession> session3 =
207 CreateSecureSpdySession(http_session_.get(), key3, NetLogWithSource());
208 GURL url3(kTestHost3);
209 base::WeakPtr<SpdyStream> spdy_stream3 = CreateStreamSynchronously(
210 SPDY_BIDIRECTIONAL_STREAM, session3, url3, MEDIUM, NetLogWithSource());
211 ASSERT_TRUE(spdy_stream3);
212
213 // All sessions are active and not closed
214 EXPECT_TRUE(session1->is_active());
215 EXPECT_TRUE(session1->IsAvailable());
216 EXPECT_TRUE(session2->is_active());
217 EXPECT_TRUE(session2->IsAvailable());
218 EXPECT_TRUE(session3->is_active());
219 EXPECT_TRUE(session3->IsAvailable());
220
221 // Should not do anything, all are active
222 spdy_session_pool_->CloseCurrentIdleSessions();
223 EXPECT_TRUE(session1->is_active());
224 EXPECT_TRUE(session1->IsAvailable());
225 EXPECT_TRUE(session2->is_active());
226 EXPECT_TRUE(session2->IsAvailable());
227 EXPECT_TRUE(session3->is_active());
228 EXPECT_TRUE(session3->IsAvailable());
229
230 // Make sessions 1 and 3 inactive, but keep them open.
231 // Session 2 still open and active
232 session1->CloseCreatedStream(spdy_stream1, OK);
233 EXPECT_FALSE(spdy_stream1);
234 session3->CloseCreatedStream(spdy_stream3, OK);
235 EXPECT_FALSE(spdy_stream3);
236 EXPECT_FALSE(session1->is_active());
237 EXPECT_TRUE(session1->IsAvailable());
238 EXPECT_TRUE(session2->is_active());
239 EXPECT_TRUE(session2->IsAvailable());
240 EXPECT_FALSE(session3->is_active());
241 EXPECT_TRUE(session3->IsAvailable());
242
243 // Should close session 1 and 3, 2 should be left open
244 spdy_session_pool_->CloseCurrentIdleSessions();
245 base::RunLoop().RunUntilIdle();
246
247 EXPECT_FALSE(session1);
248 EXPECT_TRUE(session2->is_active());
249 EXPECT_TRUE(session2->IsAvailable());
250 EXPECT_FALSE(session3);
251
252 // Should not do anything
253 spdy_session_pool_->CloseCurrentIdleSessions();
254 base::RunLoop().RunUntilIdle();
255
256 EXPECT_TRUE(session2->is_active());
257 EXPECT_TRUE(session2->IsAvailable());
258
259 // Make 2 not active
260 session2->CloseCreatedStream(spdy_stream2, OK);
261 base::RunLoop().RunUntilIdle();
262
263 EXPECT_FALSE(spdy_stream2);
264 EXPECT_FALSE(session2->is_active());
265 EXPECT_TRUE(session2->IsAvailable());
266
267 // This should close session 2
268 spdy_session_pool_->CloseCurrentIdleSessions();
269 base::RunLoop().RunUntilIdle();
270
271 EXPECT_FALSE(session2);
272 }
273
274 // Set up a SpdyStream to create a new session when it is closed.
275 // CloseAllSessions should close the newly-created session.
276 TEST_F(SpdySessionPoolTest, CloseAllSessions) {
277 const char kTestHost[] = "www.foo.com";
278 const int kTestPort = 80;
279
280 session_deps_.host_resolver->set_synchronous_mode(true);
281
282 HostPortPair test_host_port_pair(kTestHost, kTestPort);
283 SpdySessionKey test_key =
284 SpdySessionKey(
285 test_host_port_pair, ProxyServer::Direct(),
286 PRIVACY_MODE_DISABLED);
287
288 MockConnect connect_data(SYNCHRONOUS, OK);
289 MockRead reads[] = {
290 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
291 };
292
293 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
294 data.set_connect_data(connect_data);
295 session_deps_.socket_factory->AddSocketDataProvider(&data);
296
297 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
298 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
299
300 CreateNetworkSession();
301
302 // Setup the first session to the first host.
303 base::WeakPtr<SpdySession> session = CreateSecureSpdySession(
304 http_session_.get(), test_key, NetLogWithSource());
305
306 // Flush the SpdySession::OnReadComplete() task.
307 base::RunLoop().RunUntilIdle();
308
309 // Verify that we have sessions for everything.
310 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
311
312 // Set the stream to create a new session when it is closed.
313 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
314 SPDY_BIDIRECTIONAL_STREAM, session, GURL("http://www.foo.com"), MEDIUM,
315 NetLogWithSource());
316 SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
317 spdy_stream->SetDelegate(&delegate);
318
319 // Close the current session.
320 spdy_session_pool_->CloseAllSessions();
321
322 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_key));
323 }
324
325 // This test has three variants, one for each style of closing the connection.
326 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
327 // the sessions are closed manually, calling SpdySessionPool::Remove() directly.
328 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_CURRENT_SESSIONS,
329 // sessions are closed with SpdySessionPool::CloseCurrentSessions().
330 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_IDLE_SESSIONS,
331 // sessions are closed with SpdySessionPool::CloseIdleSessions().
332 void SpdySessionPoolTest::RunIPPoolingTest(
333 SpdyPoolCloseSessionsType close_sessions_type) {
334 const int kTestPort = 80;
335 struct TestHosts {
336 SpdyString url;
337 SpdyString name;
338 SpdyString iplist;
339 SpdySessionKey key;
340 AddressList addresses;
341 } test_hosts[] = {
342 {"http:://www.example.org", "www.example.org",
343 "192.0.2.33,192.168.0.1,192.168.0.5"},
344 {"http://mail.example.org", "mail.example.org",
345 "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"},
346 {"http://mail.example.com", "mail.example.com",
347 "192.168.0.4,192.168.0.3"},
348 };
349
350 session_deps_.host_resolver->set_synchronous_mode(true);
351 std::unique_ptr<HostResolver::Request> request[arraysize(test_hosts)];
352 for (size_t i = 0; i < arraysize(test_hosts); i++) {
353 session_deps_.host_resolver->rules()->AddIPLiteralRule(
354 test_hosts[i].name, test_hosts[i].iplist, SpdyString());
355
356 // This test requires that the HostResolver cache be populated. Normal
357 // code would have done this already, but we do it manually.
358 HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
359 session_deps_.host_resolver->Resolve(
360 info, DEFAULT_PRIORITY, &test_hosts[i].addresses, CompletionCallback(),
361 &request[i], NetLogWithSource());
362
363 // Setup a SpdySessionKey
364 test_hosts[i].key = SpdySessionKey(
365 HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct(),
366 PRIVACY_MODE_DISABLED);
367 }
368
369 MockConnect connect_data(SYNCHRONOUS, OK);
370 MockRead reads[] = {
371 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
372 };
373
374 StaticSocketDataProvider data1(reads, arraysize(reads), NULL, 0);
375 data1.set_connect_data(connect_data);
376 session_deps_.socket_factory->AddSocketDataProvider(&data1);
377
378 AddSSLSocketData();
379
380 CreateNetworkSession();
381
382 // Setup the first session to the first host.
383 base::WeakPtr<SpdySession> session = CreateSecureSpdySession(
384 http_session_.get(), test_hosts[0].key, NetLogWithSource());
385
386 // Flush the SpdySession::OnReadComplete() task.
387 base::RunLoop().RunUntilIdle();
388
389 // The third host has no overlap with the first, so it can't pool IPs.
390 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
391
392 // The second host overlaps with the first, and should IP pool.
393 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
394
395 // However, if IP pooling is disabled, FindAvailableSession() should not find
396 // |session| for the second host.
397 base::WeakPtr<SpdySession> session1 =
398 spdy_session_pool_->FindAvailableSession(
399 test_hosts[1].key, GURL(test_hosts[1].url),
400 /* enable_ip_based_pooling = */ false, NetLogWithSource());
401 EXPECT_FALSE(session1);
402
403 // Verify that the second host, through a proxy, won't share the IP.
404 SpdySessionKey proxy_key(test_hosts[1].key.host_port_pair(),
405 ProxyServer::FromPacString("HTTP http://proxy.foo.com/"),
406 PRIVACY_MODE_DISABLED);
407 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, proxy_key));
408
409 // Overlap between 2 and 3 does is not transitive to 1.
410 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
411
412 // Create a new session to host 2.
413 StaticSocketDataProvider data2(reads, arraysize(reads), NULL, 0);
414 data2.set_connect_data(connect_data);
415 session_deps_.socket_factory->AddSocketDataProvider(&data2);
416
417 AddSSLSocketData();
418
419 base::WeakPtr<SpdySession> session2 = CreateSecureSpdySession(
420 http_session_.get(), test_hosts[2].key, NetLogWithSource());
421
422 // Verify that we have sessions for everything.
423 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
424 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
425 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
426
427 // Grab the session to host 1 and verify that it is the same session
428 // we got with host 0, and that is a different from host 2's session.
429 session1 = spdy_session_pool_->FindAvailableSession(
430 test_hosts[1].key, GURL(test_hosts[1].url),
431 /* enable_ip_based_pooling = */ true, NetLogWithSource());
432 EXPECT_EQ(session.get(), session1.get());
433 EXPECT_NE(session2.get(), session1.get());
434
435 // Remove the aliases and observe that we still have a session for host1.
436 SpdySessionPoolPeer pool_peer(spdy_session_pool_);
437 pool_peer.RemoveAliases(test_hosts[0].key);
438 pool_peer.RemoveAliases(test_hosts[1].key);
439 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
440
441 // Expire the host cache
442 session_deps_.host_resolver->GetHostCache()->clear();
443 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
444
445 // Cleanup the sessions.
446 switch (close_sessions_type) {
447 case SPDY_POOL_CLOSE_SESSIONS_MANUALLY:
448 session->CloseSessionOnError(ERR_ABORTED, SpdyString());
449 session2->CloseSessionOnError(ERR_ABORTED, SpdyString());
450 base::RunLoop().RunUntilIdle();
451 EXPECT_FALSE(session);
452 EXPECT_FALSE(session2);
453 break;
454 case SPDY_POOL_CLOSE_CURRENT_SESSIONS:
455 spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
456 break;
457 case SPDY_POOL_CLOSE_IDLE_SESSIONS:
458 GURL url(test_hosts[0].url);
459 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
460 SPDY_BIDIRECTIONAL_STREAM, session, url, MEDIUM, NetLogWithSource());
461 GURL url1(test_hosts[1].url);
462 base::WeakPtr<SpdyStream> spdy_stream1 =
463 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session1, url1,
464 MEDIUM, NetLogWithSource());
465 GURL url2(test_hosts[2].url);
466 base::WeakPtr<SpdyStream> spdy_stream2 =
467 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session2, url2,
468 MEDIUM, NetLogWithSource());
469
470 // Close streams to make spdy_session and spdy_session1 inactive.
471 session->CloseCreatedStream(spdy_stream, OK);
472 EXPECT_FALSE(spdy_stream);
473 session1->CloseCreatedStream(spdy_stream1, OK);
474 EXPECT_FALSE(spdy_stream1);
475
476 // Check spdy_session and spdy_session1 are not closed.
477 EXPECT_FALSE(session->is_active());
478 EXPECT_TRUE(session->IsAvailable());
479 EXPECT_FALSE(session1->is_active());
480 EXPECT_TRUE(session1->IsAvailable());
481 EXPECT_TRUE(session2->is_active());
482 EXPECT_TRUE(session2->IsAvailable());
483
484 // Test that calling CloseIdleSessions, does not cause a crash.
485 // http://crbug.com/181400
486 spdy_session_pool_->CloseCurrentIdleSessions();
487 base::RunLoop().RunUntilIdle();
488
489 // Verify spdy_session and spdy_session1 are closed.
490 EXPECT_FALSE(session);
491 EXPECT_FALSE(session1);
492 EXPECT_TRUE(session2->is_active());
493 EXPECT_TRUE(session2->IsAvailable());
494
495 spdy_stream2->Cancel();
496 EXPECT_FALSE(spdy_stream);
497 EXPECT_FALSE(spdy_stream1);
498 EXPECT_FALSE(spdy_stream2);
499
500 session2->CloseSessionOnError(ERR_ABORTED, SpdyString());
501 base::RunLoop().RunUntilIdle();
502 EXPECT_FALSE(session2);
503 break;
504 }
505
506 // Verify that the map is all cleaned up.
507 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
508 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
509 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
510 }
511
512 TEST_F(SpdySessionPoolTest, IPPooling) {
513 RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY);
514 }
515
516 TEST_F(SpdySessionPoolTest, IPPoolingCloseCurrentSessions) {
517 RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS);
518 }
519
520 TEST_F(SpdySessionPoolTest, IPPoolingCloseIdleSessions) {
521 RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS);
522 }
523
524 // Regression test for https://crbug.com/643025.
525 TEST_F(SpdySessionPoolTest, IPPoolingNetLog) {
526 // Define two hosts with identical IP address.
527 const int kTestPort = 443;
528 struct TestHosts {
529 SpdyString name;
530 SpdyString iplist;
531 SpdySessionKey key;
532 AddressList addresses;
533 std::unique_ptr<HostResolver::Request> request;
534 } test_hosts[] = {
535 {"www.example.org", "192.168.0.1"}, {"mail.example.org", "192.168.0.1"},
536 };
537
538 // Populate the HostResolver cache.
539 session_deps_.host_resolver->set_synchronous_mode(true);
540 for (size_t i = 0; i < arraysize(test_hosts); i++) {
541 session_deps_.host_resolver->rules()->AddIPLiteralRule(
542 test_hosts[i].name, test_hosts[i].iplist, SpdyString());
543
544 HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
545 session_deps_.host_resolver->Resolve(
546 info, DEFAULT_PRIORITY, &test_hosts[i].addresses, CompletionCallback(),
547 &test_hosts[i].request, NetLogWithSource());
548
549 test_hosts[i].key =
550 SpdySessionKey(HostPortPair(test_hosts[i].name, kTestPort),
551 ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
552 }
553
554 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
555 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
556 MockConnect connect_data(SYNCHRONOUS, OK);
557 data.set_connect_data(connect_data);
558
559 session_deps_.socket_factory->AddSocketDataProvider(&data);
560 AddSSLSocketData();
561
562 CreateNetworkSession();
563
564 // Open SpdySession to the first host.
565 base::WeakPtr<SpdySession> session0 = CreateSecureSpdySession(
566 http_session_.get(), test_hosts[0].key, NetLogWithSource());
567
568 // A request to the second host should pool to the existing connection.
569 BoundTestNetLog net_log;
570 base::HistogramTester histogram_tester;
571 base::WeakPtr<SpdySession> session1 =
572 spdy_session_pool_->FindAvailableSession(
573 test_hosts[1].key, GURL(),
574 /* enable_ip_based_pooling = */ true, net_log.bound());
575 EXPECT_EQ(session0.get(), session1.get());
576
577 ASSERT_EQ(1u, net_log.GetSize());
578 histogram_tester.ExpectTotalCount("Net.SpdySessionGet", 1);
579
580 // A request to the second host should still pool to the existing connection.
581 session1 = spdy_session_pool_->FindAvailableSession(
582 test_hosts[1].key, GURL(),
583 /* enable_ip_based_pooling = */ true, net_log.bound());
584 EXPECT_EQ(session0.get(), session1.get());
585
586 ASSERT_EQ(2u, net_log.GetSize());
587 histogram_tester.ExpectTotalCount("Net.SpdySessionGet", 2);
588
589 // Both FindAvailableSession() calls should log netlog events
590 // indicating IP pooling.
591 TestNetLogEntry::List entry_list;
592 net_log.GetEntries(&entry_list);
593 EXPECT_EQ(
594 NetLogEventType::HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION_FROM_IP_POOL,
595 entry_list[0].type);
596 EXPECT_EQ(
597 NetLogEventType::HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION_FROM_IP_POOL,
598 entry_list[1].type);
599
600 // Both FindAvailableSession() calls should log histogram entries
601 // indicating IP pooling.
602 histogram_tester.ExpectUniqueSample("Net.SpdySessionGet", 2, 2);
603 }
604
605 TEST_F(SpdySessionPoolTest, IPPoolingDisabled) {
606 // Define two hosts with identical IP address.
607 const int kTestPort = 443;
608 struct TestHosts {
609 SpdyString name;
610 SpdyString iplist;
611 SpdySessionKey key;
612 AddressList addresses;
613 std::unique_ptr<HostResolver::Request> request;
614 } test_hosts[] = {
615 {"www.example.org", "192.168.0.1"}, {"mail.example.org", "192.168.0.1"},
616 };
617
618 // Populate the HostResolver cache.
619 session_deps_.host_resolver->set_synchronous_mode(true);
620 for (size_t i = 0; i < arraysize(test_hosts); i++) {
621 session_deps_.host_resolver->rules()->AddIPLiteralRule(
622 test_hosts[i].name, test_hosts[i].iplist, SpdyString());
623
624 HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
625 session_deps_.host_resolver->Resolve(
626 info, DEFAULT_PRIORITY, &test_hosts[i].addresses, CompletionCallback(),
627 &test_hosts[i].request, NetLogWithSource());
628
629 test_hosts[i].key =
630 SpdySessionKey(HostPortPair(test_hosts[i].name, kTestPort),
631 ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
632 }
633
634 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
635 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
636 MockConnect connect_data(SYNCHRONOUS, OK);
637 data.set_connect_data(connect_data);
638 session_deps_.socket_factory->AddSocketDataProvider(&data);
639 AddSSLSocketData();
640
641 MockRead reads1[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
642 StaticSocketDataProvider data1(reads1, arraysize(reads1), nullptr, 0);
643 MockConnect connect_data1(SYNCHRONOUS, OK);
644 data1.set_connect_data(connect_data1);
645 session_deps_.socket_factory->AddSocketDataProvider(&data1);
646 AddSSLSocketData();
647
648 CreateNetworkSession();
649
650 // Open SpdySession to the first host.
651 base::WeakPtr<SpdySession> session0 = CreateSecureSpdySession(
652 http_session_.get(), test_hosts[0].key, NetLogWithSource());
653
654 // A request to the second host should pool to the existing connection.
655 base::WeakPtr<SpdySession> session1 =
656 spdy_session_pool_->FindAvailableSession(
657 test_hosts[1].key, GURL(),
658 /* enable_ip_based_pooling = */ true, NetLogWithSource());
659 EXPECT_EQ(session0.get(), session1.get());
660
661 // A request to the second host should not pool to the existing connection if
662 // IP based pooling is disabled.
663 session1 = spdy_session_pool_->FindAvailableSession(
664 test_hosts[1].key, GURL(),
665 /* enable_ip_based_pooling = */ false, NetLogWithSource());
666 EXPECT_FALSE(session1);
667
668 // It should be possible to open a new SpdySession, even if a previous call to
669 // FindAvailableSession() linked the second key to the first connection in the
670 // IP pooled bucket of SpdySessionPool::available_session_map_.
671 session1 = CreateSecureSpdySessionWithIpBasedPoolingDisabled(
672 http_session_.get(), test_hosts[1].key, NetLogWithSource());
673 EXPECT_TRUE(session1);
674 EXPECT_NE(session0.get(), session1.get());
675 }
676
677 // Construct a Pool with SpdySessions in various availability states. Simulate
678 // an IP address change. Ensure sessions gracefully shut down. Regression test
679 // for crbug.com/379469.
680 TEST_F(SpdySessionPoolTest, IPAddressChanged) {
681 MockConnect connect_data(SYNCHRONOUS, OK);
682 session_deps_.host_resolver->set_synchronous_mode(true);
683
684 // This isn't testing anything having to do with SPDY frames; we
685 // can ignore issues of how dependencies are set. We default to
686 // setting them (when doing the appropriate protocol) since that's
687 // where we're eventually headed for all HTTP/2 connections.
688 SpdyTestUtil spdy_util;
689
690 MockRead reads[] = {
691 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
692 };
693 SpdySerializedFrame req(
694 spdy_util.ConstructSpdyGet("http://www.example.org", 1, MEDIUM));
695 MockWrite writes[] = {CreateMockWrite(req, 1)};
696
697 StaticSocketDataProvider dataA(reads, arraysize(reads), writes,
698 arraysize(writes));
699 dataA.set_connect_data(connect_data);
700 session_deps_.socket_factory->AddSocketDataProvider(&dataA);
701
702 AddSSLSocketData();
703
704 CreateNetworkSession();
705
706 // Set up session A: Going away, but with an active stream.
707 const SpdyString kTestHostA("www.example.org");
708 HostPortPair test_host_port_pairA(kTestHostA, 80);
709 SpdySessionKey keyA(
710 test_host_port_pairA, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
711 base::WeakPtr<SpdySession> sessionA =
712 CreateSecureSpdySession(http_session_.get(), keyA, NetLogWithSource());
713
714 GURL urlA("http://www.example.org");
715 base::WeakPtr<SpdyStream> spdy_streamA = CreateStreamSynchronously(
716 SPDY_BIDIRECTIONAL_STREAM, sessionA, urlA, MEDIUM, NetLogWithSource());
717 test::StreamDelegateDoNothing delegateA(spdy_streamA);
718 spdy_streamA->SetDelegate(&delegateA);
719
720 SpdyHeaderBlock headers(spdy_util.ConstructGetHeaderBlock(urlA.spec()));
721 spdy_streamA->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
722
723 base::RunLoop().RunUntilIdle(); // Allow headers to write.
724 EXPECT_TRUE(delegateA.send_headers_completed());
725
726 sessionA->MakeUnavailable();
727 EXPECT_TRUE(sessionA->IsGoingAway());
728 EXPECT_FALSE(delegateA.StreamIsClosed());
729
730 // Set up session B: Available, with a created stream.
731 StaticSocketDataProvider dataB(reads, arraysize(reads), writes,
732 arraysize(writes));
733 dataB.set_connect_data(connect_data);
734 session_deps_.socket_factory->AddSocketDataProvider(&dataB);
735
736 AddSSLSocketData();
737
738 const SpdyString kTestHostB("mail.example.org");
739 HostPortPair test_host_port_pairB(kTestHostB, 80);
740 SpdySessionKey keyB(
741 test_host_port_pairB, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
742 base::WeakPtr<SpdySession> sessionB =
743 CreateSecureSpdySession(http_session_.get(), keyB, NetLogWithSource());
744 EXPECT_TRUE(sessionB->IsAvailable());
745
746 GURL urlB("http://mail.example.org");
747 base::WeakPtr<SpdyStream> spdy_streamB = CreateStreamSynchronously(
748 SPDY_BIDIRECTIONAL_STREAM, sessionB, urlB, MEDIUM, NetLogWithSource());
749 test::StreamDelegateDoNothing delegateB(spdy_streamB);
750 spdy_streamB->SetDelegate(&delegateB);
751
752 // Set up session C: Draining.
753 StaticSocketDataProvider dataC(reads, arraysize(reads), writes,
754 arraysize(writes));
755 dataC.set_connect_data(connect_data);
756 session_deps_.socket_factory->AddSocketDataProvider(&dataC);
757
758 AddSSLSocketData();
759
760 const SpdyString kTestHostC("mail.example.com");
761 HostPortPair test_host_port_pairC(kTestHostC, 80);
762 SpdySessionKey keyC(
763 test_host_port_pairC, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
764 base::WeakPtr<SpdySession> sessionC =
765 CreateSecureSpdySession(http_session_.get(), keyC, NetLogWithSource());
766
767 sessionC->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Error!");
768 EXPECT_TRUE(sessionC->IsDraining());
769
770 spdy_session_pool_->OnIPAddressChanged();
771
772 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
773 EXPECT_TRUE(sessionA->IsGoingAway());
774 EXPECT_TRUE(sessionB->IsDraining());
775 EXPECT_TRUE(sessionC->IsDraining());
776
777 EXPECT_EQ(1u,
778 sessionA->num_active_streams()); // Active stream is still active.
779 EXPECT_FALSE(delegateA.StreamIsClosed());
780
781 EXPECT_TRUE(delegateB.StreamIsClosed()); // Created stream was closed.
782 EXPECT_THAT(delegateB.WaitForClose(), IsError(ERR_NETWORK_CHANGED));
783
784 sessionA->CloseSessionOnError(ERR_ABORTED, "Closing");
785 sessionB->CloseSessionOnError(ERR_ABORTED, "Closing");
786
787 EXPECT_TRUE(delegateA.StreamIsClosed());
788 EXPECT_THAT(delegateA.WaitForClose(), IsError(ERR_ABORTED));
789 #else
790 EXPECT_TRUE(sessionA->IsDraining());
791 EXPECT_TRUE(sessionB->IsDraining());
792 EXPECT_TRUE(sessionC->IsDraining());
793
794 // Both streams were closed with an error.
795 EXPECT_TRUE(delegateA.StreamIsClosed());
796 EXPECT_THAT(delegateA.WaitForClose(), IsError(ERR_NETWORK_CHANGED));
797 EXPECT_TRUE(delegateB.StreamIsClosed());
798 EXPECT_THAT(delegateB.WaitForClose(), IsError(ERR_NETWORK_CHANGED));
799 #endif // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
800 }
801
802 TEST_F(SpdySessionPoolTest, FindAvailableSession) {
803 SpdySessionKey key(HostPortPair("https://www.example.org", 443),
804 ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
805
806 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
807 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
808 data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
809 session_deps_.socket_factory->AddSocketDataProvider(&data);
810
811 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
812 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
813
814 CreateNetworkSession();
815
816 base::WeakPtr<SpdySession> session =
817 CreateSecureSpdySession(http_session_.get(), key, NetLogWithSource());
818
819 // Flush the SpdySession::OnReadComplete() task.
820 base::RunLoop().RunUntilIdle();
821
822 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key));
823
824 // FindAvailableSession should return |session| if called with empty |url|.
825 base::WeakPtr<SpdySession> session1 =
826 spdy_session_pool_->FindAvailableSession(
827 key, GURL(),
828 /* enable_ip_based_pooling = */ true, NetLogWithSource());
829 EXPECT_EQ(session.get(), session1.get());
830
831 // FindAvailableSession should return |session| if called with |url| for which
832 // there is no pushed stream on any sessions owned by |spdy_session_pool_|.
833 base::WeakPtr<SpdySession> session2 =
834 spdy_session_pool_->FindAvailableSession(
835 key, GURL("http://news.example.org/foo.html"),
836 /* enable_ip_based_pooling = */ true, NetLogWithSource());
837 EXPECT_EQ(session.get(), session2.get());
838
839 spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
840 }
841
842 class SpdySessionMemoryDumpTest
843 : public SpdySessionPoolTest,
844 public testing::WithParamInterface<
845 base::trace_event::MemoryDumpLevelOfDetail> {};
846
847 INSTANTIATE_TEST_CASE_P(
848 /* no prefix */,
849 SpdySessionMemoryDumpTest,
850 ::testing::Values(base::trace_event::MemoryDumpLevelOfDetail::DETAILED,
851 base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND));
852
853 TEST_P(SpdySessionMemoryDumpTest, DumpMemoryStats) {
854 SpdySessionKey key(HostPortPair("https://www.example.org", 443),
855 ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
856
857 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
858 StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
859 data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
860 session_deps_.socket_factory->AddSocketDataProvider(&data);
861
862 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
863 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
864
865 CreateNetworkSession();
866
867 base::WeakPtr<SpdySession> session =
868 CreateSecureSpdySession(http_session_.get(), key, NetLogWithSource());
869
870 // Flush the SpdySession::OnReadComplete() task.
871 base::RunLoop().RunUntilIdle();
872
873 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key));
874 base::trace_event::MemoryDumpArgs dump_args = {GetParam()};
875 std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
876 new base::trace_event::ProcessMemoryDump(nullptr, dump_args));
877 base::trace_event::MemoryAllocatorDump* parent_dump =
878 process_memory_dump->CreateAllocatorDump(
879 "net/http_network_session_0x123");
880 spdy_session_pool_->DumpMemoryStats(process_memory_dump.get(),
881 parent_dump->absolute_name());
882
883 // Whether SpdySession::DumpMemoryStats() is invoked.
884 bool did_dump = false;
885 const base::trace_event::ProcessMemoryDump::AllocatorDumpsMap&
886 allocator_dumps = process_memory_dump->allocator_dumps();
887 for (const auto& pair : allocator_dumps) {
888 const SpdyString& dump_name = pair.first;
889 if (dump_name.find("spdy_session_pool") == SpdyString::npos)
890 continue;
891 std::unique_ptr<base::Value> raw_attrs =
892 pair.second->attributes_for_testing()->ToBaseValue();
893 base::DictionaryValue* attrs;
894 ASSERT_TRUE(raw_attrs->GetAsDictionary(&attrs));
895 base::DictionaryValue* active_session_count_attr;
896 ASSERT_TRUE(attrs->GetDictionary("active_session_count",
897 &active_session_count_attr));
898 SpdyString active_session_count;
899 ASSERT_TRUE(
900 active_session_count_attr->GetString("value", &active_session_count));
901 // No created stream so the session should be idle.
902 ASSERT_EQ("0", active_session_count);
903 did_dump = true;
904 }
905 EXPECT_TRUE(did_dump);
906 spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
907 }
908
909 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/spdy_session_pool.cc ('k') | net/spdy/spdy_session_test_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698