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