| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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.h" | |
| 6 | |
| 7 #include "net/base/ip_endpoint.h" | |
| 8 #include "net/base/net_log_unittest.h" | |
| 9 #include "net/spdy/spdy_io_buffer.h" | |
| 10 #include "net/spdy/spdy_session_pool.h" | |
| 11 #include "net/spdy/spdy_stream.h" | |
| 12 #include "net/spdy/spdy_test_util.h" | |
| 13 #include "testing/platform_test.h" | |
| 14 | |
| 15 namespace net { | |
| 16 | |
| 17 // TODO(cbentzel): Expose compression setter/getter in public SpdySession | |
| 18 // interface rather than going through all these contortions. | |
| 19 class SpdySessionTest : public PlatformTest { | |
| 20 public: | |
| 21 static void TurnOffCompression() { | |
| 22 spdy::SpdyFramer::set_enable_compression_default(false); | |
| 23 } | |
| 24 protected: | |
| 25 virtual void TearDown() { | |
| 26 // Wanted to be 100% sure PING is disabled. | |
| 27 SpdySession::set_enable_ping_based_connection_checking(false); | |
| 28 } | |
| 29 }; | |
| 30 | |
| 31 class TestSpdyStreamDelegate : public net::SpdyStream::Delegate { | |
| 32 public: | |
| 33 explicit TestSpdyStreamDelegate(const CompletionCallback& callback) | |
| 34 : callback_(callback) {} | |
| 35 virtual ~TestSpdyStreamDelegate() {} | |
| 36 | |
| 37 virtual bool OnSendHeadersComplete(int status) { return true; } | |
| 38 | |
| 39 virtual int OnSendBody() { | |
| 40 return ERR_UNEXPECTED; | |
| 41 } | |
| 42 | |
| 43 virtual int OnSendBodyComplete(int /*status*/, bool* /*eof*/) { | |
| 44 return ERR_UNEXPECTED; | |
| 45 } | |
| 46 | |
| 47 virtual int OnResponseReceived(const spdy::SpdyHeaderBlock& response, | |
| 48 base::Time response_time, | |
| 49 int status) { | |
| 50 return status; | |
| 51 } | |
| 52 | |
| 53 virtual void OnDataReceived(const char* buffer, int bytes) { | |
| 54 } | |
| 55 | |
| 56 virtual void OnDataSent(int length) { | |
| 57 } | |
| 58 | |
| 59 virtual void OnClose(int status) { | |
| 60 CompletionCallback callback = callback_; | |
| 61 callback_.Reset(); | |
| 62 callback.Run(OK); | |
| 63 } | |
| 64 | |
| 65 virtual void set_chunk_callback(net::ChunkCallback *) {} | |
| 66 | |
| 67 private: | |
| 68 CompletionCallback callback_; | |
| 69 }; | |
| 70 | |
| 71 // Test the SpdyIOBuffer class. | |
| 72 TEST_F(SpdySessionTest, SpdyIOBuffer) { | |
| 73 std::priority_queue<SpdyIOBuffer> queue_; | |
| 74 const size_t kQueueSize = 100; | |
| 75 | |
| 76 // Insert 100 items; pri 100 to 1. | |
| 77 for (size_t index = 0; index < kQueueSize; ++index) { | |
| 78 SpdyIOBuffer buffer(new IOBuffer(), 0, kQueueSize - index, NULL); | |
| 79 queue_.push(buffer); | |
| 80 } | |
| 81 | |
| 82 // Insert several priority 0 items last. | |
| 83 const size_t kNumDuplicates = 12; | |
| 84 IOBufferWithSize* buffers[kNumDuplicates]; | |
| 85 for (size_t index = 0; index < kNumDuplicates; ++index) { | |
| 86 buffers[index] = new IOBufferWithSize(index+1); | |
| 87 queue_.push(SpdyIOBuffer(buffers[index], buffers[index]->size(), 0, NULL)); | |
| 88 } | |
| 89 | |
| 90 EXPECT_EQ(kQueueSize + kNumDuplicates, queue_.size()); | |
| 91 | |
| 92 // Verify the P0 items come out in FIFO order. | |
| 93 for (size_t index = 0; index < kNumDuplicates; ++index) { | |
| 94 SpdyIOBuffer buffer = queue_.top(); | |
| 95 EXPECT_EQ(0, buffer.priority()); | |
| 96 EXPECT_EQ(index + 1, buffer.size()); | |
| 97 queue_.pop(); | |
| 98 } | |
| 99 | |
| 100 int priority = 1; | |
| 101 while (queue_.size()) { | |
| 102 SpdyIOBuffer buffer = queue_.top(); | |
| 103 EXPECT_EQ(priority++, buffer.priority()); | |
| 104 queue_.pop(); | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 TEST_F(SpdySessionTest, GoAway) { | |
| 109 SpdySessionDependencies session_deps; | |
| 110 session_deps.host_resolver->set_synchronous_mode(true); | |
| 111 | |
| 112 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 113 scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyGoAway()); | |
| 114 MockRead reads[] = { | |
| 115 CreateMockRead(*goaway), | |
| 116 MockRead(SYNCHRONOUS, 0, 0) // EOF | |
| 117 }; | |
| 118 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); | |
| 119 data.set_connect_data(connect_data); | |
| 120 session_deps.socket_factory->AddSocketDataProvider(&data); | |
| 121 | |
| 122 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
| 123 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 124 | |
| 125 scoped_refptr<HttpNetworkSession> http_session( | |
| 126 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
| 127 | |
| 128 const std::string kTestHost("www.foo.com"); | |
| 129 const int kTestPort = 80; | |
| 130 HostPortPair test_host_port_pair(kTestHost, kTestPort); | |
| 131 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); | |
| 132 | |
| 133 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); | |
| 134 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 135 scoped_refptr<SpdySession> session = | |
| 136 spdy_session_pool->Get(pair, BoundNetLog()); | |
| 137 EXPECT_TRUE(spdy_session_pool->HasSession(pair)); | |
| 138 | |
| 139 scoped_refptr<TransportSocketParams> transport_params( | |
| 140 new TransportSocketParams(test_host_port_pair, | |
| 141 MEDIUM, | |
| 142 false, | |
| 143 false)); | |
| 144 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 145 EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), | |
| 146 transport_params, MEDIUM, CompletionCallback(), | |
| 147 http_session->GetTransportSocketPool(), | |
| 148 BoundNetLog())); | |
| 149 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); | |
| 150 | |
| 151 // Flush the SpdySession::OnReadComplete() task. | |
| 152 MessageLoop::current()->RunAllPending(); | |
| 153 | |
| 154 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 155 | |
| 156 scoped_refptr<SpdySession> session2 = | |
| 157 spdy_session_pool->Get(pair, BoundNetLog()); | |
| 158 | |
| 159 // Delete the first session. | |
| 160 session = NULL; | |
| 161 | |
| 162 // Delete the second session. | |
| 163 spdy_session_pool->Remove(session2); | |
| 164 session2 = NULL; | |
| 165 } | |
| 166 | |
| 167 TEST_F(SpdySessionTest, Ping) { | |
| 168 SpdySessionDependencies session_deps; | |
| 169 session_deps.host_resolver->set_synchronous_mode(true); | |
| 170 | |
| 171 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 172 scoped_ptr<spdy::SpdyFrame> read_ping(ConstructSpdyPing()); | |
| 173 MockRead reads[] = { | |
| 174 CreateMockRead(*read_ping), | |
| 175 CreateMockRead(*read_ping), | |
| 176 MockRead(SYNCHRONOUS, 0, 0) // EOF | |
| 177 }; | |
| 178 scoped_ptr<spdy::SpdyFrame> write_ping(ConstructSpdyPing()); | |
| 179 MockRead writes[] = { | |
| 180 CreateMockRead(*write_ping), | |
| 181 CreateMockRead(*write_ping), | |
| 182 }; | |
| 183 StaticSocketDataProvider data( | |
| 184 reads, arraysize(reads), writes, arraysize(writes)); | |
| 185 data.set_connect_data(connect_data); | |
| 186 session_deps.socket_factory->AddSocketDataProvider(&data); | |
| 187 | |
| 188 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
| 189 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 190 | |
| 191 scoped_refptr<HttpNetworkSession> http_session( | |
| 192 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
| 193 | |
| 194 static const char kStreamUrl[] = "http://www.google.com/"; | |
| 195 GURL url(kStreamUrl); | |
| 196 | |
| 197 const std::string kTestHost("www.google.com"); | |
| 198 const int kTestPort = 80; | |
| 199 HostPortPair test_host_port_pair(kTestHost, kTestPort); | |
| 200 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); | |
| 201 | |
| 202 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); | |
| 203 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 204 scoped_refptr<SpdySession> session = | |
| 205 spdy_session_pool->Get(pair, BoundNetLog()); | |
| 206 EXPECT_TRUE(spdy_session_pool->HasSession(pair)); | |
| 207 | |
| 208 | |
| 209 scoped_refptr<TransportSocketParams> transport_params( | |
| 210 new TransportSocketParams(test_host_port_pair, | |
| 211 MEDIUM, | |
| 212 false, | |
| 213 false)); | |
| 214 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 215 EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), | |
| 216 transport_params, MEDIUM, CompletionCallback(), | |
| 217 http_session->GetTransportSocketPool(), | |
| 218 BoundNetLog())); | |
| 219 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); | |
| 220 | |
| 221 scoped_refptr<SpdyStream> spdy_stream1; | |
| 222 TestCompletionCallback callback1; | |
| 223 EXPECT_EQ(OK, session->CreateStream(url, | |
| 224 MEDIUM, | |
| 225 &spdy_stream1, | |
| 226 BoundNetLog(), | |
| 227 callback1.callback())); | |
| 228 scoped_ptr<TestSpdyStreamDelegate> delegate( | |
| 229 new TestSpdyStreamDelegate(callback1.callback())); | |
| 230 spdy_stream1->SetDelegate(delegate.get()); | |
| 231 | |
| 232 base::TimeTicks before_ping_time = base::TimeTicks::Now(); | |
| 233 | |
| 234 // Enable sending of PING. | |
| 235 SpdySession::set_enable_ping_based_connection_checking(true); | |
| 236 SpdySession::set_connection_at_risk_of_loss_seconds(0); | |
| 237 SpdySession::set_trailing_ping_delay_time_ms(0); | |
| 238 SpdySession::set_hung_interval_ms(50); | |
| 239 | |
| 240 session->SendPrefacePingIfNoneInFlight(); | |
| 241 | |
| 242 EXPECT_EQ(OK, callback1.WaitForResult()); | |
| 243 | |
| 244 session->CheckPingStatus(before_ping_time); | |
| 245 | |
| 246 EXPECT_EQ(0, session->pings_in_flight()); | |
| 247 EXPECT_GT(session->next_ping_id(), static_cast<uint32>(1)); | |
| 248 EXPECT_FALSE(session->trailing_ping_pending()); | |
| 249 EXPECT_FALSE(session->check_ping_status_pending()); | |
| 250 EXPECT_GE(session->received_data_time(), before_ping_time); | |
| 251 | |
| 252 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 253 | |
| 254 // Delete the first session. | |
| 255 session = NULL; | |
| 256 } | |
| 257 | |
| 258 TEST_F(SpdySessionTest, FailedPing) { | |
| 259 SpdySessionDependencies session_deps; | |
| 260 session_deps.host_resolver->set_synchronous_mode(true); | |
| 261 | |
| 262 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 263 scoped_ptr<spdy::SpdyFrame> read_ping(ConstructSpdyPing()); | |
| 264 MockRead reads[] = { | |
| 265 CreateMockRead(*read_ping), | |
| 266 MockRead(SYNCHRONOUS, 0, 0) // EOF | |
| 267 }; | |
| 268 scoped_ptr<spdy::SpdyFrame> write_ping(ConstructSpdyPing()); | |
| 269 MockRead writes[] = { | |
| 270 CreateMockRead(*write_ping), | |
| 271 }; | |
| 272 StaticSocketDataProvider data( | |
| 273 reads, arraysize(reads), writes, arraysize(writes)); | |
| 274 data.set_connect_data(connect_data); | |
| 275 session_deps.socket_factory->AddSocketDataProvider(&data); | |
| 276 | |
| 277 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
| 278 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 279 | |
| 280 scoped_refptr<HttpNetworkSession> http_session( | |
| 281 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
| 282 | |
| 283 static const char kStreamUrl[] = "http://www.gmail.com/"; | |
| 284 GURL url(kStreamUrl); | |
| 285 | |
| 286 const std::string kTestHost("www.gmail.com"); | |
| 287 const int kTestPort = 80; | |
| 288 HostPortPair test_host_port_pair(kTestHost, kTestPort); | |
| 289 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); | |
| 290 | |
| 291 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); | |
| 292 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 293 scoped_refptr<SpdySession> session = | |
| 294 spdy_session_pool->Get(pair, BoundNetLog()); | |
| 295 EXPECT_TRUE(spdy_session_pool->HasSession(pair)); | |
| 296 | |
| 297 scoped_refptr<TransportSocketParams> transport_params( | |
| 298 new TransportSocketParams(test_host_port_pair, | |
| 299 MEDIUM, | |
| 300 false, | |
| 301 false)); | |
| 302 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 303 EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), | |
| 304 transport_params, MEDIUM, CompletionCallback(), | |
| 305 http_session->GetTransportSocketPool(), | |
| 306 BoundNetLog())); | |
| 307 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); | |
| 308 | |
| 309 scoped_refptr<SpdyStream> spdy_stream1; | |
| 310 TestCompletionCallback callback1; | |
| 311 EXPECT_EQ(OK, session->CreateStream(url, | |
| 312 MEDIUM, | |
| 313 &spdy_stream1, | |
| 314 BoundNetLog(), | |
| 315 callback1.callback())); | |
| 316 scoped_ptr<TestSpdyStreamDelegate> delegate( | |
| 317 new TestSpdyStreamDelegate(callback1.callback())); | |
| 318 spdy_stream1->SetDelegate(delegate.get()); | |
| 319 | |
| 320 // Enable sending of PING. | |
| 321 SpdySession::set_enable_ping_based_connection_checking(true); | |
| 322 SpdySession::set_connection_at_risk_of_loss_seconds(0); | |
| 323 SpdySession::set_trailing_ping_delay_time_ms(0); | |
| 324 SpdySession::set_hung_interval_ms(0); | |
| 325 | |
| 326 // Send a PING frame. | |
| 327 session->WritePingFrame(1); | |
| 328 EXPECT_LT(0, session->pings_in_flight()); | |
| 329 EXPECT_GT(session->next_ping_id(), static_cast<uint32>(1)); | |
| 330 EXPECT_TRUE(session->check_ping_status_pending()); | |
| 331 | |
| 332 // Assert session is not closed. | |
| 333 EXPECT_FALSE(session->IsClosed()); | |
| 334 EXPECT_LT(0u, session->num_active_streams()); | |
| 335 EXPECT_TRUE(spdy_session_pool->HasSession(pair)); | |
| 336 | |
| 337 // We set last time we have received any data in 1 sec less than now. | |
| 338 // CheckPingStatus will trigger timeout because hung interval is zero. | |
| 339 base::TimeTicks now = base::TimeTicks::Now(); | |
| 340 session->received_data_time_ = now - base::TimeDelta::FromSeconds(1); | |
| 341 session->CheckPingStatus(now); | |
| 342 | |
| 343 EXPECT_TRUE(session->IsClosed()); | |
| 344 EXPECT_EQ(0u, session->num_active_streams()); | |
| 345 EXPECT_EQ(0u, session->num_unclaimed_pushed_streams()); | |
| 346 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 347 | |
| 348 // Delete the first session. | |
| 349 session = NULL; | |
| 350 } | |
| 351 | |
| 352 class StreamReleaserCallback : public TestCompletionCallbackBase { | |
| 353 public: | |
| 354 StreamReleaserCallback(SpdySession* session, | |
| 355 SpdyStream* first_stream) | |
| 356 : session_(session), | |
| 357 first_stream_(first_stream), | |
| 358 ALLOW_THIS_IN_INITIALIZER_LIST(callback_( | |
| 359 base::Bind(&StreamReleaserCallback::OnComplete, | |
| 360 base::Unretained(this)))) { | |
| 361 } | |
| 362 | |
| 363 virtual ~StreamReleaserCallback() {} | |
| 364 | |
| 365 scoped_refptr<SpdyStream>* stream() { return &stream_; } | |
| 366 | |
| 367 const CompletionCallback& callback() const { return callback_; } | |
| 368 | |
| 369 private: | |
| 370 void OnComplete(int result) { | |
| 371 session_->CloseSessionOnError(ERR_FAILED, false, "On complete."); | |
| 372 session_ = NULL; | |
| 373 first_stream_->Cancel(); | |
| 374 first_stream_ = NULL; | |
| 375 stream_->Cancel(); | |
| 376 stream_ = NULL; | |
| 377 SetResult(result); | |
| 378 } | |
| 379 | |
| 380 scoped_refptr<SpdySession> session_; | |
| 381 scoped_refptr<SpdyStream> first_stream_; | |
| 382 scoped_refptr<SpdyStream> stream_; | |
| 383 CompletionCallback callback_; | |
| 384 }; | |
| 385 | |
| 386 // TODO(kristianm): Could also test with more sessions where some are idle, | |
| 387 // and more than one session to a HostPortPair. | |
| 388 TEST_F(SpdySessionTest, CloseIdleSessions) { | |
| 389 SpdySessionDependencies session_deps; | |
| 390 scoped_refptr<HttpNetworkSession> http_session( | |
| 391 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
| 392 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); | |
| 393 | |
| 394 // Set up session 1 | |
| 395 const std::string kTestHost1("http://www.a.com"); | |
| 396 HostPortPair test_host_port_pair1(kTestHost1, 80); | |
| 397 HostPortProxyPair pair1(test_host_port_pair1, ProxyServer::Direct()); | |
| 398 scoped_refptr<SpdySession> session1 = | |
| 399 spdy_session_pool->Get(pair1, BoundNetLog()); | |
| 400 scoped_refptr<SpdyStream> spdy_stream1; | |
| 401 TestCompletionCallback callback1; | |
| 402 GURL url1(kTestHost1); | |
| 403 EXPECT_EQ(OK, session1->CreateStream(url1, | |
| 404 MEDIUM, /* priority, not important */ | |
| 405 &spdy_stream1, | |
| 406 BoundNetLog(), | |
| 407 callback1.callback())); | |
| 408 | |
| 409 // Set up session 2 | |
| 410 const std::string kTestHost2("http://www.b.com"); | |
| 411 HostPortPair test_host_port_pair2(kTestHost2, 80); | |
| 412 HostPortProxyPair pair2(test_host_port_pair2, ProxyServer::Direct()); | |
| 413 scoped_refptr<SpdySession> session2 = | |
| 414 spdy_session_pool->Get(pair2, BoundNetLog()); | |
| 415 scoped_refptr<SpdyStream> spdy_stream2; | |
| 416 TestCompletionCallback callback2; | |
| 417 GURL url2(kTestHost2); | |
| 418 EXPECT_EQ(OK, session2->CreateStream( | |
| 419 url2, MEDIUM, /* priority, not important */ | |
| 420 &spdy_stream2, BoundNetLog(), callback2.callback())); | |
| 421 | |
| 422 // Set up session 3 | |
| 423 const std::string kTestHost3("http://www.c.com"); | |
| 424 HostPortPair test_host_port_pair3(kTestHost3, 80); | |
| 425 HostPortProxyPair pair3(test_host_port_pair3, ProxyServer::Direct()); | |
| 426 scoped_refptr<SpdySession> session3 = | |
| 427 spdy_session_pool->Get(pair3, BoundNetLog()); | |
| 428 scoped_refptr<SpdyStream> spdy_stream3; | |
| 429 TestCompletionCallback callback3; | |
| 430 GURL url3(kTestHost3); | |
| 431 EXPECT_EQ(OK, session3->CreateStream( | |
| 432 url3, MEDIUM, /* priority, not important */ | |
| 433 &spdy_stream3, BoundNetLog(), callback3.callback())); | |
| 434 | |
| 435 // All sessions are active and not closed | |
| 436 EXPECT_TRUE(session1->is_active()); | |
| 437 EXPECT_FALSE(session1->IsClosed()); | |
| 438 EXPECT_TRUE(session2->is_active()); | |
| 439 EXPECT_FALSE(session2->IsClosed()); | |
| 440 EXPECT_TRUE(session3->is_active()); | |
| 441 EXPECT_FALSE(session3->IsClosed()); | |
| 442 | |
| 443 // Should not do anything, all are active | |
| 444 spdy_session_pool->CloseIdleSessions(); | |
| 445 EXPECT_TRUE(session1->is_active()); | |
| 446 EXPECT_FALSE(session1->IsClosed()); | |
| 447 EXPECT_TRUE(session2->is_active()); | |
| 448 EXPECT_FALSE(session2->IsClosed()); | |
| 449 EXPECT_TRUE(session3->is_active()); | |
| 450 EXPECT_FALSE(session3->IsClosed()); | |
| 451 | |
| 452 // Make sessions 1 and 3 inactive, but keep them open. | |
| 453 // Session 2 still open and active | |
| 454 session1->CloseStream(spdy_stream1->stream_id(), OK); | |
| 455 session3->CloseStream(spdy_stream3->stream_id(), OK); | |
| 456 EXPECT_FALSE(session1->is_active()); | |
| 457 EXPECT_FALSE(session1->IsClosed()); | |
| 458 EXPECT_TRUE(session2->is_active()); | |
| 459 EXPECT_FALSE(session2->IsClosed()); | |
| 460 EXPECT_FALSE(session3->is_active()); | |
| 461 EXPECT_FALSE(session3->IsClosed()); | |
| 462 | |
| 463 // Should close session 1 and 3, 2 should be left open | |
| 464 spdy_session_pool->CloseIdleSessions(); | |
| 465 EXPECT_FALSE(session1->is_active()); | |
| 466 EXPECT_TRUE(session1->IsClosed()); | |
| 467 EXPECT_TRUE(session2->is_active()); | |
| 468 EXPECT_FALSE(session2->IsClosed()); | |
| 469 EXPECT_FALSE(session3->is_active()); | |
| 470 EXPECT_TRUE(session3->IsClosed()); | |
| 471 | |
| 472 // Should not do anything | |
| 473 spdy_session_pool->CloseIdleSessions(); | |
| 474 EXPECT_TRUE(session2->is_active()); | |
| 475 EXPECT_FALSE(session2->IsClosed()); | |
| 476 | |
| 477 // Make 2 not active | |
| 478 session2->CloseStream(spdy_stream2->stream_id(), OK); | |
| 479 EXPECT_FALSE(session2->is_active()); | |
| 480 EXPECT_FALSE(session2->IsClosed()); | |
| 481 | |
| 482 // This should close session 2 | |
| 483 spdy_session_pool->CloseIdleSessions(); | |
| 484 EXPECT_FALSE(session2->is_active()); | |
| 485 EXPECT_TRUE(session2->IsClosed()); | |
| 486 } | |
| 487 | |
| 488 // Start with max concurrent streams set to 1. Request two streams. Receive a | |
| 489 // settings frame setting max concurrent streams to 2. Have the callback | |
| 490 // release the stream, which releases its reference (the last) to the session. | |
| 491 // Make sure nothing blows up. | |
| 492 // http://crbug.com/57331 | |
| 493 TEST_F(SpdySessionTest, OnSettings) { | |
| 494 SpdySessionDependencies session_deps; | |
| 495 session_deps.host_resolver->set_synchronous_mode(true); | |
| 496 | |
| 497 spdy::SpdySettings new_settings; | |
| 498 spdy::SettingsFlagsAndId id(0); | |
| 499 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); | |
| 500 const size_t max_concurrent_streams = 2; | |
| 501 new_settings.push_back(spdy::SpdySetting(id, max_concurrent_streams)); | |
| 502 | |
| 503 // Set up the socket so we read a SETTINGS frame that raises max concurrent | |
| 504 // streams to 2. | |
| 505 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 506 scoped_ptr<spdy::SpdyFrame> settings_frame( | |
| 507 ConstructSpdySettings(new_settings)); | |
| 508 MockRead reads[] = { | |
| 509 CreateMockRead(*settings_frame), | |
| 510 MockRead(SYNCHRONOUS, 0, 0) // EOF | |
| 511 }; | |
| 512 | |
| 513 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); | |
| 514 data.set_connect_data(connect_data); | |
| 515 session_deps.socket_factory->AddSocketDataProvider(&data); | |
| 516 | |
| 517 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
| 518 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 519 | |
| 520 scoped_refptr<HttpNetworkSession> http_session( | |
| 521 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
| 522 | |
| 523 const std::string kTestHost("www.foo.com"); | |
| 524 const int kTestPort = 80; | |
| 525 HostPortPair test_host_port_pair(kTestHost, kTestPort); | |
| 526 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); | |
| 527 | |
| 528 // Initialize the SpdySettingsStorage with 1 max concurrent streams. | |
| 529 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); | |
| 530 spdy::SpdySettings old_settings; | |
| 531 id.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); | |
| 532 old_settings.push_back(spdy::SpdySetting(id, 1)); | |
| 533 spdy_session_pool->http_server_properties()->SetSpdySettings( | |
| 534 test_host_port_pair, old_settings); | |
| 535 | |
| 536 // Create a session. | |
| 537 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 538 scoped_refptr<SpdySession> session = | |
| 539 spdy_session_pool->Get(pair, BoundNetLog()); | |
| 540 ASSERT_TRUE(spdy_session_pool->HasSession(pair)); | |
| 541 | |
| 542 scoped_refptr<TransportSocketParams> transport_params( | |
| 543 new TransportSocketParams(test_host_port_pair, | |
| 544 MEDIUM, | |
| 545 false, | |
| 546 false)); | |
| 547 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 548 EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), | |
| 549 transport_params, MEDIUM, CompletionCallback(), | |
| 550 http_session->GetTransportSocketPool(), | |
| 551 BoundNetLog())); | |
| 552 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); | |
| 553 | |
| 554 // Create 2 streams. First will succeed. Second will be pending. | |
| 555 scoped_refptr<SpdyStream> spdy_stream1; | |
| 556 TestCompletionCallback callback1; | |
| 557 GURL url("http://www.google.com"); | |
| 558 EXPECT_EQ(OK, | |
| 559 session->CreateStream(url, | |
| 560 MEDIUM, /* priority, not important */ | |
| 561 &spdy_stream1, | |
| 562 BoundNetLog(), | |
| 563 callback1.callback())); | |
| 564 | |
| 565 StreamReleaserCallback stream_releaser(session, spdy_stream1); | |
| 566 | |
| 567 ASSERT_EQ(ERR_IO_PENDING, | |
| 568 session->CreateStream(url, | |
| 569 MEDIUM, /* priority, not important */ | |
| 570 stream_releaser.stream(), | |
| 571 BoundNetLog(), | |
| 572 stream_releaser.callback())); | |
| 573 | |
| 574 // Make sure |stream_releaser| holds the last refs. | |
| 575 session = NULL; | |
| 576 spdy_stream1 = NULL; | |
| 577 | |
| 578 EXPECT_EQ(OK, stream_releaser.WaitForResult()); | |
| 579 } | |
| 580 | |
| 581 // Start with max concurrent streams set to 1. Request two streams. When the | |
| 582 // first completes, have the callback close itself, which should trigger the | |
| 583 // second stream creation. Then cancel that one immediately. Don't crash. | |
| 584 // http://crbug.com/63532 | |
| 585 TEST_F(SpdySessionTest, CancelPendingCreateStream) { | |
| 586 SpdySessionDependencies session_deps; | |
| 587 session_deps.host_resolver->set_synchronous_mode(true); | |
| 588 | |
| 589 MockRead reads[] = { | |
| 590 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
| 591 }; | |
| 592 | |
| 593 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); | |
| 594 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 595 | |
| 596 data.set_connect_data(connect_data); | |
| 597 session_deps.socket_factory->AddSocketDataProvider(&data); | |
| 598 | |
| 599 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
| 600 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 601 | |
| 602 scoped_refptr<HttpNetworkSession> http_session( | |
| 603 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
| 604 | |
| 605 const std::string kTestHost("www.foo.com"); | |
| 606 const int kTestPort = 80; | |
| 607 HostPortPair test_host_port_pair(kTestHost, kTestPort); | |
| 608 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); | |
| 609 | |
| 610 // Initialize the SpdySettingsStorage with 1 max concurrent streams. | |
| 611 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); | |
| 612 spdy::SpdySettings settings; | |
| 613 spdy::SettingsFlagsAndId id(0); | |
| 614 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); | |
| 615 id.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); | |
| 616 settings.push_back(spdy::SpdySetting(id, 1)); | |
| 617 spdy_session_pool->http_server_properties()->SetSpdySettings( | |
| 618 test_host_port_pair, settings); | |
| 619 | |
| 620 // Create a session. | |
| 621 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 622 scoped_refptr<SpdySession> session = | |
| 623 spdy_session_pool->Get(pair, BoundNetLog()); | |
| 624 ASSERT_TRUE(spdy_session_pool->HasSession(pair)); | |
| 625 | |
| 626 scoped_refptr<TransportSocketParams> transport_params( | |
| 627 new TransportSocketParams(test_host_port_pair, | |
| 628 MEDIUM, | |
| 629 false, | |
| 630 false)); | |
| 631 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 632 EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), | |
| 633 transport_params, MEDIUM, CompletionCallback(), | |
| 634 http_session->GetTransportSocketPool(), | |
| 635 BoundNetLog())); | |
| 636 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); | |
| 637 | |
| 638 // Use scoped_ptr to let us invalidate the memory when we want to, to trigger | |
| 639 // a valgrind error if the callback is invoked when it's not supposed to be. | |
| 640 scoped_ptr<TestCompletionCallback> callback(new TestCompletionCallback); | |
| 641 | |
| 642 // Create 2 streams. First will succeed. Second will be pending. | |
| 643 scoped_refptr<SpdyStream> spdy_stream1; | |
| 644 GURL url("http://www.google.com"); | |
| 645 ASSERT_EQ(OK, | |
| 646 session->CreateStream(url, | |
| 647 MEDIUM, /* priority, not important */ | |
| 648 &spdy_stream1, | |
| 649 BoundNetLog(), | |
| 650 callback->callback())); | |
| 651 | |
| 652 scoped_refptr<SpdyStream> spdy_stream2; | |
| 653 ASSERT_EQ(ERR_IO_PENDING, | |
| 654 session->CreateStream(url, | |
| 655 MEDIUM, /* priority, not important */ | |
| 656 &spdy_stream2, | |
| 657 BoundNetLog(), | |
| 658 callback->callback())); | |
| 659 | |
| 660 // Release the first one, this will allow the second to be created. | |
| 661 spdy_stream1->Cancel(); | |
| 662 spdy_stream1 = NULL; | |
| 663 | |
| 664 session->CancelPendingCreateStreams(&spdy_stream2); | |
| 665 callback.reset(); | |
| 666 | |
| 667 // Should not crash when running the pending callback. | |
| 668 MessageLoop::current()->RunAllPending(); | |
| 669 } | |
| 670 | |
| 671 TEST_F(SpdySessionTest, SendSettingsOnNewSession) { | |
| 672 SpdySessionDependencies session_deps; | |
| 673 session_deps.host_resolver->set_synchronous_mode(true); | |
| 674 | |
| 675 MockRead reads[] = { | |
| 676 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
| 677 }; | |
| 678 | |
| 679 // Create the bogus setting that we want to verify is sent out. | |
| 680 // Note that it will be marked as SETTINGS_FLAG_PERSISTED when sent out. But | |
| 681 // to set it into the SpdySettingsStorage, we need to mark as | |
| 682 // SETTINGS_FLAG_PLEASE_PERSIST. | |
| 683 spdy::SpdySettings settings; | |
| 684 const uint32 kBogusSettingId = 0xABAB; | |
| 685 const uint32 kBogusSettingValue = 0xCDCD; | |
| 686 spdy::SettingsFlagsAndId id(0); | |
| 687 id.set_id(kBogusSettingId); | |
| 688 id.set_flags(spdy::SETTINGS_FLAG_PERSISTED); | |
| 689 settings.push_back(spdy::SpdySetting(id, kBogusSettingValue)); | |
| 690 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 691 scoped_ptr<spdy::SpdyFrame> settings_frame( | |
| 692 ConstructSpdySettings(settings)); | |
| 693 MockWrite writes[] = { | |
| 694 CreateMockWrite(*settings_frame), | |
| 695 }; | |
| 696 | |
| 697 StaticSocketDataProvider data( | |
| 698 reads, arraysize(reads), writes, arraysize(writes)); | |
| 699 data.set_connect_data(connect_data); | |
| 700 session_deps.socket_factory->AddSocketDataProvider(&data); | |
| 701 | |
| 702 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
| 703 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 704 | |
| 705 scoped_refptr<HttpNetworkSession> http_session( | |
| 706 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
| 707 | |
| 708 const std::string kTestHost("www.foo.com"); | |
| 709 const int kTestPort = 80; | |
| 710 HostPortPair test_host_port_pair(kTestHost, kTestPort); | |
| 711 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); | |
| 712 | |
| 713 id.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); | |
| 714 settings.clear(); | |
| 715 settings.push_back(spdy::SpdySetting(id, kBogusSettingValue)); | |
| 716 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); | |
| 717 spdy_session_pool->http_server_properties()->SetSpdySettings( | |
| 718 test_host_port_pair, settings); | |
| 719 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 720 scoped_refptr<SpdySession> session = | |
| 721 spdy_session_pool->Get(pair, BoundNetLog()); | |
| 722 EXPECT_TRUE(spdy_session_pool->HasSession(pair)); | |
| 723 | |
| 724 scoped_refptr<TransportSocketParams> transport_params( | |
| 725 new TransportSocketParams(test_host_port_pair, | |
| 726 MEDIUM, | |
| 727 false, | |
| 728 false)); | |
| 729 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 730 EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), | |
| 731 transport_params, MEDIUM, CompletionCallback(), | |
| 732 http_session->GetTransportSocketPool(), | |
| 733 BoundNetLog())); | |
| 734 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); | |
| 735 MessageLoop::current()->RunAllPending(); | |
| 736 EXPECT_TRUE(data.at_write_eof()); | |
| 737 } | |
| 738 | |
| 739 // This test has two variants, one for each style of closing the connection. | |
| 740 // If |clean_via_close_current_sessions| is false, the sessions are closed | |
| 741 // manually, calling SpdySessionPool::Remove() directly. If it is true, | |
| 742 // sessions are closed with SpdySessionPool::CloseCurrentSessions(). | |
| 743 void IPPoolingTest(bool clean_via_close_current_sessions) { | |
| 744 const int kTestPort = 80; | |
| 745 struct TestHosts { | |
| 746 std::string name; | |
| 747 std::string iplist; | |
| 748 HostPortProxyPair pair; | |
| 749 AddressList addresses; | |
| 750 } test_hosts[] = { | |
| 751 { "www.foo.com", "192.0.2.33,192.168.0.1,192.168.0.5" }, | |
| 752 { "images.foo.com", "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33" }, | |
| 753 { "js.foo.com", "192.168.0.4,192.168.0.3" }, | |
| 754 }; | |
| 755 | |
| 756 SpdySessionDependencies session_deps; | |
| 757 session_deps.host_resolver->set_synchronous_mode(true); | |
| 758 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_hosts); i++) { | |
| 759 session_deps.host_resolver->rules()->AddIPLiteralRule(test_hosts[i].name, | |
| 760 test_hosts[i].iplist, ""); | |
| 761 | |
| 762 // This test requires that the HostResolver cache be populated. Normal | |
| 763 // code would have done this already, but we do it manually. | |
| 764 HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort)); | |
| 765 session_deps.host_resolver->Resolve( | |
| 766 info, &test_hosts[i].addresses, CompletionCallback(), NULL, | |
| 767 BoundNetLog()); | |
| 768 | |
| 769 // Setup a HostPortProxyPair | |
| 770 test_hosts[i].pair = HostPortProxyPair( | |
| 771 HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct()); | |
| 772 } | |
| 773 | |
| 774 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 775 MockRead reads[] = { | |
| 776 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
| 777 }; | |
| 778 | |
| 779 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); | |
| 780 data.set_connect_data(connect_data); | |
| 781 session_deps.socket_factory->AddSocketDataProvider(&data); | |
| 782 | |
| 783 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
| 784 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 785 | |
| 786 scoped_refptr<HttpNetworkSession> http_session( | |
| 787 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
| 788 | |
| 789 // Setup the first session to the first host. | |
| 790 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); | |
| 791 EXPECT_FALSE(spdy_session_pool->HasSession(test_hosts[0].pair)); | |
| 792 scoped_refptr<SpdySession> session = | |
| 793 spdy_session_pool->Get(test_hosts[0].pair, BoundNetLog()); | |
| 794 EXPECT_TRUE(spdy_session_pool->HasSession(test_hosts[0].pair)); | |
| 795 | |
| 796 HostPortPair test_host_port_pair(test_hosts[0].name, kTestPort); | |
| 797 scoped_refptr<TransportSocketParams> transport_params( | |
| 798 new TransportSocketParams(test_host_port_pair, | |
| 799 MEDIUM, | |
| 800 false, | |
| 801 false)); | |
| 802 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 803 EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), | |
| 804 transport_params, MEDIUM, CompletionCallback(), | |
| 805 http_session->GetTransportSocketPool(), | |
| 806 BoundNetLog())); | |
| 807 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); | |
| 808 | |
| 809 // TODO(rtenneti): MockClientSocket::GetPeerAddress return's 0 as the port | |
| 810 // number. Fix it to return port 80 and then use GetPeerAddress to AddAlias. | |
| 811 const addrinfo* address = test_hosts[0].addresses.head(); | |
| 812 SpdySessionPoolPeer pool_peer(spdy_session_pool); | |
| 813 pool_peer.AddAlias(address, test_hosts[0].pair); | |
| 814 | |
| 815 // Flush the SpdySession::OnReadComplete() task. | |
| 816 MessageLoop::current()->RunAllPending(); | |
| 817 | |
| 818 // The third host has no overlap with the first, so it can't pool IPs. | |
| 819 EXPECT_FALSE(spdy_session_pool->HasSession(test_hosts[2].pair)); | |
| 820 | |
| 821 // The second host overlaps with the first, and should IP pool. | |
| 822 EXPECT_TRUE(spdy_session_pool->HasSession(test_hosts[1].pair)); | |
| 823 | |
| 824 // Verify that the second host, through a proxy, won't share the IP. | |
| 825 HostPortProxyPair proxy_pair(test_hosts[1].pair.first, | |
| 826 ProxyServer::FromPacString("HTTP http://proxy.foo.com/")); | |
| 827 EXPECT_FALSE(spdy_session_pool->HasSession(proxy_pair)); | |
| 828 | |
| 829 // Overlap between 2 and 3 does is not transitive to 1. | |
| 830 EXPECT_FALSE(spdy_session_pool->HasSession(test_hosts[2].pair)); | |
| 831 | |
| 832 // Create a new session to host 2. | |
| 833 scoped_refptr<SpdySession> session2 = | |
| 834 spdy_session_pool->Get(test_hosts[2].pair, BoundNetLog()); | |
| 835 | |
| 836 // Verify that we have sessions for everything. | |
| 837 EXPECT_TRUE(spdy_session_pool->HasSession(test_hosts[0].pair)); | |
| 838 EXPECT_TRUE(spdy_session_pool->HasSession(test_hosts[1].pair)); | |
| 839 EXPECT_TRUE(spdy_session_pool->HasSession(test_hosts[2].pair)); | |
| 840 | |
| 841 // Cleanup the sessions. | |
| 842 if (!clean_via_close_current_sessions) { | |
| 843 spdy_session_pool->Remove(session); | |
| 844 session = NULL; | |
| 845 spdy_session_pool->Remove(session2); | |
| 846 session2 = NULL; | |
| 847 } else { | |
| 848 spdy_session_pool->CloseCurrentSessions(); | |
| 849 } | |
| 850 | |
| 851 // Verify that the map is all cleaned up. | |
| 852 EXPECT_FALSE(spdy_session_pool->HasSession(test_hosts[0].pair)); | |
| 853 EXPECT_FALSE(spdy_session_pool->HasSession(test_hosts[1].pair)); | |
| 854 EXPECT_FALSE(spdy_session_pool->HasSession(test_hosts[2].pair)); | |
| 855 } | |
| 856 | |
| 857 TEST_F(SpdySessionTest, IPPooling) { | |
| 858 IPPoolingTest(false); | |
| 859 } | |
| 860 | |
| 861 TEST_F(SpdySessionTest, IPPoolingCloseCurrentSessions) { | |
| 862 IPPoolingTest(true); | |
| 863 } | |
| 864 | |
| 865 TEST_F(SpdySessionTest, ClearSettingsStorage) { | |
| 866 SpdySettingsStorage settings_storage; | |
| 867 const std::string kTestHost("www.foo.com"); | |
| 868 const int kTestPort = 80; | |
| 869 HostPortPair test_host_port_pair(kTestHost, kTestPort); | |
| 870 spdy::SpdySettings test_settings; | |
| 871 spdy::SettingsFlagsAndId id(0); | |
| 872 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); | |
| 873 id.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); | |
| 874 const size_t max_concurrent_streams = 2; | |
| 875 test_settings.push_back(spdy::SpdySetting(id, max_concurrent_streams)); | |
| 876 | |
| 877 settings_storage.Set(test_host_port_pair, test_settings); | |
| 878 EXPECT_NE(0u, settings_storage.Get(test_host_port_pair).size()); | |
| 879 settings_storage.Clear(); | |
| 880 EXPECT_EQ(0u, settings_storage.Get(test_host_port_pair).size()); | |
| 881 } | |
| 882 | |
| 883 TEST_F(SpdySessionTest, ClearSettingsStorageOnIPAddressChanged) { | |
| 884 const std::string kTestHost("www.foo.com"); | |
| 885 const int kTestPort = 80; | |
| 886 HostPortPair test_host_port_pair(kTestHost, kTestPort); | |
| 887 | |
| 888 SpdySessionDependencies session_deps; | |
| 889 scoped_refptr<HttpNetworkSession> http_session( | |
| 890 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
| 891 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); | |
| 892 | |
| 893 HttpServerProperties* test_http_server_properties = | |
| 894 spdy_session_pool->http_server_properties(); | |
| 895 spdy::SettingsFlagsAndId id(0); | |
| 896 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); | |
| 897 id.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); | |
| 898 const size_t max_concurrent_streams = 2; | |
| 899 spdy::SpdySettings test_settings; | |
| 900 test_settings.push_back(spdy::SpdySetting(id, max_concurrent_streams)); | |
| 901 | |
| 902 test_http_server_properties->SetSpdySettings(test_host_port_pair, | |
| 903 test_settings); | |
| 904 EXPECT_NE(0u, test_http_server_properties->GetSpdySettings( | |
| 905 test_host_port_pair).size()); | |
| 906 spdy_session_pool->OnIPAddressChanged(); | |
| 907 EXPECT_EQ(0u, test_http_server_properties->GetSpdySettings( | |
| 908 test_host_port_pair).size()); | |
| 909 } | |
| 910 | |
| 911 TEST_F(SpdySessionTest, NeedsCredentials) { | |
| 912 SpdySessionDependencies session_deps; | |
| 913 | |
| 914 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 915 MockRead reads[] = { | |
| 916 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
| 917 }; | |
| 918 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); | |
| 919 data.set_connect_data(connect_data); | |
| 920 session_deps.socket_factory->AddSocketDataProvider(&data); | |
| 921 | |
| 922 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
| 923 ssl.origin_bound_cert_type = CLIENT_CERT_ECDSA_SIGN; | |
| 924 ssl.protocol_negotiated = SSLClientSocket::kProtoSPDY3; | |
| 925 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 926 | |
| 927 scoped_refptr<HttpNetworkSession> http_session( | |
| 928 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
| 929 | |
| 930 const std::string kTestHost("www.foo.com"); | |
| 931 const int kTestPort = 80; | |
| 932 HostPortPair test_host_port_pair(kTestHost, kTestPort); | |
| 933 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); | |
| 934 | |
| 935 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); | |
| 936 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 937 scoped_refptr<SpdySession> session = | |
| 938 spdy_session_pool->Get(pair, BoundNetLog()); | |
| 939 EXPECT_TRUE(spdy_session_pool->HasSession(pair)); | |
| 940 | |
| 941 SSLConfig ssl_config; | |
| 942 scoped_refptr<TransportSocketParams> transport_params( | |
| 943 new TransportSocketParams(test_host_port_pair, | |
| 944 MEDIUM, | |
| 945 false, | |
| 946 false)); | |
| 947 scoped_refptr<SOCKSSocketParams> socks_params; | |
| 948 scoped_refptr<HttpProxySocketParams> http_proxy_params; | |
| 949 scoped_refptr<SSLSocketParams> ssl_params( | |
| 950 new SSLSocketParams(transport_params, | |
| 951 socks_params, | |
| 952 http_proxy_params, | |
| 953 ProxyServer::SCHEME_DIRECT, | |
| 954 test_host_port_pair, | |
| 955 ssl_config, | |
| 956 0, | |
| 957 false, | |
| 958 false)); | |
| 959 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 960 EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), | |
| 961 ssl_params, MEDIUM, CompletionCallback(), | |
| 962 http_session->GetSSLSocketPool(), | |
| 963 BoundNetLog())); | |
| 964 | |
| 965 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), true, OK)); | |
| 966 | |
| 967 EXPECT_FALSE(session->NeedsCredentials(test_host_port_pair)); | |
| 968 const std::string kTestHost2("www.bar.com"); | |
| 969 HostPortPair test_host_port_pair2(kTestHost2, kTestPort); | |
| 970 EXPECT_TRUE(session->NeedsCredentials(test_host_port_pair2)); | |
| 971 | |
| 972 // Flush the SpdySession::OnReadComplete() task. | |
| 973 MessageLoop::current()->RunAllPending(); | |
| 974 | |
| 975 spdy_session_pool->Remove(session); | |
| 976 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 977 } | |
| 978 | |
| 979 TEST_F(SpdySessionTest, SendCredentials) { | |
| 980 SpdySessionDependencies session_deps; | |
| 981 | |
| 982 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 983 MockRead reads[] = { | |
| 984 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. | |
| 985 }; | |
| 986 spdy::SpdySettings settings; | |
| 987 scoped_ptr<spdy::SpdyFrame> settings_frame( | |
| 988 ConstructSpdySettings(settings)); | |
| 989 MockWrite writes[] = { | |
| 990 CreateMockWrite(*settings_frame), | |
| 991 }; | |
| 992 StaticSocketDataProvider data(reads, arraysize(reads), | |
| 993 writes, arraysize(writes)); | |
| 994 data.set_connect_data(connect_data); | |
| 995 session_deps.socket_factory->AddSocketDataProvider(&data); | |
| 996 | |
| 997 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
| 998 ssl.origin_bound_cert_type = CLIENT_CERT_ECDSA_SIGN; | |
| 999 ssl.protocol_negotiated = SSLClientSocket::kProtoSPDY3; | |
| 1000 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 1001 | |
| 1002 scoped_refptr<HttpNetworkSession> http_session( | |
| 1003 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
| 1004 | |
| 1005 const std::string kTestHost("www.foo.com"); | |
| 1006 const int kTestPort = 80; | |
| 1007 HostPortPair test_host_port_pair(kTestHost, kTestPort); | |
| 1008 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); | |
| 1009 | |
| 1010 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); | |
| 1011 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 1012 scoped_refptr<SpdySession> session = | |
| 1013 spdy_session_pool->Get(pair, BoundNetLog()); | |
| 1014 EXPECT_TRUE(spdy_session_pool->HasSession(pair)); | |
| 1015 | |
| 1016 SSLConfig ssl_config; | |
| 1017 scoped_refptr<TransportSocketParams> transport_params( | |
| 1018 new TransportSocketParams(test_host_port_pair, | |
| 1019 MEDIUM, | |
| 1020 false, | |
| 1021 false)); | |
| 1022 scoped_refptr<SOCKSSocketParams> socks_params; | |
| 1023 scoped_refptr<HttpProxySocketParams> http_proxy_params; | |
| 1024 scoped_refptr<SSLSocketParams> ssl_params( | |
| 1025 new SSLSocketParams(transport_params, | |
| 1026 socks_params, | |
| 1027 http_proxy_params, | |
| 1028 ProxyServer::SCHEME_DIRECT, | |
| 1029 test_host_port_pair, | |
| 1030 ssl_config, | |
| 1031 0, | |
| 1032 false, | |
| 1033 false)); | |
| 1034 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 1035 EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), | |
| 1036 ssl_params, MEDIUM, CompletionCallback(), | |
| 1037 http_session->GetSSLSocketPool(), | |
| 1038 BoundNetLog())); | |
| 1039 | |
| 1040 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), true, OK)); | |
| 1041 | |
| 1042 EXPECT_FALSE(session->NeedsCredentials(test_host_port_pair)); | |
| 1043 const std::string kTestHost2("www.bar.com"); | |
| 1044 HostPortPair test_host_port_pair2(kTestHost2, kTestPort); | |
| 1045 EXPECT_TRUE(session->NeedsCredentials(test_host_port_pair2)); | |
| 1046 | |
| 1047 // Flush the SpdySession::OnReadComplete() task. | |
| 1048 MessageLoop::current()->RunAllPending(); | |
| 1049 | |
| 1050 spdy_session_pool->Remove(session); | |
| 1051 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 1052 } | |
| 1053 | |
| 1054 TEST_F(SpdySessionTest, CloseSessionOnError) { | |
| 1055 SpdySessionDependencies session_deps; | |
| 1056 session_deps.host_resolver->set_synchronous_mode(true); | |
| 1057 | |
| 1058 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 1059 scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyGoAway()); | |
| 1060 MockRead reads[] = { | |
| 1061 CreateMockRead(*goaway), | |
| 1062 MockRead(SYNCHRONOUS, 0, 0) // EOF | |
| 1063 }; | |
| 1064 | |
| 1065 net::CapturingBoundNetLog log(net::CapturingNetLog::kUnbounded); | |
| 1066 | |
| 1067 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); | |
| 1068 data.set_connect_data(connect_data); | |
| 1069 session_deps.socket_factory->AddSocketDataProvider(&data); | |
| 1070 | |
| 1071 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
| 1072 session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 1073 | |
| 1074 scoped_refptr<HttpNetworkSession> http_session( | |
| 1075 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
| 1076 | |
| 1077 const std::string kTestHost("www.foo.com"); | |
| 1078 const int kTestPort = 80; | |
| 1079 HostPortPair test_host_port_pair(kTestHost, kTestPort); | |
| 1080 HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); | |
| 1081 | |
| 1082 SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); | |
| 1083 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 1084 scoped_refptr<SpdySession> session = | |
| 1085 spdy_session_pool->Get(pair, log.bound()); | |
| 1086 EXPECT_TRUE(spdy_session_pool->HasSession(pair)); | |
| 1087 | |
| 1088 scoped_refptr<TransportSocketParams> transport_params( | |
| 1089 new TransportSocketParams(test_host_port_pair, | |
| 1090 MEDIUM, | |
| 1091 false, | |
| 1092 false)); | |
| 1093 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 1094 EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), | |
| 1095 transport_params, MEDIUM, CompletionCallback(), | |
| 1096 http_session->GetTransportSocketPool(), | |
| 1097 log.bound())); | |
| 1098 EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); | |
| 1099 | |
| 1100 // Flush the SpdySession::OnReadComplete() task. | |
| 1101 MessageLoop::current()->RunAllPending(); | |
| 1102 | |
| 1103 EXPECT_FALSE(spdy_session_pool->HasSession(pair)); | |
| 1104 | |
| 1105 // Check that the NetLog was filled reasonably. | |
| 1106 net::CapturingNetLog::EntryList entries; | |
| 1107 log.GetEntries(&entries); | |
| 1108 EXPECT_LT(0u, entries.size()); | |
| 1109 | |
| 1110 // Check that we logged SPDY_SESSION_CLOSE correctly. | |
| 1111 int pos = net::ExpectLogContainsSomewhere( | |
| 1112 entries, 0, | |
| 1113 net::NetLog::TYPE_SPDY_SESSION_CLOSE, | |
| 1114 net::NetLog::PHASE_NONE); | |
| 1115 | |
| 1116 CapturingNetLog::Entry entry = entries[pos]; | |
| 1117 NetLogSpdySessionCloseParameter* request_params = | |
| 1118 static_cast<NetLogSpdySessionCloseParameter*>( | |
| 1119 entry.extra_parameters.get()); | |
| 1120 EXPECT_EQ(ERR_CONNECTION_CLOSED, request_params->status()); | |
| 1121 } | |
| 1122 | |
| 1123 } // namespace net | |
| OLD | NEW |