1 // Copyright 2013 The Chromium Authors
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 <tuple>
9 #include <utility>
10
11 #include "base/functional/bind.h"
12 #include "base/functional/callback.h"
13 #include "base/memory/raw_ptr.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/run_loop.h"
16 #include "base/test/bind.h"
17 #include "base/test/metrics/histogram_tester.h"
18 #include "base/trace_event/memory_allocator_dump.h"
19 #include "base/trace_event/process_memory_dump.h"
20 #include "build/build_config.h"
21 #include "net/base/proxy_string_util.h"
22 #include "net/base/session_usage.h"
23 #include "net/base/test_completion_callback.h"
24 #include "net/base/tracing.h"
25 #include "net/dns/host_cache.h"
26 #include "net/dns/public/host_resolver_results.h"
27 #include "net/dns/public/secure_dns_policy.h"
28 #include "net/http/http_network_session.h"
29 #include "net/log/net_log_with_source.h"
30 #include "net/log/test_net_log.h"
31 #include "net/socket/client_socket_handle.h"
32 #include "net/socket/socket_tag.h"
33 #include "net/socket/socket_test_util.h"
34 #include "net/socket/transport_client_socket_pool.h"
35 #include "net/spdy/spdy_session.h"
36 #include "net/spdy/spdy_stream_test_util.h"
37 #include "net/spdy/spdy_test_util_common.h"
38 #include "net/test/cert_test_util.h"
39 #include "net/test/gtest_util.h"
40 #include "net/test/test_certificate_data.h"
41 #include "net/test/test_data_directory.h"
42 #include "net/test/test_with_task_environment.h"
43 #include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"
44 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
45 #include "testing/gmock/include/gmock/gmock.h"
46 #include "testing/gtest/include/gtest/gtest.h"
47
48 using base::trace_event::MemoryAllocatorDump;
49 using net::test::IsError;
50 using net::test::IsOk;
51 using testing::Contains;
52 using testing::Eq;
53 using testing::Contains;
54 using testing::ByRef;
55
56 namespace net {
57
58 class SpdySessionPoolTest : public TestWithTaskEnvironment {
59 protected:
60 // Used by RunIPPoolingTest().
61 enum SpdyPoolCloseSessionsType {
62 SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
63 SPDY_POOL_CLOSE_CURRENT_SESSIONS,
64 SPDY_POOL_CLOSE_IDLE_SESSIONS,
65 };
66
67 SpdySessionPoolTest() = default;
68
CreateNetworkSession()69 void CreateNetworkSession() {
70 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
71 spdy_session_pool_ = http_session_->spdy_session_pool();
72 }
73
AddSSLSocketData()74 void AddSSLSocketData() {
75 auto ssl = std::make_unique<SSLSocketDataProvider>(SYNCHRONOUS, OK);
76 ssl->ssl_info.cert =
77 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
78 ASSERT_TRUE(ssl->ssl_info.cert);
79 session_deps_.socket_factory->AddSSLSocketDataProvider(ssl.get());
80 ssl_data_vector_.push_back(std::move(ssl));
81 }
82
83 void RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type);
84 void RunIPPoolingDisabledTest(SSLSocketDataProvider* ssl);
85
num_active_streams(base::WeakPtr<SpdySession> session)86 size_t num_active_streams(base::WeakPtr<SpdySession> session) {
87 return session->active_streams_.size();
88 }
89
max_concurrent_streams(base::WeakPtr<SpdySession> session)90 size_t max_concurrent_streams(base::WeakPtr<SpdySession> session) {
91 return session->max_concurrent_streams_;
92 }
93
94 SpdySessionDependencies session_deps_;
95 std::unique_ptr<HttpNetworkSession> http_session_;
96 raw_ptr<SpdySessionPool, DanglingUntriaged> spdy_session_pool_ = nullptr;
97 std::vector<std::unique_ptr<SSLSocketDataProvider>> ssl_data_vector_;
98 };
99
100 class SpdySessionRequestDelegate
101 : public SpdySessionPool::SpdySessionRequest::Delegate {
102 public:
103 SpdySessionRequestDelegate() = default;
104
105 SpdySessionRequestDelegate(const SpdySessionRequestDelegate&) = delete;
106 SpdySessionRequestDelegate& operator=(const SpdySessionRequestDelegate&) =
107 delete;
108
109 ~SpdySessionRequestDelegate() override = default;
110
OnSpdySessionAvailable(base::WeakPtr<SpdySession> spdy_session)111 void OnSpdySessionAvailable(
112 base::WeakPtr<SpdySession> spdy_session) override {
113 EXPECT_FALSE(callback_invoked_);
114 callback_invoked_ = true;
115 spdy_session_ = spdy_session;
116 }
117
callback_invoked() const118 bool callback_invoked() const { return callback_invoked_; }
119
spdy_session()120 SpdySession* spdy_session() { return spdy_session_.get(); }
121
122 private:
123 bool callback_invoked_ = false;
124 base::WeakPtr<SpdySession> spdy_session_;
125 };
126
127 // Attempts to set up an alias for |key| using an already existing session in
128 // |pool|. To do this, simulates a host resolution that returns
129 // |endpoints|.
TryCreateAliasedSpdySession(SpdySessionPool * pool,const SpdySessionKey & key,const std::vector<HostResolverEndpointResult> & endpoints,bool enable_ip_based_pooling=true,bool is_websocket=false)130 bool TryCreateAliasedSpdySession(
131 SpdySessionPool* pool,
132 const SpdySessionKey& key,
133 const std::vector<HostResolverEndpointResult>& endpoints,
134 bool enable_ip_based_pooling = true,
135 bool is_websocket = false) {
136 // The requested session must not already exist.
137 EXPECT_FALSE(pool->FindAvailableSession(key, enable_ip_based_pooling,
138 is_websocket, NetLogWithSource()));
139
140 // Create a request for the session. There should be no matching session
141 // (aliased or otherwise) yet. A pending request is necessary for the session
142 // to create an alias on host resolution completion.
143 std::unique_ptr<SpdySessionPool::SpdySessionRequest> request;
144 bool is_blocking_request_for_session = false;
145 SpdySessionRequestDelegate request_delegate;
146 EXPECT_FALSE(pool->RequestSession(
147 key, enable_ip_based_pooling, is_websocket, NetLogWithSource(),
148 /* on_blocking_request_destroyed_callback = */ base::RepeatingClosure(),
149 &request_delegate, &request, &is_blocking_request_for_session));
150 EXPECT_TRUE(request);
151 EXPECT_TRUE(is_blocking_request_for_session);
152
153 // Simulate a host resolution completing.
154 OnHostResolutionCallbackResult result = pool->OnHostResolutionComplete(
155 key, is_websocket, endpoints, /*aliases=*/{});
156
157 // Spin the message loop and see if it creates an H2 session.
158 base::RunLoop().RunUntilIdle();
159 EXPECT_EQ(request_delegate.callback_invoked(),
160 result == OnHostResolutionCallbackResult::kMayBeDeletedAsync);
161 EXPECT_EQ(request_delegate.callback_invoked(),
162 request_delegate.spdy_session() != nullptr);
163 request.reset();
164
165 // Calling RequestSession again should return request_delegate.spdy_session()
166 // (i.e. the newly created session, if a session was created, or nullptr, if
167 // one was not.)
168 EXPECT_EQ(request_delegate.spdy_session(),
169 pool->RequestSession(key, enable_ip_based_pooling, is_websocket,
170 NetLogWithSource(),
171 /* on_blocking_request_destroyed_callback = */
172 base::RepeatingClosure(), &request_delegate,
173 &request, &is_blocking_request_for_session)
174 .get());
175
176 return request_delegate.spdy_session() != nullptr;
177 }
178
179 // Attempts to set up an alias for |key| using an already existing session in
180 // |pool|. To do this, simulates a host resolution that returns
181 // |ip_address_list|.
TryCreateAliasedSpdySession(SpdySessionPool * pool,const SpdySessionKey & key,const std::string & ip_address_list,bool enable_ip_based_pooling=true,bool is_websocket=false)182 bool TryCreateAliasedSpdySession(SpdySessionPool* pool,
183 const SpdySessionKey& key,
184 const std::string& ip_address_list,
185 bool enable_ip_based_pooling = true,
186 bool is_websocket = false) {
187 std::vector<IPEndPoint> ip_endpoints;
188 EXPECT_THAT(ParseAddressList(ip_address_list, &ip_endpoints), IsOk());
189 HostResolverEndpointResult endpoint;
190 for (auto& ip_endpoint : ip_endpoints) {
191 endpoint.ip_endpoints.emplace_back(ip_endpoint.address(), 443);
192 }
193 return TryCreateAliasedSpdySession(pool, key, {endpoint},
194 enable_ip_based_pooling, is_websocket);
195 }
196
197 // A delegate that opens a new session when it is closed.
198 class SessionOpeningDelegate : public SpdyStream::Delegate {
199 public:
SessionOpeningDelegate(SpdySessionPool * spdy_session_pool,const SpdySessionKey & key)200 SessionOpeningDelegate(SpdySessionPool* spdy_session_pool,
201 const SpdySessionKey& key)
202 : spdy_session_pool_(spdy_session_pool),
203 key_(key) {}
204
205 ~SessionOpeningDelegate() override = default;
206
OnHeadersSent()207 void OnHeadersSent() override {}
208
OnEarlyHintsReceived(const spdy::Http2HeaderBlock & headers)209 void OnEarlyHintsReceived(const spdy::Http2HeaderBlock& headers) override {}
210
OnHeadersReceived(const spdy::Http2HeaderBlock & response_headers)211 void OnHeadersReceived(
212 const spdy::Http2HeaderBlock& response_headers) override {}
213
OnDataReceived(std::unique_ptr<SpdyBuffer> buffer)214 void OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) override {}
215
OnDataSent()216 void OnDataSent() override {}
217
OnTrailers(const spdy::Http2HeaderBlock & trailers)218 void OnTrailers(const spdy::Http2HeaderBlock& trailers) override {}
219
OnClose(int status)220 void OnClose(int status) override {
221 std::ignore = CreateFakeSpdySession(spdy_session_pool_, key_);
222 }
223
CanGreaseFrameType() const224 bool CanGreaseFrameType() const override { return false; }
225
source_dependency() const226 NetLogSource source_dependency() const override { return NetLogSource(); }
227
228 private:
229 const raw_ptr<SpdySessionPool> spdy_session_pool_;
230 const SpdySessionKey key_;
231 };
232
233 // Set up a SpdyStream to create a new session when it is closed.
234 // CloseCurrentSessions should not close the newly-created session.
TEST_F(SpdySessionPoolTest,CloseCurrentSessions)235 TEST_F(SpdySessionPoolTest, CloseCurrentSessions) {
236 const char kTestHost[] = "www.foo.com";
237 const int kTestPort = 80;
238
239 HostPortPair test_host_port_pair(kTestHost, kTestPort);
240 SpdySessionKey test_key = SpdySessionKey(
241 test_host_port_pair, PRIVACY_MODE_DISABLED, ProxyChain::Direct(),
242 SessionUsage::kDestination, SocketTag(), NetworkAnonymizationKey(),
243 SecureDnsPolicy::kAllow,
244 /*disable_cert_verification_network_fetches=*/false);
245
246 MockConnect connect_data(SYNCHRONOUS, OK);
247 MockRead reads[] = {
248 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
249 };
250
251 StaticSocketDataProvider data(reads, base::span<MockWrite>());
252 data.set_connect_data(connect_data);
253 session_deps_.socket_factory->AddSocketDataProvider(&data);
254
255 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
256 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
257
258 CreateNetworkSession();
259
260 // Setup the first session to the first host.
261 base::WeakPtr<SpdySession> session =
262 CreateSpdySession(http_session_.get(), test_key, NetLogWithSource());
263
264 // Flush the SpdySession::OnReadComplete() task.
265 base::RunLoop().RunUntilIdle();
266
267 // Verify that we have sessions for everything.
268 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
269
270 // Set the stream to create a new session when it is closed.
271 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
272 SPDY_BIDIRECTIONAL_STREAM, session, GURL("http://www.foo.com"), MEDIUM,
273 NetLogWithSource());
274 SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
275 spdy_stream->SetDelegate(&delegate);
276
277 // Close the current session.
278 spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
279
280 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
281 }
282
TEST_F(SpdySessionPoolTest,CloseCurrentIdleSessions)283 TEST_F(SpdySessionPoolTest, CloseCurrentIdleSessions) {
284 const std::string close_session_description = "Closing idle sessions.";
285 MockConnect connect_data(SYNCHRONOUS, OK);
286 MockRead reads[] = {
287 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
288 };
289
290 StaticSocketDataProvider data1(reads, base::span<MockWrite>());
291 data1.set_connect_data(connect_data);
292 session_deps_.socket_factory->AddSocketDataProvider(&data1);
293
294 AddSSLSocketData();
295 AddSSLSocketData();
296 AddSSLSocketData();
297
298 CreateNetworkSession();
299
300 // Set up session 1
301 const GURL url1("https://www.example.org");
302 HostPortPair test_host_port_pair1(HostPortPair::FromURL(url1));
303 SpdySessionKey key1(test_host_port_pair1, PRIVACY_MODE_DISABLED,
304 ProxyChain::Direct(), SessionUsage::kDestination,
305 SocketTag(), NetworkAnonymizationKey(),
306 SecureDnsPolicy::kAllow,
307 /*disable_cert_verification_network_fetches=*/false);
308 base::WeakPtr<SpdySession> session1 =
309 CreateSpdySession(http_session_.get(), key1, NetLogWithSource());
310 base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
311 SPDY_BIDIRECTIONAL_STREAM, session1, url1, MEDIUM, NetLogWithSource());
312 ASSERT_TRUE(spdy_stream1);
313
314 // Set up session 2
315 StaticSocketDataProvider data2(reads, base::span<MockWrite>());
316 session_deps_.socket_factory->AddSocketDataProvider(&data2);
317 const GURL url2("https://mail.example.org");
318 HostPortPair test_host_port_pair2(HostPortPair::FromURL(url2));
319 SpdySessionKey key2(test_host_port_pair2, PRIVACY_MODE_DISABLED,
320 ProxyChain::Direct(), SessionUsage::kDestination,
321 SocketTag(), NetworkAnonymizationKey(),
322 SecureDnsPolicy::kAllow,
323 /*disable_cert_verification_network_fetches=*/false);
324 base::WeakPtr<SpdySession> session2 =
325 CreateSpdySession(http_session_.get(), key2, NetLogWithSource());
326 base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
327 SPDY_BIDIRECTIONAL_STREAM, session2, url2, MEDIUM, NetLogWithSource());
328 ASSERT_TRUE(spdy_stream2);
329
330 // Set up session 3
331 StaticSocketDataProvider data3(reads, base::span<MockWrite>());
332 data3.set_connect_data(connect_data);
333 session_deps_.socket_factory->AddSocketDataProvider(&data3);
334 const GURL url3("https://mail.example.com");
335 HostPortPair test_host_port_pair3(HostPortPair::FromURL(url3));
336 SpdySessionKey key3(test_host_port_pair3, PRIVACY_MODE_DISABLED,
337 ProxyChain::Direct(), SessionUsage::kDestination,
338 SocketTag(), NetworkAnonymizationKey(),
339 SecureDnsPolicy::kAllow,
340 /*disable_cert_verification_network_fetches=*/false);
341 base::WeakPtr<SpdySession> session3 =
342 CreateSpdySession(http_session_.get(), key3, NetLogWithSource());
343 base::WeakPtr<SpdyStream> spdy_stream3 = CreateStreamSynchronously(
344 SPDY_BIDIRECTIONAL_STREAM, session3, url3, MEDIUM, NetLogWithSource());
345 ASSERT_TRUE(spdy_stream3);
346
347 // All sessions are active and not closed
348 EXPECT_TRUE(session1->is_active());
349 EXPECT_TRUE(session1->IsAvailable());
350 EXPECT_TRUE(session2->is_active());
351 EXPECT_TRUE(session2->IsAvailable());
352 EXPECT_TRUE(session3->is_active());
353 EXPECT_TRUE(session3->IsAvailable());
354
355 // Should not do anything, all are active
356 spdy_session_pool_->CloseCurrentIdleSessions(close_session_description);
357 EXPECT_TRUE(session1->is_active());
358 EXPECT_TRUE(session1->IsAvailable());
359 EXPECT_TRUE(session2->is_active());
360 EXPECT_TRUE(session2->IsAvailable());
361 EXPECT_TRUE(session3->is_active());
362 EXPECT_TRUE(session3->IsAvailable());
363
364 // Make sessions 1 and 3 inactive, but keep them open.
365 // Session 2 still open and active
366 session1->CloseCreatedStream(spdy_stream1, OK);
367 EXPECT_FALSE(spdy_stream1);
368 session3->CloseCreatedStream(spdy_stream3, OK);
369 EXPECT_FALSE(spdy_stream3);
370 EXPECT_FALSE(session1->is_active());
371 EXPECT_TRUE(session1->IsAvailable());
372 EXPECT_TRUE(session2->is_active());
373 EXPECT_TRUE(session2->IsAvailable());
374 EXPECT_FALSE(session3->is_active());
375 EXPECT_TRUE(session3->IsAvailable());
376
377 // Should close session 1 and 3, 2 should be left open
378 spdy_session_pool_->CloseCurrentIdleSessions(close_session_description);
379 base::RunLoop().RunUntilIdle();
380
381 EXPECT_FALSE(session1);
382 EXPECT_TRUE(session2->is_active());
383 EXPECT_TRUE(session2->IsAvailable());
384 EXPECT_FALSE(session3);
385
386 // Should not do anything
387 spdy_session_pool_->CloseCurrentIdleSessions(close_session_description);
388 base::RunLoop().RunUntilIdle();
389
390 EXPECT_TRUE(session2->is_active());
391 EXPECT_TRUE(session2->IsAvailable());
392
393 // Make 2 not active
394 session2->CloseCreatedStream(spdy_stream2, OK);
395 base::RunLoop().RunUntilIdle();
396
397 EXPECT_FALSE(spdy_stream2);
398 EXPECT_FALSE(session2->is_active());
399 EXPECT_TRUE(session2->IsAvailable());
400
401 // This should close session 2
402 spdy_session_pool_->CloseCurrentIdleSessions(close_session_description);
403 base::RunLoop().RunUntilIdle();
404
405 EXPECT_FALSE(session2);
406 }
407
408 // Set up a SpdyStream to create a new session when it is closed.
409 // CloseAllSessions should close the newly-created session.
TEST_F(SpdySessionPoolTest,CloseAllSessions)410 TEST_F(SpdySessionPoolTest, CloseAllSessions) {
411 const char kTestHost[] = "www.foo.com";
412 const int kTestPort = 80;
413
414 HostPortPair test_host_port_pair(kTestHost, kTestPort);
415 SpdySessionKey test_key = SpdySessionKey(
416 test_host_port_pair, PRIVACY_MODE_DISABLED, ProxyChain::Direct(),
417 SessionUsage::kDestination, SocketTag(), NetworkAnonymizationKey(),
418 SecureDnsPolicy::kAllow,
419 /*disable_cert_verification_network_fetches=*/false);
420
421 MockConnect connect_data(SYNCHRONOUS, OK);
422 MockRead reads[] = {
423 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
424 };
425
426 StaticSocketDataProvider data(reads, base::span<MockWrite>());
427 data.set_connect_data(connect_data);
428 session_deps_.socket_factory->AddSocketDataProvider(&data);
429
430 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
431 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
432
433 CreateNetworkSession();
434
435 // Setup the first session to the first host.
436 base::WeakPtr<SpdySession> session =
437 CreateSpdySession(http_session_.get(), test_key, NetLogWithSource());
438
439 // Flush the SpdySession::OnReadComplete() task.
440 base::RunLoop().RunUntilIdle();
441
442 // Verify that we have sessions for everything.
443 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
444
445 // Set the stream to create a new session when it is closed.
446 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
447 SPDY_BIDIRECTIONAL_STREAM, session, GURL("http://www.foo.com"), MEDIUM,
448 NetLogWithSource());
449 SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
450 spdy_stream->SetDelegate(&delegate);
451
452 // Close the current session.
453 spdy_session_pool_->CloseAllSessions();
454
455 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_key));
456 }
457
458 // Code testing SpdySessionPool::OnIPAddressChange requires a SpdySessionPool
459 // with some active sessions. This fixture takes care of setting most things up
460 // but doesn't create the pool yet, allowing tests to possibly further
461 // configure sessions_deps_.
462 class SpdySessionPoolOnIPAddressChangeTest : public SpdySessionPoolTest {
463 protected:
SpdySessionPoolOnIPAddressChangeTest()464 SpdySessionPoolOnIPAddressChangeTest()
465 : test_host_port_pair_(kTestHost, kTestPort),
466 reads_({
467 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
468 }),
469 test_key_(SpdySessionKey(
470 test_host_port_pair_,
471 PRIVACY_MODE_DISABLED,
472 ProxyChain::Direct(),
473 SessionUsage::kDestination,
474 SocketTag(),
475 NetworkAnonymizationKey(),
476 SecureDnsPolicy::kAllow,
477 /*disable_cert_verification_network_fetches=*/false)),
478 connect_data_(SYNCHRONOUS, OK),
479 data_(reads_, base::span<MockWrite>()),
480 ssl_(SYNCHRONOUS, OK) {
481 data_.set_connect_data(connect_data_);
482 session_deps_.socket_factory->AddSocketDataProvider(&data_);
483 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_);
484 }
485
486 static constexpr char kTestHost[] = "www.foo.com";
487 static constexpr int kTestPort = 80;
488 static constexpr int kReadSize = 1;
489
490 const HostPortPair test_host_port_pair_;
491 const std::array<MockRead, kReadSize> reads_;
492 const SpdySessionKey test_key_;
493 const MockConnect connect_data_;
494 StaticSocketDataProvider data_;
495 SSLSocketDataProvider ssl_;
496 };
497
TEST_F(SpdySessionPoolOnIPAddressChangeTest,DoNotIgnoreIPAddressChanges)498 TEST_F(SpdySessionPoolOnIPAddressChangeTest, DoNotIgnoreIPAddressChanges) {
499 // Default behavior should be ignore_ip_address_changes = false;
500 CreateNetworkSession();
501
502 base::WeakPtr<SpdySession> session =
503 CreateSpdySession(http_session_.get(), test_key_, NetLogWithSource());
504
505 // Flush the SpdySession::OnReadComplete() task.
506 base::RunLoop().RunUntilIdle();
507 // Verify that we have a session.
508 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key_));
509
510 // Without setting session_deps_.ignore_ip_address_changes = true the pool
511 // should close (or make unavailable) all sessions after an IP address change.
512 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
513 base::RunLoop().RunUntilIdle();
514 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_key_));
515 }
516
TEST_F(SpdySessionPoolOnIPAddressChangeTest,IgnoreIPAddressChanges)517 TEST_F(SpdySessionPoolOnIPAddressChangeTest, IgnoreIPAddressChanges) {
518 session_deps_.ignore_ip_address_changes = true;
519 CreateNetworkSession();
520
521 // Setup the first session to the first host.
522 base::WeakPtr<SpdySession> session =
523 CreateSpdySession(http_session_.get(), test_key_, NetLogWithSource());
524 // Flush the SpdySession::OnReadComplete() task.
525 base::RunLoop().RunUntilIdle();
526 // Verify that we have a session.
527 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key_));
528
529 // Since we set ignore_ip_address_changes = true, the session should still be
530 // there after an IP address change.
531 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
532 base::RunLoop().RunUntilIdle();
533 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key_));
534 }
535
536 // This test has three variants, one for each style of closing the connection.
537 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
538 // the sessions are closed manually, calling SpdySessionPool::Remove() directly.
539 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_CURRENT_SESSIONS,
540 // sessions are closed with SpdySessionPool::CloseCurrentSessions().
541 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_IDLE_SESSIONS,
542 // sessions are closed with SpdySessionPool::CloseIdleSessions().
RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type)543 void SpdySessionPoolTest::RunIPPoolingTest(
544 SpdyPoolCloseSessionsType close_sessions_type) {
545 constexpr int kTestPort = 443;
546 struct TestHosts {
547 std::string url;
548 std::string name;
549 std::string iplist;
550 SpdySessionKey key;
551 } test_hosts[] = {
552 {"http://www.example.org", "www.example.org",
553 "192.0.2.33,192.168.0.1,192.168.0.5"},
554 {"http://mail.example.org", "mail.example.org",
555 "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"},
556 {"http://mail.example.com", "mail.example.com",
557 "192.168.0.4,192.168.0.3"},
558 };
559
560 for (auto& test_host : test_hosts) {
561 session_deps_.host_resolver->rules()->AddIPLiteralRule(
562 test_host.name, test_host.iplist, std::string());
563
564 test_host.key = SpdySessionKey(
565 HostPortPair(test_host.name, kTestPort), PRIVACY_MODE_DISABLED,
566 ProxyChain::Direct(), SessionUsage::kDestination, SocketTag(),
567 NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
568 /*disable_cert_verification_network_fetches=*/false);
569 }
570
571 MockConnect connect_data(SYNCHRONOUS, OK);
572 MockRead reads[] = {
573 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
574 };
575
576 StaticSocketDataProvider data1(reads, base::span<MockWrite>());
577 data1.set_connect_data(connect_data);
578 session_deps_.socket_factory->AddSocketDataProvider(&data1);
579
580 AddSSLSocketData();
581
582 CreateNetworkSession();
583
584 // Setup the first session to the first host.
585 base::WeakPtr<SpdySession> session = CreateSpdySession(
586 http_session_.get(), test_hosts[0].key, NetLogWithSource());
587
588 // Flush the SpdySession::OnReadComplete() task.
589 base::RunLoop().RunUntilIdle();
590
591 // The third host has no overlap with the first, so it can't pool IPs.
592 EXPECT_FALSE(TryCreateAliasedSpdySession(
593 spdy_session_pool_, test_hosts[2].key, test_hosts[2].iplist));
594
595 // The second host overlaps with the first, and should IP pool.
596 EXPECT_TRUE(TryCreateAliasedSpdySession(spdy_session_pool_, test_hosts[1].key,
597 test_hosts[1].iplist));
598
599 // However, if IP pooling is disabled, FindAvailableSession() should not find
600 // |session| for the second host.
601 base::WeakPtr<SpdySession> session1 =
602 spdy_session_pool_->FindAvailableSession(
603 test_hosts[1].key, /* enable_ip_based_pooling = */ false,
604 /* is_websocket = */ false, NetLogWithSource());
605 EXPECT_FALSE(session1);
606
607 // Verify that the second host, through a proxy, won't share the IP, even if
608 // the IP list matches.
609 SpdySessionKey proxy_key(
610 test_hosts[1].key.host_port_pair(), PRIVACY_MODE_DISABLED,
611 PacResultElementToProxyChain("HTTP http://proxy.foo.com/"),
612 SessionUsage::kDestination, SocketTag(), NetworkAnonymizationKey(),
613 SecureDnsPolicy::kAllow,
614 /*disable_cert_verification_network_fetches=*/false);
615 EXPECT_FALSE(TryCreateAliasedSpdySession(spdy_session_pool_, proxy_key,
616 test_hosts[1].iplist));
617
618 // Verify that the second host, with a different SecureDnsPolicy,
619 // won't share the IP, even if the IP list matches.
620 SpdySessionKey disable_secure_dns_key(
621 test_hosts[1].key.host_port_pair(), PRIVACY_MODE_DISABLED,
622 ProxyChain::Direct(), SessionUsage::kDestination, SocketTag(),
623 NetworkAnonymizationKey(), SecureDnsPolicy::kDisable,
624 /*disable_cert_verification_network_fetches=*/false);
625 EXPECT_FALSE(TryCreateAliasedSpdySession(
626 spdy_session_pool_, disable_secure_dns_key, test_hosts[1].iplist));
627
628 // Overlap between 2 and 3 is not transitive to 1.
629 EXPECT_FALSE(TryCreateAliasedSpdySession(
630 spdy_session_pool_, test_hosts[2].key, test_hosts[2].iplist));
631
632 // Create a new session to host 2.
633 StaticSocketDataProvider data2(reads, base::span<MockWrite>());
634 data2.set_connect_data(connect_data);
635 session_deps_.socket_factory->AddSocketDataProvider(&data2);
636
637 AddSSLSocketData();
638
639 base::WeakPtr<SpdySession> session2 = CreateSpdySession(
640 http_session_.get(), test_hosts[2].key, NetLogWithSource());
641
642 // Verify that we have sessions for everything.
643 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
644 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
645 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
646
647 // Grab the session to host 1 and verify that it is the same session
648 // we got with host 0, and that is a different from host 2's session.
649 session1 = spdy_session_pool_->FindAvailableSession(
650 test_hosts[1].key, /* enable_ip_based_pooling = */ true,
651 /* is_websocket = */ false, NetLogWithSource());
652 EXPECT_EQ(session.get(), session1.get());
653 EXPECT_NE(session2.get(), session1.get());
654
655 // Remove the aliases and observe that we still have a session for host1.
656 SpdySessionPoolPeer pool_peer(spdy_session_pool_);
657 pool_peer.RemoveAliases(test_hosts[0].key);
658 pool_peer.RemoveAliases(test_hosts[1].key);
659 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
660
661 // Cleanup the sessions.
662 switch (close_sessions_type) {
663 case SPDY_POOL_CLOSE_SESSIONS_MANUALLY:
664 session->CloseSessionOnError(ERR_ABORTED, std::string());
665 session2->CloseSessionOnError(ERR_ABORTED, std::string());
666 base::RunLoop().RunUntilIdle();
667 EXPECT_FALSE(session);
668 EXPECT_FALSE(session2);
669 break;
670 case SPDY_POOL_CLOSE_CURRENT_SESSIONS:
671 spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
672 break;
673 case SPDY_POOL_CLOSE_IDLE_SESSIONS:
674 GURL url(test_hosts[0].url);
675 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
676 SPDY_BIDIRECTIONAL_STREAM, session, url, MEDIUM, NetLogWithSource());
677 GURL url1(test_hosts[1].url);
678 base::WeakPtr<SpdyStream> spdy_stream1 =
679 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session1, url1,
680 MEDIUM, NetLogWithSource());
681 GURL url2(test_hosts[2].url);
682 base::WeakPtr<SpdyStream> spdy_stream2 =
683 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session2, url2,
684 MEDIUM, NetLogWithSource());
685
686 // Close streams to make spdy_session and spdy_session1 inactive.
687 session->CloseCreatedStream(spdy_stream, OK);
688 EXPECT_FALSE(spdy_stream);
689 session1->CloseCreatedStream(spdy_stream1, OK);
690 EXPECT_FALSE(spdy_stream1);
691
692 // Check spdy_session and spdy_session1 are not closed.
693 EXPECT_FALSE(session->is_active());
694 EXPECT_TRUE(session->IsAvailable());
695 EXPECT_FALSE(session1->is_active());
696 EXPECT_TRUE(session1->IsAvailable());
697 EXPECT_TRUE(session2->is_active());
698 EXPECT_TRUE(session2->IsAvailable());
699
700 // Test that calling CloseIdleSessions, does not cause a crash.
701 // http://crbug.com/181400
702 spdy_session_pool_->CloseCurrentIdleSessions("Closing idle sessions.");
703 base::RunLoop().RunUntilIdle();
704
705 // Verify spdy_session and spdy_session1 are closed.
706 EXPECT_FALSE(session);
707 EXPECT_FALSE(session1);
708 EXPECT_TRUE(session2->is_active());
709 EXPECT_TRUE(session2->IsAvailable());
710
711 spdy_stream2->Cancel(ERR_ABORTED);
712 EXPECT_FALSE(spdy_stream);
713 EXPECT_FALSE(spdy_stream1);
714 EXPECT_FALSE(spdy_stream2);
715
716 session2->CloseSessionOnError(ERR_ABORTED, std::string());
717 base::RunLoop().RunUntilIdle();
718 EXPECT_FALSE(session2);
719 break;
720 }
721
722 // Verify that the map is all cleaned up.
723 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
724 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
725 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
726 EXPECT_FALSE(TryCreateAliasedSpdySession(
727 spdy_session_pool_, test_hosts[0].key, test_hosts[0].iplist));
728 EXPECT_FALSE(TryCreateAliasedSpdySession(
729 spdy_session_pool_, test_hosts[1].key, test_hosts[1].iplist));
730 EXPECT_FALSE(TryCreateAliasedSpdySession(
731 spdy_session_pool_, test_hosts[2].key, test_hosts[2].iplist));
732 }
733
RunIPPoolingDisabledTest(SSLSocketDataProvider * ssl)734 void SpdySessionPoolTest::RunIPPoolingDisabledTest(SSLSocketDataProvider* ssl) {
735 constexpr int kTestPort = 443;
736 struct TestHosts {
737 std::string name;
738 std::string iplist;
739 SpdySessionKey key;
740 } test_hosts[] = {
741 {"www.webkit.org", "192.0.2.33,192.168.0.1,192.168.0.5"},
742 {"js.webkit.com", "192.168.0.4,192.168.0.1,192.0.2.33"},
743 };
744
745 session_deps_.host_resolver->set_synchronous_mode(true);
746 for (auto& test_host : test_hosts) {
747 session_deps_.host_resolver->rules()->AddIPLiteralRule(
748 test_host.name, test_host.iplist, std::string());
749
750 // Setup a SpdySessionKey
751 test_host.key = SpdySessionKey(
752 HostPortPair(test_host.name, kTestPort), PRIVACY_MODE_DISABLED,
753 ProxyChain::Direct(), SessionUsage::kDestination, SocketTag(),
754 NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
755 /*disable_cert_verification_network_fetches=*/false);
756 }
757
758 MockRead reads[] = {
759 MockRead(ASYNC, ERR_IO_PENDING),
760 };
761 StaticSocketDataProvider data(reads, base::span<MockWrite>());
762 session_deps_.socket_factory->AddSocketDataProvider(&data);
763 session_deps_.socket_factory->AddSSLSocketDataProvider(ssl);
764
765 CreateNetworkSession();
766
767 base::WeakPtr<SpdySession> spdy_session = CreateSpdySession(
768 http_session_.get(), test_hosts[0].key, NetLogWithSource());
769 EXPECT_TRUE(
770 HasSpdySession(http_session_->spdy_session_pool(), test_hosts[0].key));
771 EXPECT_FALSE(TryCreateAliasedSpdySession(
772 spdy_session_pool_, test_hosts[1].key, test_hosts[1].iplist,
773 /* enable_ip_based_pooling = */ false));
774
775 http_session_->spdy_session_pool()->CloseAllSessions();
776 }
777
TEST_F(SpdySessionPoolTest,IPPooling)778 TEST_F(SpdySessionPoolTest, IPPooling) {
779 RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY);
780 }
781
TEST_F(SpdySessionPoolTest,IPPoolingCloseCurrentSessions)782 TEST_F(SpdySessionPoolTest, IPPoolingCloseCurrentSessions) {
783 RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS);
784 }
785
TEST_F(SpdySessionPoolTest,IPPoolingCloseIdleSessions)786 TEST_F(SpdySessionPoolTest, IPPoolingCloseIdleSessions) {
787 RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS);
788 }
789
790 // Regression test for https://crbug.com/643025.
TEST_F(SpdySessionPoolTest,IPPoolingNetLog)791 TEST_F(SpdySessionPoolTest, IPPoolingNetLog) {
792 // Define two hosts with identical IP address.
793 constexpr int kTestPort = 443;
794 struct TestHosts {
795 std::string name;
796 std::string iplist;
797 SpdySessionKey key;
798 } test_hosts[] = {
799 {"www.example.org", "192.168.0.1"}, {"mail.example.org", "192.168.0.1"},
800 };
801
802 // Populate the HostResolver cache.
803 session_deps_.host_resolver->set_synchronous_mode(true);
804 for (auto& test_host : test_hosts) {
805 session_deps_.host_resolver->rules()->AddIPLiteralRule(
806 test_host.name, test_host.iplist, std::string());
807
808 test_host.key = SpdySessionKey(
809 HostPortPair(test_host.name, kTestPort), PRIVACY_MODE_DISABLED,
810 ProxyChain::Direct(), SessionUsage::kDestination, SocketTag(),
811 NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
812 /*disable_cert_verification_network_fetches=*/false);
813 }
814
815 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
816 StaticSocketDataProvider data(reads, base::span<MockWrite>());
817 MockConnect connect_data(SYNCHRONOUS, OK);
818 data.set_connect_data(connect_data);
819
820 session_deps_.socket_factory->AddSocketDataProvider(&data);
821 AddSSLSocketData();
822
823 CreateNetworkSession();
824
825 // Open SpdySession to the first host.
826 base::WeakPtr<SpdySession> session0 = CreateSpdySession(
827 http_session_.get(), test_hosts[0].key, NetLogWithSource());
828
829 // The second host should pool to the existing connection.
830 RecordingNetLogObserver net_log_observer;
831 base::HistogramTester histogram_tester;
832 EXPECT_TRUE(TryCreateAliasedSpdySession(spdy_session_pool_, test_hosts[1].key,
833 test_hosts[1].iplist));
834 histogram_tester.ExpectTotalCount("Net.SpdySessionGet", 1);
835
836 base::WeakPtr<SpdySession> session1 =
837 spdy_session_pool_->FindAvailableSession(
838 test_hosts[1].key, /* enable_ip_based_pooling = */ true,
839 /* is_websocket = */ false,
840 NetLogWithSource::Make(NetLogSourceType::NONE));
841 EXPECT_EQ(session0.get(), session1.get());
842
843 ASSERT_EQ(1u, net_log_observer.GetSize());
844 histogram_tester.ExpectTotalCount("Net.SpdySessionGet", 2);
845
846 // FindAvailableSession() should have logged a netlog event indicating IP
847 // pooling.
848 auto entry_list = net_log_observer.GetEntries();
849 EXPECT_EQ(
850 NetLogEventType::HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION_FROM_IP_POOL,
851 entry_list[0].type);
852
853 // Both FindAvailableSession() calls (including one from
854 // TryCreateAliasedSpdySession) should log histogram entries indicating IP
855 // pooling.
856 histogram_tester.ExpectUniqueSample("Net.SpdySessionGet", 2, 2);
857 }
858
859 // Test IP pooling when the DNS responses have ALPNs.
TEST_F(SpdySessionPoolTest,IPPoolingDnsAlpn)860 TEST_F(SpdySessionPoolTest, IPPoolingDnsAlpn) {
861 // Define two hosts with identical IP address.
862 constexpr int kTestPort = 443;
863 struct TestHosts {
864 std::string name;
865 std::vector<HostResolverEndpointResult> endpoints;
866 SpdySessionKey key;
867 } test_hosts[] = {{"www.example.org"},
868 {"mail.example.org"},
869 {"mail.example.com"},
870 {"example.test"}};
871
872 const IPEndPoint kRightIP(*IPAddress::FromIPLiteral("192.168.0.1"),
873 kTestPort);
874 const IPEndPoint kWrongIP(*IPAddress::FromIPLiteral("192.168.0.2"),
875 kTestPort);
876 const std::string kRightALPN = "h2";
877 const std::string kWrongALPN = "h3";
878
879 // `test_hosts[0]` and `test_hosts[1]` resolve to the same IP address, without
880 // any ALPN information.
881 test_hosts[0].endpoints.emplace_back();
882 test_hosts[0].endpoints[0].ip_endpoints = {kRightIP};
883 test_hosts[1].endpoints.emplace_back();
884 test_hosts[1].endpoints[0].ip_endpoints = {kRightIP};
885
886 // `test_hosts[2]` resolves to the same IP address, but only via an
887 // alternative endpoint with matching ALPN.
888 test_hosts[2].endpoints.emplace_back();
889 test_hosts[2].endpoints[0].ip_endpoints = {kRightIP};
890 test_hosts[2].endpoints[0].metadata.supported_protocol_alpns = {kRightALPN};
891
892 // `test_hosts[3]` resolves to the same IP address, but only via an
893 // alternative endpoint with a mismatching ALPN.
894 test_hosts[3].endpoints.resize(2);
895 test_hosts[3].endpoints[0].ip_endpoints = {kRightIP};
896 test_hosts[3].endpoints[0].metadata.supported_protocol_alpns = {kWrongALPN};
897 test_hosts[3].endpoints[1].ip_endpoints = {kWrongIP};
898 test_hosts[3].endpoints[1].metadata.supported_protocol_alpns = {kRightALPN};
899
900 // Populate the HostResolver cache.
901 session_deps_.host_resolver->set_synchronous_mode(true);
902 for (auto& test_host : test_hosts) {
903 session_deps_.host_resolver->rules()->AddRule(
904 test_host.name,
905 MockHostResolverBase::RuleResolver::RuleResult(test_host.endpoints));
906
907 test_host.key = SpdySessionKey(
908 HostPortPair(test_host.name, kTestPort), PRIVACY_MODE_DISABLED,
909 ProxyChain::Direct(), SessionUsage::kDestination, SocketTag(),
910 NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
911 /*disable_cert_verification_network_fetches=*/false);
912 }
913
914 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
915 StaticSocketDataProvider data(reads, base::span<MockWrite>());
916 MockConnect connect_data(SYNCHRONOUS, OK);
917 data.set_connect_data(connect_data);
918
919 session_deps_.socket_factory->AddSocketDataProvider(&data);
920 AddSSLSocketData();
921
922 CreateNetworkSession();
923
924 // Open SpdySession to the first host.
925 base::WeakPtr<SpdySession> session0 = CreateSpdySession(
926 http_session_.get(), test_hosts[0].key, NetLogWithSource());
927
928 // The second host should pool to the existing connection. Although the
929 // addresses are not associated with ALPNs, the default connection flow for
930 // HTTPS is compatible with HTTP/2.
931 EXPECT_TRUE(TryCreateAliasedSpdySession(spdy_session_pool_, test_hosts[1].key,
932 test_hosts[1].endpoints));
933 base::WeakPtr<SpdySession> session1 =
934 spdy_session_pool_->FindAvailableSession(
935 test_hosts[1].key, /*enable_ip_based_pooling=*/true,
936 /*is_websocket=*/false,
937 NetLogWithSource::Make(NetLogSourceType::NONE));
938 EXPECT_EQ(session0.get(), session1.get());
939
940 // The third host should also pool to the existing connection.
941 EXPECT_TRUE(TryCreateAliasedSpdySession(spdy_session_pool_, test_hosts[2].key,
942 test_hosts[2].endpoints));
943 base::WeakPtr<SpdySession> session2 =
944 spdy_session_pool_->FindAvailableSession(
945 test_hosts[2].key, /*enable_ip_based_pooling=*/true,
946 /*is_websocket=*/false,
947 NetLogWithSource::Make(NetLogSourceType::NONE));
948 EXPECT_EQ(session0.get(), session2.get());
949
950 // The fourth host should not pool. The only matching endpoint is specific to
951 // QUIC.
952 EXPECT_FALSE(TryCreateAliasedSpdySession(
953 spdy_session_pool_, test_hosts[3].key, test_hosts[3].endpoints));
954 }
955
TEST_F(SpdySessionPoolTest,IPPoolingDisabled)956 TEST_F(SpdySessionPoolTest, IPPoolingDisabled) {
957 // Define two hosts with identical IP address.
958 constexpr int kTestPort = 443;
959 struct TestHosts {
960 std::string name;
961 std::string iplist;
962 SpdySessionKey key;
963 } test_hosts[] = {
964 {"www.example.org", "192.168.0.1"}, {"mail.example.org", "192.168.0.1"},
965 };
966
967 // Populate the HostResolver cache.
968 session_deps_.host_resolver->set_synchronous_mode(true);
969 for (auto& test_host : test_hosts) {
970 session_deps_.host_resolver->rules()->AddIPLiteralRule(
971 test_host.name, test_host.iplist, std::string());
972
973 test_host.key = SpdySessionKey(
974 HostPortPair(test_host.name, kTestPort), PRIVACY_MODE_DISABLED,
975 ProxyChain::Direct(), SessionUsage::kDestination, SocketTag(),
976 NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
977 /*disable_cert_verification_network_fetches=*/false);
978 }
979
980 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
981 StaticSocketDataProvider data(reads, base::span<MockWrite>());
982 MockConnect connect_data(SYNCHRONOUS, OK);
983 data.set_connect_data(connect_data);
984 session_deps_.socket_factory->AddSocketDataProvider(&data);
985 AddSSLSocketData();
986
987 MockRead reads1[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
988 StaticSocketDataProvider data1(reads1, base::span<MockWrite>());
989 MockConnect connect_data1(SYNCHRONOUS, OK);
990 data1.set_connect_data(connect_data1);
991 session_deps_.socket_factory->AddSocketDataProvider(&data1);
992 AddSSLSocketData();
993
994 CreateNetworkSession();
995
996 // Open SpdySession to the first host.
997 base::WeakPtr<SpdySession> session0 = CreateSpdySession(
998 http_session_.get(), test_hosts[0].key, NetLogWithSource());
999
1000 // |test_hosts[1]| should pool to the existing connection.
1001 EXPECT_TRUE(TryCreateAliasedSpdySession(spdy_session_pool_, test_hosts[1].key,
1002 test_hosts[1].iplist));
1003 base::WeakPtr<SpdySession> session1 =
1004 spdy_session_pool_->FindAvailableSession(
1005 test_hosts[1].key, /* enable_ip_based_pooling = */ true,
1006 /* is_websocket = */ false, NetLogWithSource());
1007 EXPECT_EQ(session0.get(), session1.get());
1008
1009 // A request to the second host should not pool to the existing connection if
1010 // IP based pooling is disabled.
1011 session1 = spdy_session_pool_->FindAvailableSession(
1012 test_hosts[1].key, /* enable_ip_based_pooling = */ false,
1013 /* is_websocket = */ false, NetLogWithSource());
1014 EXPECT_FALSE(session1);
1015
1016 // It should be possible to open a new SpdySession, even if a previous call to
1017 // FindAvailableSession() linked the second key to the first connection in the
1018 // IP pooled bucket of SpdySessionPool::available_session_map_.
1019 session1 = CreateSpdySessionWithIpBasedPoolingDisabled(
1020 http_session_.get(), test_hosts[1].key, NetLogWithSource());
1021 EXPECT_TRUE(session1);
1022 EXPECT_NE(session0.get(), session1.get());
1023 }
1024
1025 // Verifies that an SSL connection with client authentication disables SPDY IP
1026 // pooling.
TEST_F(SpdySessionPoolTest,IPPoolingClientCert)1027 TEST_F(SpdySessionPoolTest, IPPoolingClientCert) {
1028 SSLSocketDataProvider ssl(ASYNC, OK);
1029 ssl.ssl_info.cert = X509Certificate::CreateFromBytes(webkit_der);
1030 ASSERT_TRUE(ssl.ssl_info.cert);
1031 ssl.ssl_info.client_cert_sent = true;
1032 ssl.next_proto = kProtoHTTP2;
1033 RunIPPoolingDisabledTest(&ssl);
1034 }
1035
1036 namespace {
1037 enum class ChangeType {
1038 kIpAddress = 0,
1039 kSSLConfig,
1040 kCertDatabase,
1041 kCertVerifier
1042 };
1043
1044 class SpdySessionGoAwayOnChangeTest
1045 : public SpdySessionPoolTest,
1046 public ::testing::WithParamInterface<ChangeType> {
1047 public:
SetUp()1048 void SetUp() override {
1049 SpdySessionPoolTest::SetUp();
1050
1051 if (GetParam() == ChangeType::kIpAddress) {
1052 session_deps_.go_away_on_ip_change = true;
1053 }
1054 }
1055
SimulateChange()1056 void SimulateChange() {
1057 switch (GetParam()) {
1058 case ChangeType::kIpAddress:
1059 spdy_session_pool_->OnIPAddressChanged();
1060 break;
1061 case ChangeType::kSSLConfig:
1062 session_deps_.ssl_config_service->NotifySSLContextConfigChange();
1063 break;
1064 case ChangeType::kCertDatabase:
1065 // TODO(mattm): For more realistic testing this should call
1066 // `CertDatabase::GetInstance()->NotifyObserversCertDBChanged()`,
1067 // however that delivers notifications asynchronously, and running
1068 // the message loop to allow the notification to be delivered allows
1069 // other parts of the tested code to advance, breaking the test
1070 // expectations.
1071 spdy_session_pool_->OnSSLConfigChanged(
1072 SSLClientContext::SSLConfigChangeType::kCertDatabaseChanged);
1073 break;
1074 case ChangeType::kCertVerifier:
1075 session_deps_.cert_verifier->SimulateOnCertVerifierChanged();
1076 break;
1077 }
1078 }
1079
ExpectedNetError() const1080 Error ExpectedNetError() const {
1081 switch (GetParam()) {
1082 case ChangeType::kIpAddress:
1083 return ERR_NETWORK_CHANGED;
1084 case ChangeType::kSSLConfig:
1085 return ERR_NETWORK_CHANGED;
1086 case ChangeType::kCertDatabase:
1087 return ERR_CERT_DATABASE_CHANGED;
1088 case ChangeType::kCertVerifier:
1089 return ERR_CERT_VERIFIER_CHANGED;
1090 }
1091 }
1092 };
1093 } // namespace
1094
1095 // Construct a Pool with SpdySessions in various availability states. Simulate
1096 // an IP address change. Ensure sessions gracefully shut down. Regression test
1097 // for crbug.com/379469.
TEST_P(SpdySessionGoAwayOnChangeTest,GoAwayOnChange)1098 TEST_P(SpdySessionGoAwayOnChangeTest, GoAwayOnChange) {
1099 MockConnect connect_data(SYNCHRONOUS, OK);
1100 session_deps_.host_resolver->set_synchronous_mode(true);
1101
1102 // This isn't testing anything having to do with SPDY frames; we
1103 // can ignore issues of how dependencies are set. We default to
1104 // setting them (when doing the appropriate protocol) since that's
1105 // where we're eventually headed for all HTTP/2 connections.
1106 SpdyTestUtil spdy_util;
1107
1108 MockRead reads[] = {
1109 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
1110 };
1111 spdy::SpdySerializedFrame req(
1112 spdy_util.ConstructSpdyGet("http://www.example.org", 1, MEDIUM));
1113 MockWrite writes[] = {CreateMockWrite(req, 1)};
1114
1115 StaticSocketDataProvider dataA(reads, writes);
1116 dataA.set_connect_data(connect_data);
1117 session_deps_.socket_factory->AddSocketDataProvider(&dataA);
1118
1119 AddSSLSocketData();
1120
1121 CreateNetworkSession();
1122
1123 // Set up session A: Going away, but with an active stream.
1124 const std::string kTestHostA("www.example.org");
1125 HostPortPair test_host_port_pairA(kTestHostA, 80);
1126 SpdySessionKey keyA(test_host_port_pairA, PRIVACY_MODE_DISABLED,
1127 ProxyChain::Direct(), SessionUsage::kDestination,
1128 SocketTag(), NetworkAnonymizationKey(),
1129 SecureDnsPolicy::kAllow,
1130 /*disable_cert_verification_network_fetches=*/false);
1131 base::WeakPtr<SpdySession> sessionA =
1132 CreateSpdySession(http_session_.get(), keyA, NetLogWithSource());
1133
1134 GURL urlA("http://www.example.org");
1135 base::WeakPtr<SpdyStream> spdy_streamA = CreateStreamSynchronously(
1136 SPDY_BIDIRECTIONAL_STREAM, sessionA, urlA, MEDIUM, NetLogWithSource());
1137 test::StreamDelegateDoNothing delegateA(spdy_streamA);
1138 spdy_streamA->SetDelegate(&delegateA);
1139
1140 spdy::Http2HeaderBlock headers(
1141 spdy_util.ConstructGetHeaderBlock(urlA.spec()));
1142 spdy_streamA->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
1143
1144 base::RunLoop().RunUntilIdle(); // Allow headers to write.
1145 EXPECT_TRUE(delegateA.send_headers_completed());
1146
1147 sessionA->MakeUnavailable();
1148 EXPECT_TRUE(sessionA->IsGoingAway());
1149 EXPECT_FALSE(delegateA.StreamIsClosed());
1150
1151 // Set up session B: Available, with a created stream.
1152 StaticSocketDataProvider dataB(reads, writes);
1153 dataB.set_connect_data(connect_data);
1154 session_deps_.socket_factory->AddSocketDataProvider(&dataB);
1155
1156 AddSSLSocketData();
1157
1158 const std::string kTestHostB("mail.example.org");
1159 HostPortPair test_host_port_pairB(kTestHostB, 80);
1160 SpdySessionKey keyB(test_host_port_pairB, PRIVACY_MODE_DISABLED,
1161 ProxyChain::Direct(), SessionUsage::kDestination,
1162 SocketTag(), NetworkAnonymizationKey(),
1163 SecureDnsPolicy::kAllow,
1164 /*disable_cert_verification_network_fetches=*/false);
1165 base::WeakPtr<SpdySession> sessionB =
1166 CreateSpdySession(http_session_.get(), keyB, NetLogWithSource());
1167 EXPECT_TRUE(sessionB->IsAvailable());
1168
1169 GURL urlB("http://mail.example.org");
1170 base::WeakPtr<SpdyStream> spdy_streamB = CreateStreamSynchronously(
1171 SPDY_BIDIRECTIONAL_STREAM, sessionB, urlB, MEDIUM, NetLogWithSource());
1172 test::StreamDelegateDoNothing delegateB(spdy_streamB);
1173 spdy_streamB->SetDelegate(&delegateB);
1174
1175 // Set up session C: Draining.
1176 StaticSocketDataProvider dataC(reads, writes);
1177 dataC.set_connect_data(connect_data);
1178 session_deps_.socket_factory->AddSocketDataProvider(&dataC);
1179
1180 AddSSLSocketData();
1181
1182 const std::string kTestHostC("mail.example.com");
1183 HostPortPair test_host_port_pairC(kTestHostC, 80);
1184 SpdySessionKey keyC(test_host_port_pairC, PRIVACY_MODE_DISABLED,
1185 ProxyChain::Direct(), SessionUsage::kDestination,
1186 SocketTag(), NetworkAnonymizationKey(),
1187 SecureDnsPolicy::kAllow,
1188 /*disable_cert_verification_network_fetches=*/false);
1189 base::WeakPtr<SpdySession> sessionC =
1190 CreateSpdySession(http_session_.get(), keyC, NetLogWithSource());
1191
1192 sessionC->CloseSessionOnError(ERR_HTTP2_PROTOCOL_ERROR, "Error!");
1193 EXPECT_TRUE(sessionC->IsDraining());
1194
1195 SimulateChange();
1196
1197 EXPECT_TRUE(sessionA->IsGoingAway());
1198 EXPECT_TRUE(sessionB->IsDraining());
1199 EXPECT_TRUE(sessionC->IsDraining());
1200
1201 EXPECT_EQ(1u,
1202 num_active_streams(sessionA)); // Active stream is still active.
1203 EXPECT_FALSE(delegateA.StreamIsClosed());
1204
1205 EXPECT_TRUE(delegateB.StreamIsClosed()); // Created stream was closed.
1206 EXPECT_THAT(delegateB.WaitForClose(), IsError(ExpectedNetError()));
1207
1208 sessionA->CloseSessionOnError(ERR_ABORTED, "Closing");
1209 sessionB->CloseSessionOnError(ERR_ABORTED, "Closing");
1210
1211 EXPECT_TRUE(delegateA.StreamIsClosed());
1212 EXPECT_THAT(delegateA.WaitForClose(), IsError(ERR_ABORTED));
1213 }
1214
1215 INSTANTIATE_TEST_SUITE_P(All,
1216 SpdySessionGoAwayOnChangeTest,
1217 testing::Values(ChangeType::kIpAddress,
1218 ChangeType::kSSLConfig,
1219 ChangeType::kCertDatabase,
1220 ChangeType::kCertVerifier));
1221
1222 // Construct a Pool with SpdySessions in various availability states. Simulate
1223 // an IP address change. Ensure sessions gracefully shut down. Regression test
1224 // for crbug.com/379469.
TEST_F(SpdySessionPoolTest,CloseOnIPAddressChanged)1225 TEST_F(SpdySessionPoolTest, CloseOnIPAddressChanged) {
1226 MockConnect connect_data(SYNCHRONOUS, OK);
1227 session_deps_.host_resolver->set_synchronous_mode(true);
1228
1229 // This isn't testing anything having to do with SPDY frames; we
1230 // can ignore issues of how dependencies are set. We default to
1231 // setting them (when doing the appropriate protocol) since that's
1232 // where we're eventually headed for all HTTP/2 connections.
1233 SpdyTestUtil spdy_util;
1234
1235 MockRead reads[] = {
1236 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
1237 };
1238 spdy::SpdySerializedFrame req(
1239 spdy_util.ConstructSpdyGet("http://www.example.org", 1, MEDIUM));
1240 MockWrite writes[] = {CreateMockWrite(req, 1)};
1241
1242 StaticSocketDataProvider dataA(reads, writes);
1243 dataA.set_connect_data(connect_data);
1244 session_deps_.socket_factory->AddSocketDataProvider(&dataA);
1245
1246 AddSSLSocketData();
1247
1248 session_deps_.go_away_on_ip_change = false;
1249 CreateNetworkSession();
1250
1251 // Set up session A: Going away, but with an active stream.
1252 const std::string kTestHostA("www.example.org");
1253 HostPortPair test_host_port_pairA(kTestHostA, 80);
1254 SpdySessionKey keyA(test_host_port_pairA, PRIVACY_MODE_DISABLED,
1255 ProxyChain::Direct(), SessionUsage::kDestination,
1256 SocketTag(), NetworkAnonymizationKey(),
1257 SecureDnsPolicy::kAllow,
1258 /*disable_cert_verification_network_fetches=*/false);
1259 base::WeakPtr<SpdySession> sessionA =
1260 CreateSpdySession(http_session_.get(), keyA, NetLogWithSource());
1261
1262 GURL urlA("http://www.example.org");
1263 base::WeakPtr<SpdyStream> spdy_streamA = CreateStreamSynchronously(
1264 SPDY_BIDIRECTIONAL_STREAM, sessionA, urlA, MEDIUM, NetLogWithSource());
1265 test::StreamDelegateDoNothing delegateA(spdy_streamA);
1266 spdy_streamA->SetDelegate(&delegateA);
1267
1268 spdy::Http2HeaderBlock headers(
1269 spdy_util.ConstructGetHeaderBlock(urlA.spec()));
1270 spdy_streamA->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
1271
1272 base::RunLoop().RunUntilIdle(); // Allow headers to write.
1273 EXPECT_TRUE(delegateA.send_headers_completed());
1274
1275 sessionA->MakeUnavailable();
1276 EXPECT_TRUE(sessionA->IsGoingAway());
1277 EXPECT_FALSE(delegateA.StreamIsClosed());
1278
1279 // Set up session B: Available, with a created stream.
1280 StaticSocketDataProvider dataB(reads, writes);
1281 dataB.set_connect_data(connect_data);
1282 session_deps_.socket_factory->AddSocketDataProvider(&dataB);
1283
1284 AddSSLSocketData();
1285
1286 const std::string kTestHostB("mail.example.org");
1287 HostPortPair test_host_port_pairB(kTestHostB, 80);
1288 SpdySessionKey keyB(test_host_port_pairB, PRIVACY_MODE_DISABLED,
1289 ProxyChain::Direct(), SessionUsage::kDestination,
1290 SocketTag(), NetworkAnonymizationKey(),
1291 SecureDnsPolicy::kAllow,
1292 /*disable_cert_verification_network_fetches=*/false);
1293 base::WeakPtr<SpdySession> sessionB =
1294 CreateSpdySession(http_session_.get(), keyB, NetLogWithSource());
1295 EXPECT_TRUE(sessionB->IsAvailable());
1296
1297 GURL urlB("http://mail.example.org");
1298 base::WeakPtr<SpdyStream> spdy_streamB = CreateStreamSynchronously(
1299 SPDY_BIDIRECTIONAL_STREAM, sessionB, urlB, MEDIUM, NetLogWithSource());
1300 test::StreamDelegateDoNothing delegateB(spdy_streamB);
1301 spdy_streamB->SetDelegate(&delegateB);
1302
1303 // Set up session C: Draining.
1304 StaticSocketDataProvider dataC(reads, writes);
1305 dataC.set_connect_data(connect_data);
1306 session_deps_.socket_factory->AddSocketDataProvider(&dataC);
1307
1308 AddSSLSocketData();
1309
1310 const std::string kTestHostC("mail.example.com");
1311 HostPortPair test_host_port_pairC(kTestHostC, 80);
1312 SpdySessionKey keyC(test_host_port_pairC, PRIVACY_MODE_DISABLED,
1313 ProxyChain::Direct(), SessionUsage::kDestination,
1314 SocketTag(), NetworkAnonymizationKey(),
1315 SecureDnsPolicy::kAllow,
1316 /*disable_cert_verification_network_fetches=*/false);
1317 base::WeakPtr<SpdySession> sessionC =
1318 CreateSpdySession(http_session_.get(), keyC, NetLogWithSource());
1319
1320 sessionC->CloseSessionOnError(ERR_HTTP2_PROTOCOL_ERROR, "Error!");
1321 EXPECT_TRUE(sessionC->IsDraining());
1322
1323 spdy_session_pool_->OnIPAddressChanged();
1324
1325 EXPECT_TRUE(sessionA->IsDraining());
1326 EXPECT_TRUE(sessionB->IsDraining());
1327 EXPECT_TRUE(sessionC->IsDraining());
1328
1329 // Both streams were closed with an error.
1330 EXPECT_TRUE(delegateA.StreamIsClosed());
1331 EXPECT_THAT(delegateA.WaitForClose(), IsError(ERR_NETWORK_CHANGED));
1332 EXPECT_TRUE(delegateB.StreamIsClosed());
1333 EXPECT_THAT(delegateB.WaitForClose(), IsError(ERR_NETWORK_CHANGED));
1334 }
1335
1336 // Regression test for https://crbug.com/789791.
TEST_F(SpdySessionPoolTest,HandleIPAddressChangeThenShutdown)1337 TEST_F(SpdySessionPoolTest, HandleIPAddressChangeThenShutdown) {
1338 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
1339 SpdyTestUtil spdy_util;
1340 spdy::SpdySerializedFrame req(
1341 spdy_util.ConstructSpdyGet(kDefaultUrl, 1, MEDIUM));
1342 MockWrite writes[] = {CreateMockWrite(req, 1)};
1343 StaticSocketDataProvider data(reads, writes);
1344
1345 MockConnect connect_data(SYNCHRONOUS, OK);
1346 data.set_connect_data(connect_data);
1347
1348 session_deps_.socket_factory->AddSocketDataProvider(&data);
1349 AddSSLSocketData();
1350
1351 CreateNetworkSession();
1352
1353 const GURL url(kDefaultUrl);
1354 SpdySessionKey key(HostPortPair::FromURL(url), PRIVACY_MODE_DISABLED,
1355 ProxyChain::Direct(), SessionUsage::kDestination,
1356 SocketTag(), NetworkAnonymizationKey(),
1357 SecureDnsPolicy::kAllow,
1358 /*disable_cert_verification_network_fetches=*/false);
1359 base::WeakPtr<SpdySession> session =
1360 CreateSpdySession(http_session_.get(), key, NetLogWithSource());
1361
1362 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
1363 SPDY_BIDIRECTIONAL_STREAM, session, url, MEDIUM, NetLogWithSource());
1364 test::StreamDelegateDoNothing delegate(spdy_stream);
1365 spdy_stream->SetDelegate(&delegate);
1366
1367 spdy::Http2HeaderBlock headers(spdy_util.ConstructGetHeaderBlock(url.spec()));
1368 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
1369
1370 base::RunLoop().RunUntilIdle();
1371 EXPECT_TRUE(delegate.send_headers_completed());
1372
1373 spdy_session_pool_->OnIPAddressChanged();
1374
1375 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
1376 EXPECT_EQ(1u, num_active_streams(session));
1377 EXPECT_TRUE(session->IsGoingAway());
1378 EXPECT_FALSE(session->IsDraining());
1379 #else
1380 EXPECT_EQ(0u, num_active_streams(session));
1381 EXPECT_FALSE(session->IsGoingAway());
1382 EXPECT_TRUE(session->IsDraining());
1383 #endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
1384
1385 http_session_.reset();
1386
1387 data.AllReadDataConsumed();
1388 data.AllWriteDataConsumed();
1389 }
1390
1391 // Regression test for https://crbug.com/789791.
TEST_F(SpdySessionPoolTest,HandleGracefulGoawayThenShutdown)1392 TEST_F(SpdySessionPoolTest, HandleGracefulGoawayThenShutdown) {
1393 SpdyTestUtil spdy_util;
1394 spdy::SpdySerializedFrame goaway(spdy_util.ConstructSpdyGoAway(
1395 0x7fffffff, spdy::ERROR_CODE_NO_ERROR, "Graceful shutdown."));
1396 MockRead reads[] = {
1397 MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(goaway, 2),
1398 MockRead(ASYNC, ERR_IO_PENDING, 3), MockRead(ASYNC, OK, 4)};
1399 spdy::SpdySerializedFrame req(
1400 spdy_util.ConstructSpdyGet(kDefaultUrl, 1, MEDIUM));
1401 MockWrite writes[] = {CreateMockWrite(req, 0)};
1402 SequencedSocketData data(reads, writes);
1403
1404 MockConnect connect_data(SYNCHRONOUS, OK);
1405 data.set_connect_data(connect_data);
1406
1407 session_deps_.socket_factory->AddSocketDataProvider(&data);
1408 AddSSLSocketData();
1409
1410 CreateNetworkSession();
1411
1412 const GURL url(kDefaultUrl);
1413 SpdySessionKey key(HostPortPair::FromURL(url), PRIVACY_MODE_DISABLED,
1414 ProxyChain::Direct(), SessionUsage::kDestination,
1415 SocketTag(), NetworkAnonymizationKey(),
1416 SecureDnsPolicy::kAllow,
1417 /*disable_cert_verification_network_fetches=*/false);
1418 base::WeakPtr<SpdySession> session =
1419 CreateSpdySession(http_session_.get(), key, NetLogWithSource());
1420
1421 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
1422 SPDY_BIDIRECTIONAL_STREAM, session, url, MEDIUM, NetLogWithSource());
1423 test::StreamDelegateDoNothing delegate(spdy_stream);
1424 spdy_stream->SetDelegate(&delegate);
1425
1426 spdy::Http2HeaderBlock headers(spdy_util.ConstructGetHeaderBlock(url.spec()));
1427 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
1428
1429 // Send headers.
1430 base::RunLoop().RunUntilIdle();
1431 EXPECT_TRUE(delegate.send_headers_completed());
1432
1433 EXPECT_EQ(1u, num_active_streams(session));
1434 EXPECT_FALSE(session->IsGoingAway());
1435 EXPECT_FALSE(session->IsDraining());
1436
1437 // Read GOAWAY.
1438 data.Resume();
1439 base::RunLoop().RunUntilIdle();
1440
1441 EXPECT_EQ(1u, num_active_streams(session));
1442 EXPECT_TRUE(session->IsGoingAway());
1443 EXPECT_FALSE(session->IsDraining());
1444
1445 http_session_.reset();
1446
1447 data.AllReadDataConsumed();
1448 data.AllWriteDataConsumed();
1449 }
1450
TEST_F(SpdySessionPoolTest,IPConnectionPoolingWithWebSockets)1451 TEST_F(SpdySessionPoolTest, IPConnectionPoolingWithWebSockets) {
1452 // Define two hosts with identical IP address.
1453 const int kTestPort = 443;
1454 struct TestHosts {
1455 std::string name;
1456 std::string iplist;
1457 SpdySessionKey key;
1458 } test_hosts[] = {
1459 {"www.example.org", "192.168.0.1"}, {"mail.example.org", "192.168.0.1"},
1460 };
1461
1462 // Populate the HostResolver cache.
1463 session_deps_.host_resolver->set_synchronous_mode(true);
1464 for (auto& test_host : test_hosts) {
1465 session_deps_.host_resolver->rules()->AddIPLiteralRule(
1466 test_host.name, test_host.iplist, std::string());
1467
1468 test_host.key = SpdySessionKey(
1469 HostPortPair(test_host.name, kTestPort), PRIVACY_MODE_DISABLED,
1470 ProxyChain::Direct(), SessionUsage::kDestination, SocketTag(),
1471 NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
1472 /*disable_cert_verification_network_fetches=*/false);
1473 }
1474
1475 SpdyTestUtil spdy_util;
1476
1477 spdy::SpdySerializedFrame req(
1478 spdy_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1479 spdy::SpdySerializedFrame settings_ack(spdy_util.ConstructSpdySettingsAck());
1480 MockWrite writes[] = {CreateMockWrite(req, 0),
1481 CreateMockWrite(settings_ack, 2)};
1482
1483 spdy::SettingsMap settings;
1484 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
1485 spdy::SpdySerializedFrame settings_frame(
1486 spdy_util.ConstructSpdySettings(settings));
1487 spdy::SpdySerializedFrame resp(
1488 spdy_util.ConstructSpdyGetReply(nullptr, 0, 1));
1489 spdy::SpdySerializedFrame body(spdy_util.ConstructSpdyDataFrame(1, true));
1490 MockRead reads[] = {CreateMockRead(settings_frame, 1),
1491 CreateMockRead(resp, 3), CreateMockRead(body, 4),
1492 MockRead(ASYNC, ERR_IO_PENDING, 5),
1493 MockRead(ASYNC, 0, 6)};
1494
1495 SequencedSocketData data(reads, writes);
1496 session_deps_.socket_factory->AddSocketDataProvider(&data);
1497 AddSSLSocketData();
1498 CreateNetworkSession();
1499
1500 // Create a connection to the first host.
1501 base::WeakPtr<SpdySession> session = CreateSpdySession(
1502 http_session_.get(), test_hosts[0].key, NetLogWithSource());
1503
1504 // SpdySession does not support Websocket before SETTINGS frame is read.
1505 EXPECT_FALSE(session->support_websocket());
1506 NetLogWithSource net_log_with_source{
1507 NetLogWithSource::Make(NetLogSourceType::NONE)};
1508 // TryCreateAliasedSpdySession should not find |session| for either
1509 // SpdySessionKeys if |is_websocket| argument is set.
1510 EXPECT_FALSE(TryCreateAliasedSpdySession(
1511 spdy_session_pool_, test_hosts[0].key, test_hosts[0].iplist,
1512 /* enable_ip_based_pooling = */ true,
1513 /* is_websocket = */ true));
1514 EXPECT_FALSE(TryCreateAliasedSpdySession(
1515 spdy_session_pool_, test_hosts[1].key, test_hosts[1].iplist,
1516 /* enable_ip_based_pooling = */ true,
1517 /* is_websocket = */ true));
1518
1519 // Start request that triggers reading the SETTINGS frame.
1520 const GURL url(kDefaultUrl);
1521 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
1522 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, NetLogWithSource());
1523 test::StreamDelegateDoNothing delegate(spdy_stream);
1524 spdy_stream->SetDelegate(&delegate);
1525
1526 spdy::Http2HeaderBlock headers(spdy_util.ConstructGetHeaderBlock(url.spec()));
1527 spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
1528
1529 base::RunLoop().RunUntilIdle();
1530
1531 // Now SpdySession has read the SETTINGS frame and thus supports Websocket.
1532 EXPECT_TRUE(session->support_websocket());
1533
1534 // FindAvailableSession() on the first host should now find the existing
1535 // session with websockets enabled, and TryCreateAliasedSpdySession() should
1536 // now set up aliases for |session| for the second one.
1537 base::WeakPtr<SpdySession> result = spdy_session_pool_->FindAvailableSession(
1538 test_hosts[0].key, /* enable_ip_based_pooling = */ true,
1539 /* is_websocket = */ true, net_log_with_source);
1540 EXPECT_EQ(session.get(), result.get());
1541 EXPECT_TRUE(TryCreateAliasedSpdySession(spdy_session_pool_, test_hosts[1].key,
1542 test_hosts[1].iplist,
1543 /* enable_ip_based_pooling = */ true,
1544 /* is_websocket = */ true));
1545
1546 // FindAvailableSession() should return |session| for either SpdySessionKeys
1547 // when IP based pooling is enabled.
1548 result = spdy_session_pool_->FindAvailableSession(
1549 test_hosts[0].key, /* enable_ip_based_pooling = */ true,
1550 /* is_websocket = */ true, net_log_with_source);
1551 EXPECT_EQ(session.get(), result.get());
1552 result = spdy_session_pool_->FindAvailableSession(
1553 test_hosts[1].key, /* enable_ip_based_pooling = */ true,
1554 /* is_websocket = */ true, net_log_with_source);
1555 EXPECT_EQ(session.get(), result.get());
1556
1557 // FindAvailableSession() should only return |session| for the first
1558 // SpdySessionKey when IP based pooling is disabled.
1559 result = spdy_session_pool_->FindAvailableSession(
1560 test_hosts[0].key, /* enable_ip_based_pooling = */ false,
1561 /* is_websocket = */ true, net_log_with_source);
1562 EXPECT_EQ(session.get(), result.get());
1563 result = spdy_session_pool_->FindAvailableSession(
1564 test_hosts[1].key, /* enable_ip_based_pooling = */ false,
1565 /* is_websocket = */ true, net_log_with_source);
1566 EXPECT_FALSE(result);
1567
1568 // Read EOF.
1569 data.Resume();
1570 base::RunLoop().RunUntilIdle();
1571
1572 EXPECT_TRUE(data.AllReadDataConsumed());
1573 EXPECT_TRUE(data.AllWriteDataConsumed());
1574 }
1575
1576 class TestOnRequestDeletedCallback {
1577 public:
1578 TestOnRequestDeletedCallback() = default;
1579
1580 TestOnRequestDeletedCallback(const TestOnRequestDeletedCallback&) = delete;
1581 TestOnRequestDeletedCallback& operator=(const TestOnRequestDeletedCallback&) =
1582 delete;
1583
1584 ~TestOnRequestDeletedCallback() = default;
1585
Callback()1586 base::RepeatingClosure Callback() {
1587 return base::BindRepeating(&TestOnRequestDeletedCallback::OnRequestDeleted,
1588 base::Unretained(this));
1589 }
1590
invoked() const1591 bool invoked() const { return invoked_; }
1592
WaitUntilInvoked()1593 void WaitUntilInvoked() { run_loop_.Run(); }
1594
SetRequestDeletedCallback(base::OnceClosure request_deleted_callback)1595 void SetRequestDeletedCallback(base::OnceClosure request_deleted_callback) {
1596 DCHECK(!request_deleted_callback_);
1597 request_deleted_callback_ = std::move(request_deleted_callback);
1598 }
1599
1600 private:
OnRequestDeleted()1601 void OnRequestDeleted() {
1602 EXPECT_FALSE(invoked_);
1603 invoked_ = true;
1604 if (request_deleted_callback_)
1605 std::move(request_deleted_callback_).Run();
1606 run_loop_.Quit();
1607 }
1608
1609 bool invoked_ = false;
1610 base::RunLoop run_loop_;
1611
1612 base::OnceClosure request_deleted_callback_;
1613 };
1614
1615 class TestRequestDelegate
1616 : public SpdySessionPool::SpdySessionRequest::Delegate {
1617 public:
1618 TestRequestDelegate() = default;
1619
1620 TestRequestDelegate(const TestRequestDelegate&) = delete;
1621 TestRequestDelegate& operator=(const TestRequestDelegate&) = delete;
1622
1623 ~TestRequestDelegate() override = default;
1624
1625 // SpdySessionPool::SpdySessionRequest::Delegate implementation:
OnSpdySessionAvailable(base::WeakPtr<SpdySession> spdy_session)1626 void OnSpdySessionAvailable(
1627 base::WeakPtr<SpdySession> spdy_session) override {}
1628 };
1629
TEST_F(SpdySessionPoolTest,RequestSessionWithNoSessions)1630 TEST_F(SpdySessionPoolTest, RequestSessionWithNoSessions) {
1631 const SpdySessionKey kSessionKey(
1632 HostPortPair("foo.test", 443), PRIVACY_MODE_DISABLED,
1633 ProxyChain::Direct(), SessionUsage::kDestination, SocketTag(),
1634 NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
1635 /*disable_cert_verification_network_fetches=*/false);
1636
1637 CreateNetworkSession();
1638
1639 // First request. Its request deleted callback should never be invoked.
1640 TestOnRequestDeletedCallback request_deleted_callback1;
1641 TestRequestDelegate request_delegate1;
1642 std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request1;
1643 bool is_first_request_for_session;
1644 EXPECT_FALSE(spdy_session_pool_->RequestSession(
1645 kSessionKey, /* enable_ip_based_pooling = */ false,
1646 /* is_websocket = */ false, NetLogWithSource(),
1647 request_deleted_callback1.Callback(), &request_delegate1,
1648 &spdy_session_request1, &is_first_request_for_session));
1649 EXPECT_TRUE(is_first_request_for_session);
1650
1651 // Second request.
1652 TestOnRequestDeletedCallback request_deleted_callback2;
1653 TestRequestDelegate request_delegate2;
1654 std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request2;
1655 EXPECT_FALSE(spdy_session_pool_->RequestSession(
1656 kSessionKey, /* enable_ip_based_pooling = */ false,
1657 /* is_websocket = */ false, NetLogWithSource(),
1658 request_deleted_callback2.Callback(), &request_delegate2,
1659 &spdy_session_request2, &is_first_request_for_session));
1660 EXPECT_FALSE(is_first_request_for_session);
1661
1662 // Third request.
1663 TestOnRequestDeletedCallback request_deleted_callback3;
1664 TestRequestDelegate request_delegate3;
1665 std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request3;
1666 EXPECT_FALSE(spdy_session_pool_->RequestSession(
1667 kSessionKey, /* enable_ip_based_pooling = */ false,
1668 /* is_websocket = */ false, NetLogWithSource(),
1669 request_deleted_callback3.Callback(), &request_delegate3,
1670 &spdy_session_request3, &is_first_request_for_session));
1671 EXPECT_FALSE(is_first_request_for_session);
1672
1673 // Destroying the second request shouldn't cause anything to happen.
1674 spdy_session_request2.reset();
1675 base::RunLoop().RunUntilIdle();
1676 EXPECT_FALSE(request_deleted_callback1.invoked());
1677 EXPECT_FALSE(request_deleted_callback2.invoked());
1678 EXPECT_FALSE(request_deleted_callback3.invoked());
1679
1680 // But destroying the first request should cause the second and third
1681 // callbacks to be invoked.
1682 spdy_session_request1.reset();
1683 request_deleted_callback2.WaitUntilInvoked();
1684 request_deleted_callback3.WaitUntilInvoked();
1685 EXPECT_FALSE(request_deleted_callback1.invoked());
1686
1687 // Nothing should happen when the third request is destroyed.
1688 spdy_session_request3.reset();
1689 base::RunLoop().RunUntilIdle();
1690 EXPECT_FALSE(request_deleted_callback1.invoked());
1691 }
1692
TEST_F(SpdySessionPoolTest,RequestSessionDuringNotification)1693 TEST_F(SpdySessionPoolTest, RequestSessionDuringNotification) {
1694 const SpdySessionKey kSessionKey(
1695 HostPortPair("foo.test", 443), PRIVACY_MODE_DISABLED,
1696 ProxyChain::Direct(), SessionUsage::kDestination, SocketTag(),
1697 NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
1698 /*disable_cert_verification_network_fetches=*/false);
1699
1700 CreateNetworkSession();
1701
1702 // First request. Its request deleted callback should never be invoked.
1703 TestOnRequestDeletedCallback request_deleted_callback1;
1704 TestRequestDelegate request_delegate1;
1705 std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request1;
1706 bool is_first_request_for_session;
1707 EXPECT_FALSE(spdy_session_pool_->RequestSession(
1708 kSessionKey, /* enable_ip_based_pooling = */ false,
1709 /* is_websocket = */ false, NetLogWithSource(),
1710 request_deleted_callback1.Callback(), &request_delegate1,
1711 &spdy_session_request1, &is_first_request_for_session));
1712 EXPECT_TRUE(is_first_request_for_session);
1713
1714 // Second request.
1715 TestOnRequestDeletedCallback request_deleted_callback2;
1716 TestRequestDelegate request_delegate2;
1717 std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request2;
1718 EXPECT_FALSE(spdy_session_pool_->RequestSession(
1719 kSessionKey, /* enable_ip_based_pooling = */ false,
1720 /* is_websocket = */ false, NetLogWithSource(),
1721 request_deleted_callback2.Callback(), &request_delegate2,
1722 &spdy_session_request2, &is_first_request_for_session));
1723 EXPECT_FALSE(is_first_request_for_session);
1724
1725 TestOnRequestDeletedCallback request_deleted_callback3;
1726 TestRequestDelegate request_delegate3;
1727 std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request3;
1728 TestOnRequestDeletedCallback request_deleted_callback4;
1729 TestRequestDelegate request_delegate4;
1730 std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request4;
1731 request_deleted_callback2.SetRequestDeletedCallback(
1732 base::BindLambdaForTesting([&]() {
1733 // Third request. It should again be marked as the first request for the
1734 // session, since it's only created after the original two have been
1735 // removed.
1736 bool is_first_request_for_session;
1737 EXPECT_FALSE(spdy_session_pool_->RequestSession(
1738 kSessionKey, /* enable_ip_based_pooling = */ false,
1739 /* is_websocket = */ false, NetLogWithSource(),
1740 request_deleted_callback3.Callback(), &request_delegate3,
1741 &spdy_session_request3, &is_first_request_for_session));
1742 EXPECT_TRUE(is_first_request_for_session);
1743
1744 // Fourth request.
1745 EXPECT_FALSE(spdy_session_pool_->RequestSession(
1746 kSessionKey, /* enable_ip_based_pooling = */ false,
1747 /* is_websocket = */ false, NetLogWithSource(),
1748 request_deleted_callback4.Callback(), &request_delegate4,
1749 &spdy_session_request4, &is_first_request_for_session));
1750 EXPECT_FALSE(is_first_request_for_session);
1751 }));
1752
1753 // Destroying the first request should cause the second callback to be
1754 // invoked, and the third and fourth request to be made.
1755 spdy_session_request1.reset();
1756 request_deleted_callback2.WaitUntilInvoked();
1757 base::RunLoop().RunUntilIdle();
1758 EXPECT_FALSE(request_deleted_callback1.invoked());
1759 EXPECT_FALSE(request_deleted_callback3.invoked());
1760 EXPECT_FALSE(request_deleted_callback4.invoked());
1761 EXPECT_TRUE(spdy_session_request3);
1762 EXPECT_TRUE(spdy_session_request4);
1763
1764 // Destroying the third request should cause the fourth callback to be
1765 // invoked.
1766 spdy_session_request3.reset();
1767 request_deleted_callback4.WaitUntilInvoked();
1768 EXPECT_FALSE(request_deleted_callback1.invoked());
1769 EXPECT_FALSE(request_deleted_callback3.invoked());
1770 }
1771
1772 static const char kSSLServerTestHost[] = "config-changed.test";
1773
1774 static const struct {
1775 const char* url;
1776 const char* proxy_pac_string;
1777 bool expect_invalidated;
1778 } kSSLServerTests[] = {
1779 // If the host and port match, the session should be invalidated.
1780 {"https://config-changed.test", "DIRECT", true},
1781 // If host and port do not match, the session should not be invalidated.
1782 {"https://mail.config-changed.test", "DIRECT", false},
1783 {"https://config-changed.test:444", "DIRECT", false},
1784 // If the proxy matches, the session should be invalidated independent of
1785 // the host.
1786 {"https://config-changed.test", "HTTPS config-changed.test:443", true},
1787 {"https://mail.config-changed.test", "HTTPS config-changed.test:443", true},
1788 // HTTP and SOCKS proxies do not have client certificates.
1789 {"https://mail.config-changed.test", "PROXY config-changed.test:443",
1790 false},
1791 {"https://mail.config-changed.test", "SOCKS5 config-changed.test:443",
1792 false},
1793 // The proxy host and port must match.
1794 {"https://mail.config-changed.test", "HTTPS mail.config-changed.test:443",
1795 false},
1796 {"https://mail.config-changed.test", "HTTPS config-changed.test:444",
1797 false},
1798 };
1799
1800 // Tests the OnSSLConfigForServersChanged() method matches SpdySessions as
1801 // expected.
TEST_F(SpdySessionPoolTest,SSLConfigForServerChanged)1802 TEST_F(SpdySessionPoolTest, SSLConfigForServerChanged) {
1803 const MockConnect connect_data(SYNCHRONOUS, OK);
1804 const MockRead reads[] = {
1805 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
1806 };
1807
1808 std::vector<std::unique_ptr<StaticSocketDataProvider>> socket_data;
1809 size_t num_tests = std::size(kSSLServerTests);
1810 for (size_t i = 0; i < num_tests; i++) {
1811 socket_data.push_back(std::make_unique<StaticSocketDataProvider>(
1812 reads, base::span<MockWrite>()));
1813 socket_data.back()->set_connect_data(connect_data);
1814 session_deps_.socket_factory->AddSocketDataProvider(
1815 socket_data.back().get());
1816 AddSSLSocketData();
1817 }
1818
1819 CreateNetworkSession();
1820
1821 std::vector<base::WeakPtr<SpdySession>> sessions;
1822 for (size_t i = 0; i < num_tests; i++) {
1823 SpdySessionKey key(
1824 HostPortPair::FromURL(GURL(kSSLServerTests[i].url)),
1825 PRIVACY_MODE_DISABLED,
1826 PacResultElementToProxyChain(kSSLServerTests[i].proxy_pac_string),
1827 SessionUsage::kDestination, SocketTag(), NetworkAnonymizationKey(),
1828 SecureDnsPolicy::kAllow,
1829 /*disable_cert_verification_network_fetches=*/false);
1830 sessions.push_back(
1831 CreateSpdySession(http_session_.get(), key, NetLogWithSource()));
1832 }
1833
1834 // All sessions are available.
1835 for (size_t i = 0; i < num_tests; i++) {
1836 SCOPED_TRACE(i);
1837 EXPECT_TRUE(sessions[i]->IsAvailable());
1838 }
1839
1840 spdy_session_pool_->OnSSLConfigForServersChanged(
1841 {HostPortPair(kSSLServerTestHost, 443)});
1842 base::RunLoop().RunUntilIdle();
1843
1844 // Sessions were inactive, so the unavailable sessions are closed.
1845 for (size_t i = 0; i < num_tests; i++) {
1846 SCOPED_TRACE(i);
1847 if (kSSLServerTests[i].expect_invalidated) {
1848 EXPECT_FALSE(sessions[i]);
1849 } else {
1850 ASSERT_TRUE(sessions[i]);
1851 EXPECT_TRUE(sessions[i]->IsAvailable());
1852 }
1853 }
1854 }
1855
1856 // Tests the OnSSLConfigForServersChanged() method matches SpdySessions
1857 // containing proxy chains.
TEST_F(SpdySessionPoolTest,SSLConfigForServerChangedWithProxyChain)1858 TEST_F(SpdySessionPoolTest, SSLConfigForServerChangedWithProxyChain) {
1859 const MockConnect connect_data(SYNCHRONOUS, OK);
1860 const MockRead reads[] = {
1861 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
1862 };
1863
1864 ProxyChain proxy_chain({
1865 ProxyServer::FromSchemeHostAndPort(ProxyServer::Scheme::SCHEME_HTTPS,
1866 "proxya", 443),
1867 ProxyServer::FromSchemeHostAndPort(ProxyServer::Scheme::SCHEME_HTTPS,
1868 "proxyb", 443),
1869 ProxyServer::FromSchemeHostAndPort(ProxyServer::Scheme::SCHEME_HTTPS,
1870 "proxyc", 443),
1871 });
1872
1873 std::vector<std::unique_ptr<StaticSocketDataProvider>> socket_data;
1874 socket_data.push_back(std::make_unique<StaticSocketDataProvider>(
1875 reads, base::span<MockWrite>()));
1876 socket_data.back()->set_connect_data(connect_data);
1877 session_deps_.socket_factory->AddSocketDataProvider(socket_data.back().get());
1878 AddSSLSocketData();
1879
1880 CreateNetworkSession();
1881
1882 SpdySessionKey key(HostPortPair::FromURL(GURL("https://example.com")),
1883 PRIVACY_MODE_DISABLED, proxy_chain,
1884 SessionUsage::kDestination, SocketTag(),
1885 NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
1886 /*disable_cert_verification_network_fetches=*/false);
1887 base::WeakPtr<SpdySession> session =
1888 CreateSpdySession(http_session_.get(), key, NetLogWithSource());
1889
1890 EXPECT_TRUE(session->IsAvailable());
1891
1892 spdy_session_pool_->OnSSLConfigForServersChanged(
1893 {HostPortPair("proxyb", 443)});
1894 base::RunLoop().RunUntilIdle();
1895
1896 // The unavailable session is closed.
1897 EXPECT_FALSE(session);
1898 }
1899
1900 // Tests the OnSSLConfigForServersChanged() method when there are streams open.
TEST_F(SpdySessionPoolTest,SSLConfigForServerChangedWithStreams)1901 TEST_F(SpdySessionPoolTest, SSLConfigForServerChangedWithStreams) {
1902 // Set up a SpdySession with an active, created, and pending stream.
1903 SpdyTestUtil spdy_util;
1904 spdy::SettingsMap settings;
1905 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = 2;
1906 spdy::SpdySerializedFrame settings_frame =
1907 spdy_util.ConstructSpdySettings(settings);
1908 spdy::SpdySerializedFrame settings_ack = spdy_util.ConstructSpdySettingsAck();
1909 spdy::SpdySerializedFrame req(
1910 spdy_util.ConstructSpdyGet(nullptr, 0, 1, MEDIUM));
1911
1912 const MockConnect connect_data(SYNCHRONOUS, OK);
1913 const MockRead reads[] = {
1914 CreateMockRead(settings_frame),
1915 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
1916 };
1917 const MockWrite writes[] = {
1918 CreateMockWrite(settings_ack),
1919 CreateMockWrite(req),
1920 };
1921
1922 StaticSocketDataProvider socket_data(reads, writes);
1923 socket_data.set_connect_data(connect_data);
1924 session_deps_.socket_factory->AddSocketDataProvider(&socket_data);
1925 AddSSLSocketData();
1926
1927 CreateNetworkSession();
1928
1929 const GURL url(kDefaultUrl);
1930 SpdySessionKey key(HostPortPair::FromURL(url), PRIVACY_MODE_DISABLED,
1931 ProxyChain::Direct(), SessionUsage::kDestination,
1932 SocketTag(), NetworkAnonymizationKey(),
1933 SecureDnsPolicy::kAllow,
1934 /*disable_cert_verification_network_fetches=*/false);
1935 base::WeakPtr<SpdySession> session =
1936 CreateSpdySession(http_session_.get(), key, NetLogWithSource());
1937
1938 // Pick up the SETTINGS frame to update SETTINGS_MAX_CONCURRENT_STREAMS.
1939 base::RunLoop().RunUntilIdle();
1940 EXPECT_EQ(2u, max_concurrent_streams(session));
1941
1942 // The first two stream requests should succeed.
1943 base::WeakPtr<SpdyStream> active_stream = CreateStreamSynchronously(
1944 SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, NetLogWithSource());
1945 test::StreamDelegateDoNothing active_stream_delegate(active_stream);
1946 active_stream->SetDelegate(&active_stream_delegate);
1947 base::WeakPtr<SpdyStream> created_stream = CreateStreamSynchronously(
1948 SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, NetLogWithSource());
1949 test::StreamDelegateDoNothing created_stream_delegate(created_stream);
1950 created_stream->SetDelegate(&created_stream_delegate);
1951
1952 // The third will block.
1953 TestCompletionCallback callback;
1954 SpdyStreamRequest stream_request;
1955 EXPECT_THAT(
1956 stream_request.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session, url,
1957 /*can_send_early=*/false, MEDIUM, SocketTag(),
1958 NetLogWithSource(), callback.callback(),
1959 TRAFFIC_ANNOTATION_FOR_TESTS),
1960 IsError(ERR_IO_PENDING));
1961
1962 // Activate the first stream by sending data.
1963 spdy::Http2HeaderBlock headers(spdy_util.ConstructGetHeaderBlock(url.spec()));
1964 active_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
1965 base::RunLoop().RunUntilIdle();
1966
1967 // The active stream should now have a stream ID.
1968 EXPECT_EQ(1u, active_stream->stream_id());
1969 EXPECT_EQ(spdy::kInvalidStreamId, created_stream->stream_id());
1970 EXPECT_TRUE(session->is_active());
1971 EXPECT_TRUE(session->IsAvailable());
1972
1973 spdy_session_pool_->OnSSLConfigForServersChanged(
1974 {HostPortPair::FromURL(url)});
1975 base::RunLoop().RunUntilIdle();
1976
1977 // The active stream is still alive, so the session is still active.
1978 ASSERT_TRUE(session);
1979 EXPECT_TRUE(session->is_active());
1980 ASSERT_TRUE(active_stream);
1981
1982 // The session is no longer available.
1983 EXPECT_FALSE(session->IsAvailable());
1984 EXPECT_TRUE(session->IsGoingAway());
1985
1986 // The pending and created stream are cancelled.
1987 // TODO(https://crbug.com/1213609): Ideally, this would be recoverable.
1988 EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NETWORK_CHANGED));
1989 EXPECT_THAT(created_stream_delegate.WaitForClose(),
1990 IsError(ERR_NETWORK_CHANGED));
1991
1992 // Close the active stream.
1993 active_stream->Close();
1994 // TODO(https://crbug.com/982499): The invalidated session should be closed
1995 // after a RunUntilIdle(), but it is not.
1996 }
1997
1998 // Tests the OnSSLConfigForServersChanged() method when there only pending
1999 // streams active.
TEST_F(SpdySessionPoolTest,SSLConfigForServerChangedWithOnlyPendingStreams)2000 TEST_F(SpdySessionPoolTest, SSLConfigForServerChangedWithOnlyPendingStreams) {
2001 // Set up a SpdySession that accepts no streams.
2002 SpdyTestUtil spdy_util;
2003 spdy::SettingsMap settings;
2004 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = 0;
2005 spdy::SpdySerializedFrame settings_frame =
2006 spdy_util.ConstructSpdySettings(settings);
2007 spdy::SpdySerializedFrame settings_ack = spdy_util.ConstructSpdySettingsAck();
2008
2009 const MockConnect connect_data(SYNCHRONOUS, OK);
2010 const MockRead reads[] = {
2011 CreateMockRead(settings_frame),
2012 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
2013 };
2014 const MockWrite writes[] = {
2015 CreateMockWrite(settings_ack),
2016 };
2017
2018 StaticSocketDataProvider socket_data(reads, writes);
2019 socket_data.set_connect_data(connect_data);
2020 session_deps_.socket_factory->AddSocketDataProvider(&socket_data);
2021 AddSSLSocketData();
2022
2023 CreateNetworkSession();
2024
2025 const GURL url(kDefaultUrl);
2026 SpdySessionKey key(HostPortPair::FromURL(url), PRIVACY_MODE_DISABLED,
2027 ProxyChain::Direct(), SessionUsage::kDestination,
2028 SocketTag(), NetworkAnonymizationKey(),
2029 SecureDnsPolicy::kAllow,
2030 /*disable_cert_verification_network_fetches=*/false);
2031 base::WeakPtr<SpdySession> session =
2032 CreateSpdySession(http_session_.get(), key, NetLogWithSource());
2033
2034 // Pick up the SETTINGS frame to update SETTINGS_MAX_CONCURRENT_STREAMS.
2035 base::RunLoop().RunUntilIdle();
2036 EXPECT_EQ(0u, max_concurrent_streams(session));
2037
2038 // Create a stream. It should block on the stream limit.
2039 TestCompletionCallback callback;
2040 SpdyStreamRequest stream_request;
2041 ASSERT_THAT(
2042 stream_request.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session, url,
2043 /*can_send_early=*/false, MEDIUM, SocketTag(),
2044 NetLogWithSource(), callback.callback(),
2045 TRAFFIC_ANNOTATION_FOR_TESTS),
2046 IsError(ERR_IO_PENDING));
2047
2048 spdy_session_pool_->OnSSLConfigForServersChanged(
2049 {HostPortPair::FromURL(url)});
2050 base::RunLoop().RunUntilIdle();
2051
2052 // The pending stream is cancelled.
2053 // TODO(https://crbug.com/1213609): Ideally, this would be recoverable.
2054 EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NETWORK_CHANGED));
2055 EXPECT_FALSE(session);
2056 }
2057
2058 } // namespace net
2059