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