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 |