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