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 "base/bind.h"
8 #include "base/callback.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/run_loop.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/ip_endpoint.h"
13 #include "net/base/net_log_unittest.h"
14 #include "net/base/request_priority.h"
15 #include "net/base/test_data_directory.h"
16 #include "net/base/test_data_stream.h"
17 #include "net/socket/client_socket_pool_manager.h"
18 #include "net/socket/next_proto.h"
19 #include "net/socket/socket_test_util.h"
20 #include "net/spdy/spdy_http_utils.h"
21 #include "net/spdy/spdy_session_pool.h"
22 #include "net/spdy/spdy_session_test_util.h"
23 #include "net/spdy/spdy_stream.h"
24 #include "net/spdy/spdy_stream_test_util.h"
25 #include "net/spdy/spdy_test_util_common.h"
26 #include "net/spdy/spdy_test_utils.h"
27 #include "net/test/cert_test_util.h"
28 #include "testing/platform_test.h"
29
30 namespace net {
31
32 namespace {
33
34 static const char kTestUrl[] = "http://www.example.org/";
35 static const char kTestHost[] = "www.example.org";
36 static const int kTestPort = 80;
37
38 const char kBodyData[] = "Body data";
39 const size_t kBodyDataSize = arraysize(kBodyData);
40 const base::StringPiece kBodyDataStringPiece(kBodyData, kBodyDataSize);
41
42 static base::TimeDelta g_time_delta;
TheNearFuture()43 base::TimeTicks TheNearFuture() {
44 return base::TimeTicks::Now() + g_time_delta;
45 }
46
47 } // namespace
48
49 class SpdySessionTest : public PlatformTest,
50 public ::testing::WithParamInterface<NextProto> {
51 public:
52 // Functions used with RunResumeAfterUnstallTest().
53
StallSessionOnly(SpdySession * session,SpdyStream * stream)54 void StallSessionOnly(SpdySession* session, SpdyStream* stream) {
55 StallSessionSend(session);
56 }
57
StallStreamOnly(SpdySession * session,SpdyStream * stream)58 void StallStreamOnly(SpdySession* session, SpdyStream* stream) {
59 StallStreamSend(stream);
60 }
61
StallSessionStream(SpdySession * session,SpdyStream * stream)62 void StallSessionStream(SpdySession* session, SpdyStream* stream) {
63 StallSessionSend(session);
64 StallStreamSend(stream);
65 }
66
StallStreamSession(SpdySession * session,SpdyStream * stream)67 void StallStreamSession(SpdySession* session, SpdyStream* stream) {
68 StallStreamSend(stream);
69 StallSessionSend(session);
70 }
71
UnstallSessionOnly(SpdySession * session,SpdyStream * stream,int32 delta_window_size)72 void UnstallSessionOnly(SpdySession* session,
73 SpdyStream* stream,
74 int32 delta_window_size) {
75 UnstallSessionSend(session, delta_window_size);
76 }
77
UnstallStreamOnly(SpdySession * session,SpdyStream * stream,int32 delta_window_size)78 void UnstallStreamOnly(SpdySession* session,
79 SpdyStream* stream,
80 int32 delta_window_size) {
81 UnstallStreamSend(stream, delta_window_size);
82 }
83
UnstallSessionStream(SpdySession * session,SpdyStream * stream,int32 delta_window_size)84 void UnstallSessionStream(SpdySession* session,
85 SpdyStream* stream,
86 int32 delta_window_size) {
87 UnstallSessionSend(session, delta_window_size);
88 UnstallStreamSend(stream, delta_window_size);
89 }
90
UnstallStreamSession(SpdySession * session,SpdyStream * stream,int32 delta_window_size)91 void UnstallStreamSession(SpdySession* session,
92 SpdyStream* stream,
93 int32 delta_window_size) {
94 UnstallStreamSend(stream, delta_window_size);
95 UnstallSessionSend(session, delta_window_size);
96 }
97
98 protected:
SpdySessionTest()99 SpdySessionTest()
100 : old_max_group_sockets_(ClientSocketPoolManager::max_sockets_per_group(
101 HttpNetworkSession::NORMAL_SOCKET_POOL)),
102 old_max_pool_sockets_(ClientSocketPoolManager::max_sockets_per_pool(
103 HttpNetworkSession::NORMAL_SOCKET_POOL)),
104 spdy_util_(GetParam()),
105 session_deps_(GetParam()),
106 spdy_session_pool_(NULL),
107 test_url_(kTestUrl),
108 test_host_port_pair_(kTestHost, kTestPort),
109 key_(test_host_port_pair_, ProxyServer::Direct(),
110 PRIVACY_MODE_DISABLED) {
111 }
112
~SpdySessionTest()113 virtual ~SpdySessionTest() {
114 // Important to restore the per-pool limit first, since the pool limit must
115 // always be greater than group limit, and the tests reduce both limits.
116 ClientSocketPoolManager::set_max_sockets_per_pool(
117 HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_pool_sockets_);
118 ClientSocketPoolManager::set_max_sockets_per_group(
119 HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_group_sockets_);
120 }
121
SetUp()122 virtual void SetUp() OVERRIDE {
123 g_time_delta = base::TimeDelta();
124 }
125
CreateDeterministicNetworkSession()126 void CreateDeterministicNetworkSession() {
127 http_session_ =
128 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
129 spdy_session_pool_ = http_session_->spdy_session_pool();
130 }
131
CreateNetworkSession()132 void CreateNetworkSession() {
133 http_session_ =
134 SpdySessionDependencies::SpdyCreateSession(&session_deps_);
135 spdy_session_pool_ = http_session_->spdy_session_pool();
136 }
137
StallSessionSend(SpdySession * session)138 void StallSessionSend(SpdySession* session) {
139 // Reduce the send window size to 0 to stall.
140 while (session->session_send_window_size_ > 0) {
141 session->DecreaseSendWindowSize(
142 std::min(kMaxSpdyFrameChunkSize, session->session_send_window_size_));
143 }
144 }
145
UnstallSessionSend(SpdySession * session,int32 delta_window_size)146 void UnstallSessionSend(SpdySession* session, int32 delta_window_size) {
147 session->IncreaseSendWindowSize(delta_window_size);
148 }
149
StallStreamSend(SpdyStream * stream)150 void StallStreamSend(SpdyStream* stream) {
151 // Reduce the send window size to 0 to stall.
152 while (stream->send_window_size() > 0) {
153 stream->DecreaseSendWindowSize(
154 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
155 }
156 }
157
UnstallStreamSend(SpdyStream * stream,int32 delta_window_size)158 void UnstallStreamSend(SpdyStream* stream, int32 delta_window_size) {
159 stream->IncreaseSendWindowSize(delta_window_size);
160 }
161
162 void RunResumeAfterUnstallTest(
163 const base::Callback<void(SpdySession*, SpdyStream*)>& stall_function,
164 const base::Callback<void(SpdySession*, SpdyStream*, int32)>&
165 unstall_function);
166
167 // Original socket limits. Some tests set these. Safest to always restore
168 // them once each test has been run.
169 int old_max_group_sockets_;
170 int old_max_pool_sockets_;
171
172 SpdyTestUtil spdy_util_;
173 SpdySessionDependencies session_deps_;
174 scoped_refptr<HttpNetworkSession> http_session_;
175 SpdySessionPool* spdy_session_pool_;
176 GURL test_url_;
177 HostPortPair test_host_port_pair_;
178 SpdySessionKey key_;
179 };
180
181 INSTANTIATE_TEST_CASE_P(
182 NextProto,
183 SpdySessionTest,
184 testing::Values(kProtoDeprecatedSPDY2,
185 kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
186
187 // Try to create a SPDY session that will fail during
188 // initialization. Nothing should blow up.
TEST_P(SpdySessionTest,InitialReadError)189 TEST_P(SpdySessionTest, InitialReadError) {
190 CreateDeterministicNetworkSession();
191
192 base::WeakPtr<SpdySession> session = TryCreateFakeSpdySessionExpectingFailure(
193 spdy_session_pool_, key_, ERR_CONNECTION_CLOSED);
194 EXPECT_TRUE(session);
195 // Flush the read.
196 base::RunLoop().RunUntilIdle();
197 EXPECT_FALSE(session);
198 }
199
200 namespace {
201
202 // A helper class that vends a callback that, when fired, destroys a
203 // given SpdyStreamRequest.
204 class StreamRequestDestroyingCallback : public TestCompletionCallbackBase {
205 public:
StreamRequestDestroyingCallback()206 StreamRequestDestroyingCallback() {}
207
~StreamRequestDestroyingCallback()208 virtual ~StreamRequestDestroyingCallback() {}
209
SetRequestToDestroy(scoped_ptr<SpdyStreamRequest> request)210 void SetRequestToDestroy(scoped_ptr<SpdyStreamRequest> request) {
211 request_ = request.Pass();
212 }
213
MakeCallback()214 CompletionCallback MakeCallback() {
215 return base::Bind(&StreamRequestDestroyingCallback::OnComplete,
216 base::Unretained(this));
217 }
218
219 private:
OnComplete(int result)220 void OnComplete(int result) {
221 request_.reset();
222 SetResult(result);
223 }
224
225 scoped_ptr<SpdyStreamRequest> request_;
226 };
227
228 } // namespace
229
230 // Request kInitialMaxConcurrentStreams streams. Request two more
231 // streams, but have the callback for one destroy the second stream
232 // request. Close the session. Nothing should blow up. This is a
233 // regression test for http://crbug.com/250841 .
TEST_P(SpdySessionTest,PendingStreamCancellingAnother)234 TEST_P(SpdySessionTest, PendingStreamCancellingAnother) {
235 session_deps_.host_resolver->set_synchronous_mode(true);
236
237 MockRead reads[] = {MockRead(ASYNC, 0, 0), };
238
239 DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
240 MockConnect connect_data(SYNCHRONOUS, OK);
241 data.set_connect_data(connect_data);
242 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
243
244 CreateDeterministicNetworkSession();
245
246 base::WeakPtr<SpdySession> session =
247 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
248
249 // Create the maximum number of concurrent streams.
250 for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
251 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
252 SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM, BoundNetLog());
253 ASSERT_TRUE(spdy_stream != NULL);
254 }
255
256 SpdyStreamRequest request1;
257 scoped_ptr<SpdyStreamRequest> request2(new SpdyStreamRequest);
258
259 StreamRequestDestroyingCallback callback1;
260 ASSERT_EQ(ERR_IO_PENDING,
261 request1.StartRequest(SPDY_BIDIRECTIONAL_STREAM,
262 session,
263 test_url_,
264 MEDIUM,
265 BoundNetLog(),
266 callback1.MakeCallback()));
267
268 // |callback2| is never called.
269 TestCompletionCallback callback2;
270 ASSERT_EQ(ERR_IO_PENDING,
271 request2->StartRequest(SPDY_BIDIRECTIONAL_STREAM,
272 session,
273 test_url_,
274 MEDIUM,
275 BoundNetLog(),
276 callback2.callback()));
277
278 callback1.SetRequestToDestroy(request2.Pass());
279
280 session->CloseSessionOnError(ERR_ABORTED, "Aborting session");
281
282 EXPECT_EQ(ERR_ABORTED, callback1.WaitForResult());
283 }
284
285 // A session receiving a GOAWAY frame with no active streams should close.
TEST_P(SpdySessionTest,GoAwayWithNoActiveStreams)286 TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) {
287 session_deps_.host_resolver->set_synchronous_mode(true);
288
289 MockConnect connect_data(SYNCHRONOUS, OK);
290 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
291 MockRead reads[] = {
292 CreateMockRead(*goaway, 0),
293 };
294 DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
295 data.set_connect_data(connect_data);
296 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
297
298 CreateDeterministicNetworkSession();
299
300 base::WeakPtr<SpdySession> session =
301 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
302
303 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
304
305 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
306
307 // Read and process the GOAWAY frame.
308 data.RunFor(1);
309 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
310 base::RunLoop().RunUntilIdle();
311 EXPECT_TRUE(session == NULL);
312 }
313
314 // A session receiving a GOAWAY frame immediately with no active
315 // streams should then close.
TEST_P(SpdySessionTest,GoAwayImmediatelyWithNoActiveStreams)316 TEST_P(SpdySessionTest, GoAwayImmediatelyWithNoActiveStreams) {
317 session_deps_.host_resolver->set_synchronous_mode(true);
318
319 MockConnect connect_data(SYNCHRONOUS, OK);
320 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
321 MockRead reads[] = {
322 CreateMockRead(*goaway, 0, SYNCHRONOUS),
323 };
324 DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
325 data.set_connect_data(connect_data);
326 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
327
328 CreateDeterministicNetworkSession();
329
330 data.StopAfter(1);
331
332 base::WeakPtr<SpdySession> session =
333 TryCreateInsecureSpdySessionExpectingFailure(
334 http_session_, key_, ERR_CONNECTION_CLOSED, BoundNetLog());
335 base::RunLoop().RunUntilIdle();
336
337 EXPECT_FALSE(session);
338 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
339 }
340
341 // A session receiving a GOAWAY frame with active streams should close
342 // when the last active stream is closed.
TEST_P(SpdySessionTest,GoAwayWithActiveStreams)343 TEST_P(SpdySessionTest, GoAwayWithActiveStreams) {
344 session_deps_.host_resolver->set_synchronous_mode(true);
345
346 MockConnect connect_data(SYNCHRONOUS, OK);
347 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
348 MockRead reads[] = {
349 CreateMockRead(*goaway, 2),
350 MockRead(ASYNC, 0, 3) // EOF
351 };
352 scoped_ptr<SpdyFrame> req1(
353 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
354 scoped_ptr<SpdyFrame> req2(
355 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
356 MockWrite writes[] = {
357 CreateMockWrite(*req1, 0),
358 CreateMockWrite(*req2, 1),
359 };
360 DeterministicSocketData data(reads, arraysize(reads),
361 writes, arraysize(writes));
362 data.set_connect_data(connect_data);
363 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
364
365 CreateDeterministicNetworkSession();
366
367 base::WeakPtr<SpdySession> session =
368 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
369
370 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
371
372 GURL url(kDefaultURL);
373 base::WeakPtr<SpdyStream> spdy_stream1 =
374 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
375 session, url, MEDIUM, BoundNetLog());
376 test::StreamDelegateDoNothing delegate1(spdy_stream1);
377 spdy_stream1->SetDelegate(&delegate1);
378
379 base::WeakPtr<SpdyStream> spdy_stream2 =
380 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
381 session, url, MEDIUM, BoundNetLog());
382 test::StreamDelegateDoNothing delegate2(spdy_stream2);
383 spdy_stream2->SetDelegate(&delegate2);
384
385 scoped_ptr<SpdyHeaderBlock> headers(
386 spdy_util_.ConstructGetHeaderBlock(url.spec()));
387 scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(*headers));
388
389 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
390 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
391 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
392 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
393
394 data.RunFor(2);
395
396 EXPECT_EQ(1u, spdy_stream1->stream_id());
397 EXPECT_EQ(3u, spdy_stream2->stream_id());
398
399 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
400
401 // Read and process the GOAWAY frame.
402 data.RunFor(1);
403
404 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
405
406 EXPECT_FALSE(session->IsStreamActive(3));
407 EXPECT_EQ(NULL, spdy_stream2.get());
408 EXPECT_TRUE(session->IsStreamActive(1));
409
410 EXPECT_TRUE(session->IsGoingAway());
411
412 // Should close the session.
413 spdy_stream1->Close();
414 EXPECT_EQ(NULL, spdy_stream1.get());
415
416 base::MessageLoop::current()->RunUntilIdle();
417 EXPECT_TRUE(session == NULL);
418 }
419
420 // Have a session receive two GOAWAY frames, with the last one causing
421 // the last active stream to be closed. The session should then be
422 // closed after the second GOAWAY frame.
TEST_P(SpdySessionTest,GoAwayTwice)423 TEST_P(SpdySessionTest, GoAwayTwice) {
424 session_deps_.host_resolver->set_synchronous_mode(true);
425
426 MockConnect connect_data(SYNCHRONOUS, OK);
427 scoped_ptr<SpdyFrame> goaway1(spdy_util_.ConstructSpdyGoAway(1));
428 scoped_ptr<SpdyFrame> goaway2(spdy_util_.ConstructSpdyGoAway(0));
429 MockRead reads[] = {
430 CreateMockRead(*goaway1, 2),
431 CreateMockRead(*goaway2, 3),
432 MockRead(ASYNC, 0, 4) // EOF
433 };
434 scoped_ptr<SpdyFrame> req1(
435 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
436 scoped_ptr<SpdyFrame> req2(
437 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
438 MockWrite writes[] = {
439 CreateMockWrite(*req1, 0),
440 CreateMockWrite(*req2, 1),
441 };
442 DeterministicSocketData data(reads, arraysize(reads),
443 writes, arraysize(writes));
444 data.set_connect_data(connect_data);
445 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
446
447 CreateDeterministicNetworkSession();
448
449 base::WeakPtr<SpdySession> session =
450 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
451
452 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
453
454 GURL url(kDefaultURL);
455 base::WeakPtr<SpdyStream> spdy_stream1 =
456 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
457 session, url, MEDIUM, BoundNetLog());
458 test::StreamDelegateDoNothing delegate1(spdy_stream1);
459 spdy_stream1->SetDelegate(&delegate1);
460
461 base::WeakPtr<SpdyStream> spdy_stream2 =
462 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
463 session, url, MEDIUM, BoundNetLog());
464 test::StreamDelegateDoNothing delegate2(spdy_stream2);
465 spdy_stream2->SetDelegate(&delegate2);
466
467 scoped_ptr<SpdyHeaderBlock> headers(
468 spdy_util_.ConstructGetHeaderBlock(url.spec()));
469 scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(*headers));
470
471 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
472 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
473 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
474 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
475
476 data.RunFor(2);
477
478 EXPECT_EQ(1u, spdy_stream1->stream_id());
479 EXPECT_EQ(3u, spdy_stream2->stream_id());
480
481 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
482
483 // Read and process the first GOAWAY frame.
484 data.RunFor(1);
485
486 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
487
488 EXPECT_FALSE(session->IsStreamActive(3));
489 EXPECT_EQ(NULL, spdy_stream2.get());
490 EXPECT_TRUE(session->IsStreamActive(1));
491 EXPECT_TRUE(session->IsGoingAway());
492
493 // Read and process the second GOAWAY frame, which should close the
494 // session.
495 data.RunFor(1);
496 base::MessageLoop::current()->RunUntilIdle();
497 EXPECT_TRUE(session == NULL);
498 }
499
500 // Have a session with active streams receive a GOAWAY frame and then
501 // close it. It should handle the close properly (i.e., not try to
502 // make itself unavailable in its pool twice).
TEST_P(SpdySessionTest,GoAwayWithActiveStreamsThenClose)503 TEST_P(SpdySessionTest, GoAwayWithActiveStreamsThenClose) {
504 session_deps_.host_resolver->set_synchronous_mode(true);
505
506 MockConnect connect_data(SYNCHRONOUS, OK);
507 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
508 MockRead reads[] = {
509 CreateMockRead(*goaway, 2),
510 MockRead(ASYNC, 0, 3) // EOF
511 };
512 scoped_ptr<SpdyFrame> req1(
513 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
514 scoped_ptr<SpdyFrame> req2(
515 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
516 MockWrite writes[] = {
517 CreateMockWrite(*req1, 0),
518 CreateMockWrite(*req2, 1),
519 };
520 DeterministicSocketData data(reads, arraysize(reads),
521 writes, arraysize(writes));
522 data.set_connect_data(connect_data);
523 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
524
525 CreateDeterministicNetworkSession();
526
527 base::WeakPtr<SpdySession> session =
528 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
529
530 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
531
532 GURL url(kDefaultURL);
533 base::WeakPtr<SpdyStream> spdy_stream1 =
534 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
535 session, url, MEDIUM, BoundNetLog());
536 test::StreamDelegateDoNothing delegate1(spdy_stream1);
537 spdy_stream1->SetDelegate(&delegate1);
538
539 base::WeakPtr<SpdyStream> spdy_stream2 =
540 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
541 session, url, MEDIUM, BoundNetLog());
542 test::StreamDelegateDoNothing delegate2(spdy_stream2);
543 spdy_stream2->SetDelegate(&delegate2);
544
545 scoped_ptr<SpdyHeaderBlock> headers(
546 spdy_util_.ConstructGetHeaderBlock(url.spec()));
547 scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(*headers));
548
549 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
550 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
551 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
552 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
553
554 data.RunFor(2);
555
556 EXPECT_EQ(1u, spdy_stream1->stream_id());
557 EXPECT_EQ(3u, spdy_stream2->stream_id());
558
559 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
560
561 // Read and process the GOAWAY frame.
562 data.RunFor(1);
563
564 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
565
566 EXPECT_FALSE(session->IsStreamActive(3));
567 EXPECT_EQ(NULL, spdy_stream2.get());
568 EXPECT_TRUE(session->IsStreamActive(1));
569 EXPECT_TRUE(session->IsGoingAway());
570
571 session->CloseSessionOnError(ERR_ABORTED, "Aborting session");
572 EXPECT_EQ(NULL, spdy_stream1.get());
573
574 base::MessageLoop::current()->RunUntilIdle();
575 EXPECT_TRUE(session == NULL);
576 }
577
578 // Process a joint read buffer which causes the session to begin draining, and
579 // then processes a GOAWAY. The session should gracefully drain. Regression test
580 // for crbug.com/379469
TEST_P(SpdySessionTest,GoAwayWhileDraining)581 TEST_P(SpdySessionTest, GoAwayWhileDraining) {
582 session_deps_.host_resolver->set_synchronous_mode(true);
583
584 scoped_ptr<SpdyFrame> req(
585 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
586 MockWrite writes[] = {
587 CreateMockWrite(*req, 0),
588 };
589
590 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
591 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
592 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
593 size_t joint_size = goaway->size() * 2 + body->size();
594
595 // Compose interleaved |goaway| and |body| frames into a single read.
596 scoped_ptr<char[]> buffer(new char[joint_size]);
597 {
598 size_t out = 0;
599 memcpy(&buffer[out], goaway->data(), goaway->size());
600 out += goaway->size();
601 memcpy(&buffer[out], body->data(), body->size());
602 out += body->size();
603 memcpy(&buffer[out], goaway->data(), goaway->size());
604 out += goaway->size();
605 ASSERT_EQ(out, joint_size);
606 }
607 SpdyFrame joint_frames(buffer.get(), joint_size, false);
608
609 MockRead reads[] = {
610 CreateMockRead(*resp, 1), CreateMockRead(joint_frames, 2),
611 MockRead(ASYNC, 0, 3) // EOF
612 };
613
614 MockConnect connect_data(SYNCHRONOUS, OK);
615 DeterministicSocketData data(
616 reads, arraysize(reads), writes, arraysize(writes));
617 data.set_connect_data(connect_data);
618 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
619
620 CreateDeterministicNetworkSession();
621 base::WeakPtr<SpdySession> session =
622 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
623
624 GURL url(kDefaultURL);
625 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
626 SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
627 test::StreamDelegateDoNothing delegate(spdy_stream);
628 spdy_stream->SetDelegate(&delegate);
629
630 scoped_ptr<SpdyHeaderBlock> headers(
631 spdy_util_.ConstructGetHeaderBlock(url.spec()));
632 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
633 EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
634
635 data.RunFor(3);
636 base::MessageLoop::current()->RunUntilIdle();
637
638 // Stream and session closed gracefully.
639 EXPECT_TRUE(delegate.StreamIsClosed());
640 EXPECT_EQ(OK, delegate.WaitForClose());
641 EXPECT_EQ(kUploadData, delegate.TakeReceivedData());
642 EXPECT_TRUE(session == NULL);
643 }
644
645 // Try to create a stream after receiving a GOAWAY frame. It should
646 // fail.
TEST_P(SpdySessionTest,CreateStreamAfterGoAway)647 TEST_P(SpdySessionTest, CreateStreamAfterGoAway) {
648 session_deps_.host_resolver->set_synchronous_mode(true);
649
650 MockConnect connect_data(SYNCHRONOUS, OK);
651 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
652 MockRead reads[] = {
653 CreateMockRead(*goaway, 1),
654 MockRead(ASYNC, 0, 2) // EOF
655 };
656 scoped_ptr<SpdyFrame> req(
657 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
658 MockWrite writes[] = {
659 CreateMockWrite(*req, 0),
660 };
661 DeterministicSocketData data(reads, arraysize(reads),
662 writes, arraysize(writes));
663 data.set_connect_data(connect_data);
664 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
665
666 CreateDeterministicNetworkSession();
667
668 base::WeakPtr<SpdySession> session =
669 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
670
671 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
672
673 GURL url(kDefaultURL);
674 base::WeakPtr<SpdyStream> spdy_stream =
675 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
676 session, url, MEDIUM, BoundNetLog());
677 test::StreamDelegateDoNothing delegate(spdy_stream);
678 spdy_stream->SetDelegate(&delegate);
679
680 scoped_ptr<SpdyHeaderBlock> headers(
681 spdy_util_.ConstructGetHeaderBlock(url.spec()));
682 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
683 EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
684
685 data.RunFor(1);
686
687 EXPECT_EQ(1u, spdy_stream->stream_id());
688
689 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
690
691 // Read and process the GOAWAY frame.
692 data.RunFor(1);
693
694 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
695 EXPECT_TRUE(session->IsStreamActive(1));
696
697 SpdyStreamRequest stream_request;
698 int rv = stream_request.StartRequest(
699 SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog(),
700 CompletionCallback());
701 EXPECT_EQ(ERR_FAILED, rv);
702
703 // Read and process EOF.
704 data.RunFor(1);
705
706 EXPECT_TRUE(session == NULL);
707 }
708
709 // Receiving a SYN_STREAM frame after a GOAWAY frame should result in
710 // the stream being refused.
TEST_P(SpdySessionTest,SynStreamAfterGoAway)711 TEST_P(SpdySessionTest, SynStreamAfterGoAway) {
712 session_deps_.host_resolver->set_synchronous_mode(true);
713
714 MockConnect connect_data(SYNCHRONOUS, OK);
715 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
716 scoped_ptr<SpdyFrame>
717 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kDefaultURL));
718 MockRead reads[] = {
719 CreateMockRead(*goaway, 1),
720 CreateMockRead(*push, 2),
721 MockRead(ASYNC, 0, 4) // EOF
722 };
723 scoped_ptr<SpdyFrame> req(
724 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
725 scoped_ptr<SpdyFrame> rst(
726 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
727 MockWrite writes[] = {
728 CreateMockWrite(*req, 0),
729 CreateMockWrite(*rst, 3)
730 };
731 DeterministicSocketData data(reads, arraysize(reads),
732 writes, arraysize(writes));
733 data.set_connect_data(connect_data);
734 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
735
736 CreateDeterministicNetworkSession();
737
738 base::WeakPtr<SpdySession> session =
739 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
740
741 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
742
743 GURL url(kDefaultURL);
744 base::WeakPtr<SpdyStream> spdy_stream =
745 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
746 session, url, MEDIUM, BoundNetLog());
747 test::StreamDelegateDoNothing delegate(spdy_stream);
748 spdy_stream->SetDelegate(&delegate);
749
750 scoped_ptr<SpdyHeaderBlock> headers(
751 spdy_util_.ConstructGetHeaderBlock(url.spec()));
752 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
753 EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
754
755 data.RunFor(1);
756
757 EXPECT_EQ(1u, spdy_stream->stream_id());
758
759 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
760
761 // Read and process the GOAWAY frame.
762 data.RunFor(1);
763
764 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
765 EXPECT_TRUE(session->IsStreamActive(1));
766
767 // Read and process the SYN_STREAM frame, the subsequent RST_STREAM,
768 // and EOF.
769 data.RunFor(3);
770 base::MessageLoop::current()->RunUntilIdle();
771 EXPECT_TRUE(session == NULL);
772 }
773
774 // A session observing a network change with active streams should close
775 // when the last active stream is closed.
TEST_P(SpdySessionTest,NetworkChangeWithActiveStreams)776 TEST_P(SpdySessionTest, NetworkChangeWithActiveStreams) {
777 session_deps_.host_resolver->set_synchronous_mode(true);
778
779 MockConnect connect_data(SYNCHRONOUS, OK);
780 MockRead reads[] = {
781 MockRead(ASYNC, 0, 1) // EOF
782 };
783 scoped_ptr<SpdyFrame> req1(
784 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
785 MockWrite writes[] = {
786 CreateMockWrite(*req1, 0),
787 };
788 DeterministicSocketData data(reads, arraysize(reads),
789 writes, arraysize(writes));
790 data.set_connect_data(connect_data);
791 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
792
793 CreateDeterministicNetworkSession();
794
795 base::WeakPtr<SpdySession> session =
796 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
797
798 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
799
800 base::WeakPtr<SpdyStream> spdy_stream =
801 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session,
802 GURL(kDefaultURL), MEDIUM, BoundNetLog());
803 test::StreamDelegateDoNothing delegate(spdy_stream);
804 spdy_stream->SetDelegate(&delegate);
805
806 scoped_ptr<SpdyHeaderBlock> headers(
807 spdy_util_.ConstructGetHeaderBlock(kDefaultURL));
808
809 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
810 EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
811
812 data.RunFor(1);
813
814 EXPECT_EQ(1u, spdy_stream->stream_id());
815
816 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
817
818 spdy_session_pool_->OnIPAddressChanged();
819
820 // The SpdySessionPool behavior differs based on how the OSs reacts to
821 // network changes; see comment in SpdySessionPool::OnIPAddressChanged().
822 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
823 // For OSs where the TCP connections will close upon relevant network
824 // changes, SpdySessionPool doesn't need to force them to close, so in these
825 // cases verify the session has become unavailable but remains open and the
826 // pre-existing stream is still active.
827 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
828
829 EXPECT_TRUE(session->IsGoingAway());
830
831 EXPECT_TRUE(session->IsStreamActive(1));
832
833 // Should close the session.
834 spdy_stream->Close();
835 #endif
836 EXPECT_EQ(NULL, spdy_stream.get());
837
838 base::MessageLoop::current()->RunUntilIdle();
839 EXPECT_TRUE(session == NULL);
840 }
841
TEST_P(SpdySessionTest,ClientPing)842 TEST_P(SpdySessionTest, ClientPing) {
843 session_deps_.enable_ping = true;
844 session_deps_.host_resolver->set_synchronous_mode(true);
845
846 MockConnect connect_data(SYNCHRONOUS, OK);
847 scoped_ptr<SpdyFrame> read_ping(spdy_util_.ConstructSpdyPing(1, true));
848 MockRead reads[] = {
849 CreateMockRead(*read_ping, 1),
850 MockRead(ASYNC, 0, 0, 2) // EOF
851 };
852 scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false));
853 MockWrite writes[] = {
854 CreateMockWrite(*write_ping, 0),
855 };
856 DeterministicSocketData data(
857 reads, arraysize(reads), writes, arraysize(writes));
858 data.set_connect_data(connect_data);
859 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
860
861 CreateDeterministicNetworkSession();
862
863 base::WeakPtr<SpdySession> session =
864 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
865
866 base::WeakPtr<SpdyStream> spdy_stream1 =
867 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
868 session, test_url_, MEDIUM, BoundNetLog());
869 ASSERT_TRUE(spdy_stream1.get() != NULL);
870 test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL);
871 spdy_stream1->SetDelegate(&delegate);
872
873 base::TimeTicks before_ping_time = base::TimeTicks::Now();
874
875 session->set_connection_at_risk_of_loss_time(
876 base::TimeDelta::FromSeconds(-1));
877 session->set_hung_interval(base::TimeDelta::FromMilliseconds(50));
878
879 session->SendPrefacePingIfNoneInFlight();
880
881 data.RunFor(2);
882
883 session->CheckPingStatus(before_ping_time);
884
885 EXPECT_EQ(0, session->pings_in_flight());
886 EXPECT_GE(session->next_ping_id(), static_cast<uint32>(1));
887 EXPECT_FALSE(session->check_ping_status_pending());
888 EXPECT_GE(session->last_activity_time(), before_ping_time);
889
890 data.RunFor(1);
891
892 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
893
894 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
895 EXPECT_TRUE(session == NULL);
896 }
897
TEST_P(SpdySessionTest,ServerPing)898 TEST_P(SpdySessionTest, ServerPing) {
899 session_deps_.host_resolver->set_synchronous_mode(true);
900
901 MockConnect connect_data(SYNCHRONOUS, OK);
902 scoped_ptr<SpdyFrame> read_ping(spdy_util_.ConstructSpdyPing(2, false));
903 MockRead reads[] = {
904 CreateMockRead(*read_ping),
905 MockRead(SYNCHRONOUS, 0, 0) // EOF
906 };
907 scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(2, true));
908 MockWrite writes[] = {
909 CreateMockWrite(*write_ping),
910 };
911 StaticSocketDataProvider data(
912 reads, arraysize(reads), writes, arraysize(writes));
913 data.set_connect_data(connect_data);
914 session_deps_.socket_factory->AddSocketDataProvider(&data);
915
916 CreateNetworkSession();
917
918 base::WeakPtr<SpdySession> session =
919 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
920
921 base::WeakPtr<SpdyStream> spdy_stream1 =
922 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
923 session, test_url_, MEDIUM, BoundNetLog());
924 ASSERT_TRUE(spdy_stream1.get() != NULL);
925 test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL);
926 spdy_stream1->SetDelegate(&delegate);
927
928 // Flush the read completion task.
929 base::MessageLoop::current()->RunUntilIdle();
930
931 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
932
933 EXPECT_TRUE(session == NULL);
934 EXPECT_EQ(NULL, spdy_stream1.get());
935 }
936
937 // Cause a ping to be sent out while producing a write. The write loop
938 // should handle this properly, i.e. another DoWriteLoop task should
939 // not be posted. This is a regression test for
940 // http://crbug.com/261043 .
TEST_P(SpdySessionTest,PingAndWriteLoop)941 TEST_P(SpdySessionTest, PingAndWriteLoop) {
942 session_deps_.enable_ping = true;
943 session_deps_.time_func = TheNearFuture;
944
945 MockConnect connect_data(SYNCHRONOUS, OK);
946 scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false));
947 scoped_ptr<SpdyFrame> req(
948 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
949 MockWrite writes[] = {
950 CreateMockWrite(*req, 0),
951 CreateMockWrite(*write_ping, 1),
952 };
953
954 MockRead reads[] = {
955 MockRead(ASYNC, 0, 2) // EOF
956 };
957
958 session_deps_.host_resolver->set_synchronous_mode(true);
959
960 DeterministicSocketData data(reads, arraysize(reads),
961 writes, arraysize(writes));
962 data.set_connect_data(connect_data);
963 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
964
965 CreateDeterministicNetworkSession();
966
967 base::WeakPtr<SpdySession> session =
968 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
969
970 GURL url(kDefaultURL);
971 base::WeakPtr<SpdyStream> spdy_stream =
972 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
973 session, url, LOWEST, BoundNetLog());
974 test::StreamDelegateDoNothing delegate(spdy_stream);
975 spdy_stream->SetDelegate(&delegate);
976
977 scoped_ptr<SpdyHeaderBlock> headers(
978 spdy_util_.ConstructGetHeaderBlock(url.spec()));
979 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
980
981 // Shift time so that a ping will be sent out.
982 g_time_delta = base::TimeDelta::FromSeconds(11);
983
984 data.RunFor(2);
985
986 session->CloseSessionOnError(ERR_ABORTED, "Aborting");
987 }
988
TEST_P(SpdySessionTest,StreamIdSpaceExhausted)989 TEST_P(SpdySessionTest, StreamIdSpaceExhausted) {
990 const SpdyStreamId kLastStreamId = 0x7fffffff;
991 session_deps_.host_resolver->set_synchronous_mode(true);
992
993 // Test setup: |stream_hi_water_mark_| and |max_concurrent_streams_| are
994 // fixed to allow for two stream ID assignments, and three concurrent
995 // streams. Four streams are started, and two are activated. Verify the
996 // session goes away, and that the created (but not activated) and
997 // stalled streams are aborted. Also verify the activated streams complete,
998 // at which point the session closes.
999
1000 scoped_ptr<SpdyFrame> req1(spdy_util_.ConstructSpdyGet(
1001 NULL, 0, false, kLastStreamId - 2, MEDIUM, true));
1002 scoped_ptr<SpdyFrame> req2(
1003 spdy_util_.ConstructSpdyGet(NULL, 0, false, kLastStreamId, MEDIUM, true));
1004
1005 MockWrite writes[] = {
1006 CreateMockWrite(*req1, 0), CreateMockWrite(*req2, 1),
1007 };
1008
1009 scoped_ptr<SpdyFrame> resp1(
1010 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, kLastStreamId - 2));
1011 scoped_ptr<SpdyFrame> resp2(
1012 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, kLastStreamId));
1013
1014 scoped_ptr<SpdyFrame> body1(
1015 spdy_util_.ConstructSpdyBodyFrame(kLastStreamId - 2, true));
1016 scoped_ptr<SpdyFrame> body2(
1017 spdy_util_.ConstructSpdyBodyFrame(kLastStreamId, true));
1018
1019 MockRead reads[] = {
1020 CreateMockRead(*resp1, 2), CreateMockRead(*resp2, 3),
1021 CreateMockRead(*body1, 4), CreateMockRead(*body2, 5),
1022 MockRead(ASYNC, 0, 6) // EOF
1023 };
1024
1025 DeterministicSocketData data(
1026 reads, arraysize(reads), writes, arraysize(writes));
1027
1028 MockConnect connect_data(SYNCHRONOUS, OK);
1029 data.set_connect_data(connect_data);
1030 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1031
1032 CreateDeterministicNetworkSession();
1033 base::WeakPtr<SpdySession> session =
1034 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1035
1036 // Fix stream_hi_water_mark_ to allow for two stream activations.
1037 session->stream_hi_water_mark_ = kLastStreamId - 2;
1038 // Fix max_concurrent_streams to allow for three stream creations.
1039 session->max_concurrent_streams_ = 3;
1040
1041 // Create three streams synchronously, and begin a fourth (which is stalled).
1042 GURL url(kDefaultURL);
1043 base::WeakPtr<SpdyStream> stream1 = CreateStreamSynchronously(
1044 SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
1045 test::StreamDelegateDoNothing delegate1(stream1);
1046 stream1->SetDelegate(&delegate1);
1047
1048 base::WeakPtr<SpdyStream> stream2 = CreateStreamSynchronously(
1049 SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
1050 test::StreamDelegateDoNothing delegate2(stream2);
1051 stream2->SetDelegate(&delegate2);
1052
1053 base::WeakPtr<SpdyStream> stream3 = CreateStreamSynchronously(
1054 SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
1055 test::StreamDelegateDoNothing delegate3(stream3);
1056 stream3->SetDelegate(&delegate3);
1057
1058 SpdyStreamRequest request4;
1059 TestCompletionCallback callback4;
1060 EXPECT_EQ(ERR_IO_PENDING,
1061 request4.StartRequest(SPDY_REQUEST_RESPONSE_STREAM,
1062 session,
1063 url,
1064 MEDIUM,
1065 BoundNetLog(),
1066 callback4.callback()));
1067
1068 // Streams 1-3 were created. 4th is stalled. No streams are active yet.
1069 EXPECT_EQ(0u, session->num_active_streams());
1070 EXPECT_EQ(3u, session->num_created_streams());
1071 EXPECT_EQ(1u, session->pending_create_stream_queue_size(MEDIUM));
1072
1073 // Activate stream 1. One ID remains available.
1074 stream1->SendRequestHeaders(
1075 scoped_ptr<SpdyHeaderBlock>(
1076 spdy_util_.ConstructGetHeaderBlock(url.spec())),
1077 NO_MORE_DATA_TO_SEND);
1078 data.RunFor(1);
1079
1080 EXPECT_EQ(kLastStreamId - 2u, stream1->stream_id());
1081 EXPECT_EQ(1u, session->num_active_streams());
1082 EXPECT_EQ(2u, session->num_created_streams());
1083 EXPECT_EQ(1u, session->pending_create_stream_queue_size(MEDIUM));
1084
1085 // Activate stream 2. ID space is exhausted.
1086 stream2->SendRequestHeaders(
1087 scoped_ptr<SpdyHeaderBlock>(
1088 spdy_util_.ConstructGetHeaderBlock(url.spec())),
1089 NO_MORE_DATA_TO_SEND);
1090 data.RunFor(1);
1091
1092 // Active streams remain active.
1093 EXPECT_EQ(kLastStreamId, stream2->stream_id());
1094 EXPECT_EQ(2u, session->num_active_streams());
1095
1096 // Session is going away. Created and stalled streams were aborted.
1097 EXPECT_EQ(SpdySession::STATE_GOING_AWAY, session->availability_state_);
1098 EXPECT_EQ(ERR_ABORTED, delegate3.WaitForClose());
1099 EXPECT_EQ(ERR_ABORTED, callback4.WaitForResult());
1100 EXPECT_EQ(0u, session->num_created_streams());
1101 EXPECT_EQ(0u, session->pending_create_stream_queue_size(MEDIUM));
1102
1103 // Read responses on remaining active streams.
1104 data.RunFor(4);
1105 EXPECT_EQ(OK, delegate1.WaitForClose());
1106 EXPECT_EQ(kUploadData, delegate1.TakeReceivedData());
1107 EXPECT_EQ(OK, delegate2.WaitForClose());
1108 EXPECT_EQ(kUploadData, delegate2.TakeReceivedData());
1109
1110 // Session was destroyed.
1111 base::MessageLoop::current()->RunUntilIdle();
1112 EXPECT_FALSE(session.get());
1113 }
1114
1115 // Verifies that an unstalled pending stream creation racing with a new stream
1116 // creation doesn't violate the maximum stream concurrency. Regression test for
1117 // crbug.com/373858.
TEST_P(SpdySessionTest,UnstallRacesWithStreamCreation)1118 TEST_P(SpdySessionTest, UnstallRacesWithStreamCreation) {
1119 session_deps_.host_resolver->set_synchronous_mode(true);
1120
1121 MockRead reads[] = {
1122 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
1123 };
1124
1125 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
1126
1127 MockConnect connect_data(SYNCHRONOUS, OK);
1128 data.set_connect_data(connect_data);
1129 session_deps_.socket_factory->AddSocketDataProvider(&data);
1130
1131 CreateNetworkSession();
1132 base::WeakPtr<SpdySession> session =
1133 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1134
1135 // Fix max_concurrent_streams to allow for one open stream.
1136 session->max_concurrent_streams_ = 1;
1137
1138 // Create two streams: one synchronously, and one which stalls.
1139 GURL url(kDefaultURL);
1140 base::WeakPtr<SpdyStream> stream1 = CreateStreamSynchronously(
1141 SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
1142
1143 SpdyStreamRequest request2;
1144 TestCompletionCallback callback2;
1145 EXPECT_EQ(ERR_IO_PENDING,
1146 request2.StartRequest(SPDY_REQUEST_RESPONSE_STREAM,
1147 session,
1148 url,
1149 MEDIUM,
1150 BoundNetLog(),
1151 callback2.callback()));
1152
1153 EXPECT_EQ(1u, session->num_created_streams());
1154 EXPECT_EQ(1u, session->pending_create_stream_queue_size(MEDIUM));
1155
1156 // Cancel the first stream. A callback to unstall the second stream was
1157 // posted. Don't run it yet.
1158 stream1->Cancel();
1159
1160 EXPECT_EQ(0u, session->num_created_streams());
1161 EXPECT_EQ(0u, session->pending_create_stream_queue_size(MEDIUM));
1162
1163 // Create a third stream prior to the second stream's callback.
1164 base::WeakPtr<SpdyStream> stream3 = CreateStreamSynchronously(
1165 SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
1166
1167 EXPECT_EQ(1u, session->num_created_streams());
1168 EXPECT_EQ(0u, session->pending_create_stream_queue_size(MEDIUM));
1169
1170 // NOW run the message loop. The unstalled stream will re-stall itself.
1171 base::MessageLoop::current()->RunUntilIdle();
1172 EXPECT_EQ(1u, session->num_created_streams());
1173 EXPECT_EQ(1u, session->pending_create_stream_queue_size(MEDIUM));
1174
1175 // Cancel the third stream and run the message loop. Verify that the second
1176 // stream creation now completes.
1177 stream3->Cancel();
1178 base::MessageLoop::current()->RunUntilIdle();
1179
1180 EXPECT_EQ(1u, session->num_created_streams());
1181 EXPECT_EQ(0u, session->pending_create_stream_queue_size(MEDIUM));
1182 EXPECT_EQ(OK, callback2.WaitForResult());
1183 }
1184
TEST_P(SpdySessionTest,DeleteExpiredPushStreams)1185 TEST_P(SpdySessionTest, DeleteExpiredPushStreams) {
1186 session_deps_.host_resolver->set_synchronous_mode(true);
1187 session_deps_.time_func = TheNearFuture;
1188
1189 scoped_ptr<SpdyFrame> req(
1190 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
1191 scoped_ptr<SpdyFrame> rst(
1192 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
1193
1194 scoped_ptr<SpdyFrame> push_a(spdy_util_.ConstructSpdyPush(
1195 NULL, 0, 2, 1, "http://www.google.com/a.dat"));
1196 scoped_ptr<SpdyFrame> push_a_body(
1197 spdy_util_.ConstructSpdyBodyFrame(2, false));
1198 scoped_ptr<SpdyFrame> push_b(spdy_util_.ConstructSpdyPush(
1199 NULL, 0, 4, 1, "http://www.google.com/b.dat"));
1200 MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4)};
1201 MockRead reads[] = {
1202 CreateMockRead(*push_a, 1), CreateMockRead(*push_a_body, 2),
1203 CreateMockRead(*push_b, 3), MockRead(ASYNC, 0, 5), // EOF
1204 };
1205 DeterministicSocketData data(
1206 reads, arraysize(reads), writes, arraysize(writes));
1207
1208 MockConnect connect_data(SYNCHRONOUS, OK);
1209 data.set_connect_data(connect_data);
1210 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1211
1212 CreateDeterministicNetworkSession();
1213 base::WeakPtr<SpdySession> session =
1214 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1215
1216 // Process the principal request, and the first push stream request & body.
1217 GURL url(kDefaultURL);
1218 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
1219 SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
1220 test::StreamDelegateDoNothing delegate(spdy_stream);
1221 spdy_stream->SetDelegate(&delegate);
1222
1223 scoped_ptr<SpdyHeaderBlock> headers(
1224 spdy_util_.ConstructGetHeaderBlock(url.spec()));
1225 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
1226
1227 data.RunFor(3);
1228
1229 // Verify that there is one unclaimed push stream.
1230 EXPECT_EQ(1u, session->num_unclaimed_pushed_streams());
1231 SpdySession::PushedStreamMap::iterator iter =
1232 session->unclaimed_pushed_streams_.find(
1233 GURL("http://www.google.com/a.dat"));
1234 EXPECT_TRUE(session->unclaimed_pushed_streams_.end() != iter);
1235
1236 if (session->flow_control_state_ ==
1237 SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) {
1238 // Unclaimed push body consumed bytes from the session window.
1239 EXPECT_EQ(kSpdySessionInitialWindowSize - kUploadDataSize,
1240 session->session_recv_window_size_);
1241 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
1242 }
1243
1244 // Shift time to expire the push stream. Read the second SYN_STREAM,
1245 // and verify a RST_STREAM was written.
1246 g_time_delta = base::TimeDelta::FromSeconds(301);
1247 data.RunFor(2);
1248
1249 // Verify that the second pushed stream evicted the first pushed stream.
1250 EXPECT_EQ(1u, session->num_unclaimed_pushed_streams());
1251 iter = session->unclaimed_pushed_streams_.find(
1252 GURL("http://www.google.com/b.dat"));
1253 EXPECT_TRUE(session->unclaimed_pushed_streams_.end() != iter);
1254
1255 if (session->flow_control_state_ ==
1256 SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) {
1257 // Verify that the session window reclaimed the evicted stream body.
1258 EXPECT_EQ(kSpdySessionInitialWindowSize,
1259 session->session_recv_window_size_);
1260 EXPECT_EQ(kUploadDataSize, session->session_unacked_recv_window_bytes_);
1261 }
1262
1263 // Read and process EOF.
1264 data.RunFor(1);
1265 base::MessageLoop::current()->RunUntilIdle();
1266 EXPECT_TRUE(session == NULL);
1267 }
1268
TEST_P(SpdySessionTest,FailedPing)1269 TEST_P(SpdySessionTest, FailedPing) {
1270 session_deps_.host_resolver->set_synchronous_mode(true);
1271
1272 MockConnect connect_data(SYNCHRONOUS, OK);
1273 MockRead reads[] = {
1274 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
1275 };
1276 scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false));
1277 scoped_ptr<SpdyFrame> goaway(
1278 spdy_util_.ConstructSpdyGoAway(0, GOAWAY_PROTOCOL_ERROR, "Failed ping."));
1279 MockWrite writes[] = {CreateMockWrite(*write_ping), CreateMockWrite(*goaway)};
1280 StaticSocketDataProvider data(
1281 reads, arraysize(reads), writes, arraysize(writes));
1282 data.set_connect_data(connect_data);
1283 session_deps_.socket_factory->AddSocketDataProvider(&data);
1284
1285 CreateNetworkSession();
1286
1287 base::WeakPtr<SpdySession> session =
1288 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1289
1290 base::WeakPtr<SpdyStream> spdy_stream1 =
1291 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1292 session, test_url_, MEDIUM, BoundNetLog());
1293 ASSERT_TRUE(spdy_stream1.get() != NULL);
1294 test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL);
1295 spdy_stream1->SetDelegate(&delegate);
1296
1297 session->set_connection_at_risk_of_loss_time(base::TimeDelta::FromSeconds(0));
1298 session->set_hung_interval(base::TimeDelta::FromSeconds(0));
1299
1300 // Send a PING frame.
1301 session->WritePingFrame(1, false);
1302 EXPECT_LT(0, session->pings_in_flight());
1303 EXPECT_GE(session->next_ping_id(), static_cast<uint32>(1));
1304 EXPECT_TRUE(session->check_ping_status_pending());
1305
1306 // Assert session is not closed.
1307 EXPECT_TRUE(session->IsAvailable());
1308 EXPECT_LT(0u, session->num_active_streams() + session->num_created_streams());
1309 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
1310
1311 // We set last time we have received any data in 1 sec less than now.
1312 // CheckPingStatus will trigger timeout because hung interval is zero.
1313 base::TimeTicks now = base::TimeTicks::Now();
1314 session->last_activity_time_ = now - base::TimeDelta::FromSeconds(1);
1315 session->CheckPingStatus(now);
1316 base::MessageLoop::current()->RunUntilIdle();
1317
1318 EXPECT_TRUE(session == NULL);
1319 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
1320 EXPECT_EQ(NULL, spdy_stream1.get());
1321 }
1322
1323 // Request kInitialMaxConcurrentStreams + 1 streams. Receive a
1324 // settings frame increasing the max concurrent streams by 1. Make
1325 // sure nothing blows up. This is a regression test for
1326 // http://crbug.com/57331 .
TEST_P(SpdySessionTest,OnSettings)1327 TEST_P(SpdySessionTest, OnSettings) {
1328 session_deps_.host_resolver->set_synchronous_mode(true);
1329
1330 const SpdySettingsIds kSpdySettingsIds = SETTINGS_MAX_CONCURRENT_STREAMS;
1331
1332 SettingsMap new_settings;
1333 const uint32 max_concurrent_streams = kInitialMaxConcurrentStreams + 1;
1334 new_settings[kSpdySettingsIds] =
1335 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1336 scoped_ptr<SpdyFrame> settings_frame(
1337 spdy_util_.ConstructSpdySettings(new_settings));
1338 MockRead reads[] = {
1339 CreateMockRead(*settings_frame, 0),
1340 MockRead(ASYNC, 0, 1),
1341 };
1342
1343 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
1344 MockWrite writes[] = {
1345 CreateMockWrite(*settings_ack, 2),
1346 };
1347
1348 DeterministicSocketData data(reads, arraysize(reads),
1349 writes, arraysize(writes));
1350 MockConnect connect_data(SYNCHRONOUS, OK);
1351 data.set_connect_data(connect_data);
1352 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1353
1354 CreateDeterministicNetworkSession();
1355
1356 base::WeakPtr<SpdySession> session =
1357 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1358
1359 // Create the maximum number of concurrent streams.
1360 for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
1361 base::WeakPtr<SpdyStream> spdy_stream =
1362 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1363 session, test_url_, MEDIUM, BoundNetLog());
1364 ASSERT_TRUE(spdy_stream != NULL);
1365 }
1366
1367 StreamReleaserCallback stream_releaser;
1368 SpdyStreamRequest request;
1369 ASSERT_EQ(ERR_IO_PENDING,
1370 request.StartRequest(
1371 SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM,
1372 BoundNetLog(),
1373 stream_releaser.MakeCallback(&request)));
1374
1375 data.RunFor(1);
1376
1377 EXPECT_EQ(OK, stream_releaser.WaitForResult());
1378
1379 data.RunFor(1);
1380 if (spdy_util_.spdy_version() >= SPDY4) {
1381 // Allow the SETTINGS+ACK to write, so the session finishes draining.
1382 data.RunFor(1);
1383 }
1384 base::MessageLoop::current()->RunUntilIdle();
1385 EXPECT_TRUE(session == NULL);
1386 }
1387
1388 // Start with a persisted value for max concurrent streams. Receive a
1389 // settings frame increasing the max concurrent streams by 1 and which
1390 // also clears the persisted data. Verify that persisted data is
1391 // correct.
TEST_P(SpdySessionTest,ClearSettings)1392 TEST_P(SpdySessionTest, ClearSettings) {
1393 if (spdy_util_.spdy_version() >= SPDY4) {
1394 // SPDY4 doesn't include settings persistence, or a CLEAR_SETTINGS flag.
1395 // Flag 0x1, CLEAR_SETTINGS in SPDY3, is instead settings ACK in SPDY4.
1396 return;
1397 }
1398 session_deps_.host_resolver->set_synchronous_mode(true);
1399
1400 SettingsMap new_settings;
1401 const uint32 max_concurrent_streams = kInitialMaxConcurrentStreams + 1;
1402 new_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1403 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1404 scoped_ptr<SpdyFrame> settings_frame(
1405 spdy_util_.ConstructSpdySettings(new_settings));
1406 uint8 flags = SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS;
1407 test::SetFrameFlags(settings_frame.get(), flags, spdy_util_.spdy_version());
1408 MockRead reads[] = {
1409 CreateMockRead(*settings_frame, 0),
1410 MockRead(ASYNC, 0, 1),
1411 };
1412
1413 DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
1414 MockConnect connect_data(SYNCHRONOUS, OK);
1415 data.set_connect_data(connect_data);
1416 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1417
1418 CreateDeterministicNetworkSession();
1419
1420 // Initialize the SpdySetting with the default.
1421 spdy_session_pool_->http_server_properties()->SetSpdySetting(
1422 test_host_port_pair_,
1423 SETTINGS_MAX_CONCURRENT_STREAMS,
1424 SETTINGS_FLAG_PLEASE_PERSIST,
1425 kInitialMaxConcurrentStreams);
1426
1427 EXPECT_FALSE(
1428 spdy_session_pool_->http_server_properties()->GetSpdySettings(
1429 test_host_port_pair_).empty());
1430
1431 base::WeakPtr<SpdySession> session =
1432 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1433
1434 // Create the maximum number of concurrent streams.
1435 for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
1436 base::WeakPtr<SpdyStream> spdy_stream =
1437 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1438 session, test_url_, MEDIUM, BoundNetLog());
1439 ASSERT_TRUE(spdy_stream != NULL);
1440 }
1441
1442 StreamReleaserCallback stream_releaser;
1443
1444 SpdyStreamRequest request;
1445 ASSERT_EQ(ERR_IO_PENDING,
1446 request.StartRequest(
1447 SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM,
1448 BoundNetLog(),
1449 stream_releaser.MakeCallback(&request)));
1450
1451 data.RunFor(1);
1452
1453 EXPECT_EQ(OK, stream_releaser.WaitForResult());
1454
1455 // Make sure that persisted data is cleared.
1456 EXPECT_TRUE(
1457 spdy_session_pool_->http_server_properties()->GetSpdySettings(
1458 test_host_port_pair_).empty());
1459
1460 // Make sure session's max_concurrent_streams is correct.
1461 EXPECT_EQ(kInitialMaxConcurrentStreams + 1,
1462 session->max_concurrent_streams());
1463
1464 data.RunFor(1);
1465 EXPECT_TRUE(session == NULL);
1466 }
1467
1468 // Start with max concurrent streams set to 1. Request two streams.
1469 // When the first completes, have the callback close its stream, which
1470 // should trigger the second stream creation. Then cancel that one
1471 // immediately. Don't crash. This is a regression test for
1472 // http://crbug.com/63532 .
TEST_P(SpdySessionTest,CancelPendingCreateStream)1473 TEST_P(SpdySessionTest, CancelPendingCreateStream) {
1474 session_deps_.host_resolver->set_synchronous_mode(true);
1475
1476 MockRead reads[] = {
1477 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
1478 };
1479
1480 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
1481 MockConnect connect_data(SYNCHRONOUS, OK);
1482
1483 data.set_connect_data(connect_data);
1484 session_deps_.socket_factory->AddSocketDataProvider(&data);
1485
1486 CreateNetworkSession();
1487
1488 // Initialize the SpdySetting with 1 max concurrent streams.
1489 spdy_session_pool_->http_server_properties()->SetSpdySetting(
1490 test_host_port_pair_,
1491 SETTINGS_MAX_CONCURRENT_STREAMS,
1492 SETTINGS_FLAG_PLEASE_PERSIST,
1493 1);
1494
1495 base::WeakPtr<SpdySession> session =
1496 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1497
1498 // Leave room for only one more stream to be created.
1499 for (size_t i = 0; i < kInitialMaxConcurrentStreams - 1; ++i) {
1500 base::WeakPtr<SpdyStream> spdy_stream =
1501 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1502 session, test_url_, MEDIUM, BoundNetLog());
1503 ASSERT_TRUE(spdy_stream != NULL);
1504 }
1505
1506 // Create 2 more streams. First will succeed. Second will be pending.
1507 base::WeakPtr<SpdyStream> spdy_stream1 =
1508 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1509 session, test_url_, MEDIUM, BoundNetLog());
1510 ASSERT_TRUE(spdy_stream1.get() != NULL);
1511
1512 // Use scoped_ptr to let us invalidate the memory when we want to, to trigger
1513 // a valgrind error if the callback is invoked when it's not supposed to be.
1514 scoped_ptr<TestCompletionCallback> callback(new TestCompletionCallback);
1515
1516 SpdyStreamRequest request;
1517 ASSERT_EQ(ERR_IO_PENDING,
1518 request.StartRequest(
1519 SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM,
1520 BoundNetLog(),
1521 callback->callback()));
1522
1523 // Release the first one, this will allow the second to be created.
1524 spdy_stream1->Cancel();
1525 EXPECT_EQ(NULL, spdy_stream1.get());
1526
1527 request.CancelRequest();
1528 callback.reset();
1529
1530 // Should not crash when running the pending callback.
1531 base::MessageLoop::current()->RunUntilIdle();
1532 }
1533
TEST_P(SpdySessionTest,SendInitialDataOnNewSession)1534 TEST_P(SpdySessionTest, SendInitialDataOnNewSession) {
1535 session_deps_.host_resolver->set_synchronous_mode(true);
1536
1537 MockRead reads[] = {
1538 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
1539 };
1540
1541 SettingsMap settings;
1542 const SpdySettingsIds kSpdySettingsIds1 = SETTINGS_MAX_CONCURRENT_STREAMS;
1543 const SpdySettingsIds kSpdySettingsIds2 = SETTINGS_INITIAL_WINDOW_SIZE;
1544 const uint32 kInitialRecvWindowSize = 10 * 1024 * 1024;
1545 settings[kSpdySettingsIds1] =
1546 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
1547 if (spdy_util_.spdy_version() >= SPDY3) {
1548 settings[kSpdySettingsIds2] =
1549 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kInitialRecvWindowSize);
1550 }
1551 MockConnect connect_data(SYNCHRONOUS, OK);
1552 scoped_ptr<SpdyFrame> settings_frame(
1553 spdy_util_.ConstructSpdySettings(settings));
1554 scoped_ptr<SpdyFrame> initial_window_update(
1555 spdy_util_.ConstructSpdyWindowUpdate(
1556 kSessionFlowControlStreamId,
1557 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
1558 std::vector<MockWrite> writes;
1559 if (GetParam() == kProtoSPDY4) {
1560 writes.push_back(
1561 MockWrite(ASYNC,
1562 kHttp2ConnectionHeaderPrefix,
1563 kHttp2ConnectionHeaderPrefixSize));
1564 }
1565 writes.push_back(CreateMockWrite(*settings_frame));
1566 if (GetParam() >= kProtoSPDY31) {
1567 writes.push_back(CreateMockWrite(*initial_window_update));
1568 };
1569
1570 SettingsMap server_settings;
1571 const uint32 initial_max_concurrent_streams = 1;
1572 server_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1573 SettingsFlagsAndValue(SETTINGS_FLAG_PERSISTED,
1574 initial_max_concurrent_streams);
1575 scoped_ptr<SpdyFrame> server_settings_frame(
1576 spdy_util_.ConstructSpdySettings(server_settings));
1577 writes.push_back(CreateMockWrite(*server_settings_frame));
1578
1579 session_deps_.stream_initial_recv_window_size = kInitialRecvWindowSize;
1580
1581 StaticSocketDataProvider data(reads, arraysize(reads),
1582 vector_as_array(&writes), writes.size());
1583 data.set_connect_data(connect_data);
1584 session_deps_.socket_factory->AddSocketDataProvider(&data);
1585
1586 CreateNetworkSession();
1587
1588 spdy_session_pool_->http_server_properties()->SetSpdySetting(
1589 test_host_port_pair_,
1590 SETTINGS_MAX_CONCURRENT_STREAMS,
1591 SETTINGS_FLAG_PLEASE_PERSIST,
1592 initial_max_concurrent_streams);
1593
1594 SpdySessionPoolPeer pool_peer(spdy_session_pool_);
1595 pool_peer.SetEnableSendingInitialData(true);
1596
1597 base::WeakPtr<SpdySession> session =
1598 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1599
1600 base::MessageLoop::current()->RunUntilIdle();
1601 EXPECT_TRUE(data.at_write_eof());
1602 }
1603
TEST_P(SpdySessionTest,ClearSettingsStorageOnIPAddressChanged)1604 TEST_P(SpdySessionTest, ClearSettingsStorageOnIPAddressChanged) {
1605 CreateNetworkSession();
1606
1607 base::WeakPtr<HttpServerProperties> test_http_server_properties =
1608 spdy_session_pool_->http_server_properties();
1609 SettingsFlagsAndValue flags_and_value1(SETTINGS_FLAG_PLEASE_PERSIST, 2);
1610 test_http_server_properties->SetSpdySetting(
1611 test_host_port_pair_,
1612 SETTINGS_MAX_CONCURRENT_STREAMS,
1613 SETTINGS_FLAG_PLEASE_PERSIST,
1614 2);
1615 EXPECT_NE(0u, test_http_server_properties->GetSpdySettings(
1616 test_host_port_pair_).size());
1617 spdy_session_pool_->OnIPAddressChanged();
1618 EXPECT_EQ(0u, test_http_server_properties->GetSpdySettings(
1619 test_host_port_pair_).size());
1620 }
1621
TEST_P(SpdySessionTest,Initialize)1622 TEST_P(SpdySessionTest, Initialize) {
1623 CapturingBoundNetLog log;
1624 session_deps_.net_log = log.bound().net_log();
1625 session_deps_.host_resolver->set_synchronous_mode(true);
1626
1627 MockConnect connect_data(SYNCHRONOUS, OK);
1628 MockRead reads[] = {
1629 MockRead(ASYNC, 0, 0) // EOF
1630 };
1631
1632 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
1633 data.set_connect_data(connect_data);
1634 session_deps_.socket_factory->AddSocketDataProvider(&data);
1635
1636 CreateNetworkSession();
1637
1638 base::WeakPtr<SpdySession> session =
1639 CreateInsecureSpdySession(http_session_, key_, log.bound());
1640 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
1641
1642 // Flush the read completion task.
1643 base::MessageLoop::current()->RunUntilIdle();
1644
1645 net::CapturingNetLog::CapturedEntryList entries;
1646 log.GetEntries(&entries);
1647 EXPECT_LT(0u, entries.size());
1648
1649 // Check that we logged TYPE_SPDY_SESSION_INITIALIZED correctly.
1650 int pos = net::ExpectLogContainsSomewhere(
1651 entries, 0,
1652 net::NetLog::TYPE_SPDY_SESSION_INITIALIZED,
1653 net::NetLog::PHASE_NONE);
1654 EXPECT_LT(0, pos);
1655
1656 CapturingNetLog::CapturedEntry entry = entries[pos];
1657 NetLog::Source socket_source;
1658 EXPECT_TRUE(NetLog::Source::FromEventParameters(entry.params.get(),
1659 &socket_source));
1660 EXPECT_TRUE(socket_source.IsValid());
1661 EXPECT_NE(log.bound().source().id, socket_source.id);
1662 }
1663
TEST_P(SpdySessionTest,NetLogOnSessionGoaway)1664 TEST_P(SpdySessionTest, NetLogOnSessionGoaway) {
1665 session_deps_.host_resolver->set_synchronous_mode(true);
1666
1667 MockConnect connect_data(SYNCHRONOUS, OK);
1668 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway());
1669 MockRead reads[] = {
1670 CreateMockRead(*goaway),
1671 MockRead(SYNCHRONOUS, 0, 0) // EOF
1672 };
1673
1674 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
1675 data.set_connect_data(connect_data);
1676 session_deps_.socket_factory->AddSocketDataProvider(&data);
1677
1678 CreateNetworkSession();
1679
1680 CapturingBoundNetLog log;
1681 base::WeakPtr<SpdySession> session =
1682 CreateInsecureSpdySession(http_session_, key_, log.bound());
1683 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
1684
1685 // Flush the read completion task.
1686 base::MessageLoop::current()->RunUntilIdle();
1687
1688 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
1689 EXPECT_TRUE(session == NULL);
1690
1691 // Check that the NetLog was filled reasonably.
1692 net::CapturingNetLog::CapturedEntryList entries;
1693 log.GetEntries(&entries);
1694 EXPECT_LT(0u, entries.size());
1695
1696 // Check that we logged SPDY_SESSION_CLOSE correctly.
1697 int pos = net::ExpectLogContainsSomewhere(
1698 entries, 0,
1699 net::NetLog::TYPE_SPDY_SESSION_CLOSE,
1700 net::NetLog::PHASE_NONE);
1701
1702 if (pos < static_cast<int>(entries.size())) {
1703 CapturingNetLog::CapturedEntry entry = entries[pos];
1704 int error_code = 0;
1705 ASSERT_TRUE(entry.GetNetErrorCode(&error_code));
1706 EXPECT_EQ(OK, error_code);
1707 } else {
1708 ADD_FAILURE();
1709 }
1710 }
1711
TEST_P(SpdySessionTest,NetLogOnSessionEOF)1712 TEST_P(SpdySessionTest, NetLogOnSessionEOF) {
1713 session_deps_.host_resolver->set_synchronous_mode(true);
1714
1715 MockConnect connect_data(SYNCHRONOUS, OK);
1716 MockRead reads[] = {
1717 MockRead(SYNCHRONOUS, 0, 0) // EOF
1718 };
1719
1720 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
1721 data.set_connect_data(connect_data);
1722 session_deps_.socket_factory->AddSocketDataProvider(&data);
1723
1724 CreateNetworkSession();
1725
1726 CapturingBoundNetLog log;
1727 base::WeakPtr<SpdySession> session =
1728 CreateInsecureSpdySession(http_session_, key_, log.bound());
1729 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
1730
1731 // Flush the read completion task.
1732 base::MessageLoop::current()->RunUntilIdle();
1733
1734 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
1735 EXPECT_TRUE(session == NULL);
1736
1737 // Check that the NetLog was filled reasonably.
1738 net::CapturingNetLog::CapturedEntryList entries;
1739 log.GetEntries(&entries);
1740 EXPECT_LT(0u, entries.size());
1741
1742 // Check that we logged SPDY_SESSION_CLOSE correctly.
1743 int pos =
1744 net::ExpectLogContainsSomewhere(entries,
1745 0,
1746 net::NetLog::TYPE_SPDY_SESSION_CLOSE,
1747 net::NetLog::PHASE_NONE);
1748
1749 if (pos < static_cast<int>(entries.size())) {
1750 CapturingNetLog::CapturedEntry entry = entries[pos];
1751 int error_code = 0;
1752 ASSERT_TRUE(entry.GetNetErrorCode(&error_code));
1753 EXPECT_EQ(ERR_CONNECTION_CLOSED, error_code);
1754 } else {
1755 ADD_FAILURE();
1756 }
1757 }
1758
1759 // Queue up a low-priority SYN_STREAM followed by a high-priority
1760 // one. The high priority one should still send first and receive
1761 // first.
TEST_P(SpdySessionTest,OutOfOrderSynStreams)1762 TEST_P(SpdySessionTest, OutOfOrderSynStreams) {
1763 // Construct the request.
1764 MockConnect connect_data(SYNCHRONOUS, OK);
1765 scoped_ptr<SpdyFrame> req_highest(
1766 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, HIGHEST, true));
1767 scoped_ptr<SpdyFrame> req_lowest(
1768 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1769 MockWrite writes[] = {
1770 CreateMockWrite(*req_highest, 0),
1771 CreateMockWrite(*req_lowest, 1),
1772 };
1773
1774 scoped_ptr<SpdyFrame> resp_highest(
1775 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1776 scoped_ptr<SpdyFrame> body_highest(
1777 spdy_util_.ConstructSpdyBodyFrame(1, true));
1778 scoped_ptr<SpdyFrame> resp_lowest(
1779 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1780 scoped_ptr<SpdyFrame> body_lowest(
1781 spdy_util_.ConstructSpdyBodyFrame(3, true));
1782 MockRead reads[] = {
1783 CreateMockRead(*resp_highest, 2),
1784 CreateMockRead(*body_highest, 3),
1785 CreateMockRead(*resp_lowest, 4),
1786 CreateMockRead(*body_lowest, 5),
1787 MockRead(ASYNC, 0, 6) // EOF
1788 };
1789
1790 session_deps_.host_resolver->set_synchronous_mode(true);
1791
1792 DeterministicSocketData data(reads, arraysize(reads),
1793 writes, arraysize(writes));
1794 data.set_connect_data(connect_data);
1795 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1796
1797 CreateDeterministicNetworkSession();
1798
1799 base::WeakPtr<SpdySession> session =
1800 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1801
1802 GURL url(kDefaultURL);
1803
1804 base::WeakPtr<SpdyStream> spdy_stream_lowest =
1805 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1806 session, url, LOWEST, BoundNetLog());
1807 ASSERT_TRUE(spdy_stream_lowest);
1808 EXPECT_EQ(0u, spdy_stream_lowest->stream_id());
1809 test::StreamDelegateDoNothing delegate_lowest(spdy_stream_lowest);
1810 spdy_stream_lowest->SetDelegate(&delegate_lowest);
1811
1812 base::WeakPtr<SpdyStream> spdy_stream_highest =
1813 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1814 session, url, HIGHEST, BoundNetLog());
1815 ASSERT_TRUE(spdy_stream_highest);
1816 EXPECT_EQ(0u, spdy_stream_highest->stream_id());
1817 test::StreamDelegateDoNothing delegate_highest(spdy_stream_highest);
1818 spdy_stream_highest->SetDelegate(&delegate_highest);
1819
1820 // Queue the lower priority one first.
1821
1822 scoped_ptr<SpdyHeaderBlock> headers_lowest(
1823 spdy_util_.ConstructGetHeaderBlock(url.spec()));
1824 spdy_stream_lowest->SendRequestHeaders(
1825 headers_lowest.Pass(), NO_MORE_DATA_TO_SEND);
1826 EXPECT_TRUE(spdy_stream_lowest->HasUrlFromHeaders());
1827
1828 scoped_ptr<SpdyHeaderBlock> headers_highest(
1829 spdy_util_.ConstructGetHeaderBlock(url.spec()));
1830 spdy_stream_highest->SendRequestHeaders(
1831 headers_highest.Pass(), NO_MORE_DATA_TO_SEND);
1832 EXPECT_TRUE(spdy_stream_highest->HasUrlFromHeaders());
1833
1834 data.RunFor(7);
1835
1836 EXPECT_FALSE(spdy_stream_lowest);
1837 EXPECT_FALSE(spdy_stream_highest);
1838 EXPECT_EQ(3u, delegate_lowest.stream_id());
1839 EXPECT_EQ(1u, delegate_highest.stream_id());
1840 }
1841
TEST_P(SpdySessionTest,CancelStream)1842 TEST_P(SpdySessionTest, CancelStream) {
1843 MockConnect connect_data(SYNCHRONOUS, OK);
1844 // Request 1, at HIGHEST priority, will be cancelled before it writes data.
1845 // Request 2, at LOWEST priority, will be a full request and will be id 1.
1846 scoped_ptr<SpdyFrame> req2(
1847 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1848 MockWrite writes[] = {
1849 CreateMockWrite(*req2, 0),
1850 };
1851
1852 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1853 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
1854 MockRead reads[] = {
1855 CreateMockRead(*resp2, 1),
1856 CreateMockRead(*body2, 2),
1857 MockRead(ASYNC, 0, 3) // EOF
1858 };
1859
1860 session_deps_.host_resolver->set_synchronous_mode(true);
1861
1862 DeterministicSocketData data(reads, arraysize(reads),
1863 writes, arraysize(writes));
1864 data.set_connect_data(connect_data);
1865 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1866
1867 CreateDeterministicNetworkSession();
1868
1869 base::WeakPtr<SpdySession> session =
1870 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1871
1872 GURL url1(kDefaultURL);
1873 base::WeakPtr<SpdyStream> spdy_stream1 =
1874 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1875 session, url1, HIGHEST, BoundNetLog());
1876 ASSERT_TRUE(spdy_stream1.get() != NULL);
1877 EXPECT_EQ(0u, spdy_stream1->stream_id());
1878 test::StreamDelegateDoNothing delegate1(spdy_stream1);
1879 spdy_stream1->SetDelegate(&delegate1);
1880
1881 GURL url2(kDefaultURL);
1882 base::WeakPtr<SpdyStream> spdy_stream2 =
1883 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1884 session, url2, LOWEST, BoundNetLog());
1885 ASSERT_TRUE(spdy_stream2.get() != NULL);
1886 EXPECT_EQ(0u, spdy_stream2->stream_id());
1887 test::StreamDelegateDoNothing delegate2(spdy_stream2);
1888 spdy_stream2->SetDelegate(&delegate2);
1889
1890 scoped_ptr<SpdyHeaderBlock> headers(
1891 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
1892 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
1893 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
1894
1895 scoped_ptr<SpdyHeaderBlock> headers2(
1896 spdy_util_.ConstructGetHeaderBlock(url2.spec()));
1897 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
1898 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
1899
1900 EXPECT_EQ(0u, spdy_stream1->stream_id());
1901
1902 spdy_stream1->Cancel();
1903 EXPECT_EQ(NULL, spdy_stream1.get());
1904
1905 EXPECT_EQ(0u, delegate1.stream_id());
1906
1907 data.RunFor(1);
1908
1909 EXPECT_EQ(0u, delegate1.stream_id());
1910 EXPECT_EQ(1u, delegate2.stream_id());
1911
1912 spdy_stream2->Cancel();
1913 EXPECT_EQ(NULL, spdy_stream2.get());
1914 }
1915
1916 // Create two streams that are set to re-close themselves on close,
1917 // and then close the session. Nothing should blow up. Also a
1918 // regression test for http://crbug.com/139518 .
TEST_P(SpdySessionTest,CloseSessionWithTwoCreatedSelfClosingStreams)1919 TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) {
1920 session_deps_.host_resolver->set_synchronous_mode(true);
1921
1922 MockConnect connect_data(SYNCHRONOUS, OK);
1923
1924 // No actual data will be sent.
1925 MockWrite writes[] = {
1926 MockWrite(ASYNC, 0, 1) // EOF
1927 };
1928
1929 MockRead reads[] = {
1930 MockRead(ASYNC, 0, 0) // EOF
1931 };
1932 DeterministicSocketData data(reads, arraysize(reads),
1933 writes, arraysize(writes));
1934 data.set_connect_data(connect_data);
1935 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1936
1937 CreateDeterministicNetworkSession();
1938
1939 base::WeakPtr<SpdySession> session =
1940 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1941
1942 GURL url1(kDefaultURL);
1943 base::WeakPtr<SpdyStream> spdy_stream1 =
1944 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1945 session, url1, HIGHEST, BoundNetLog());
1946 ASSERT_TRUE(spdy_stream1.get() != NULL);
1947 EXPECT_EQ(0u, spdy_stream1->stream_id());
1948
1949 GURL url2(kDefaultURL);
1950 base::WeakPtr<SpdyStream> spdy_stream2 =
1951 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1952 session, url2, LOWEST, BoundNetLog());
1953 ASSERT_TRUE(spdy_stream2.get() != NULL);
1954 EXPECT_EQ(0u, spdy_stream2->stream_id());
1955
1956 test::ClosingDelegate delegate1(spdy_stream1);
1957 spdy_stream1->SetDelegate(&delegate1);
1958
1959 test::ClosingDelegate delegate2(spdy_stream2);
1960 spdy_stream2->SetDelegate(&delegate2);
1961
1962 scoped_ptr<SpdyHeaderBlock> headers(
1963 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
1964 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
1965 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
1966
1967 scoped_ptr<SpdyHeaderBlock> headers2(
1968 spdy_util_.ConstructGetHeaderBlock(url2.spec()));
1969 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
1970 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
1971
1972 // Ensure that the streams have not yet been activated and assigned an id.
1973 EXPECT_EQ(0u, spdy_stream1->stream_id());
1974 EXPECT_EQ(0u, spdy_stream2->stream_id());
1975
1976 // Ensure we don't crash while closing the session.
1977 session->CloseSessionOnError(ERR_ABORTED, std::string());
1978
1979 EXPECT_EQ(NULL, spdy_stream1.get());
1980 EXPECT_EQ(NULL, spdy_stream2.get());
1981
1982 EXPECT_TRUE(delegate1.StreamIsClosed());
1983 EXPECT_TRUE(delegate2.StreamIsClosed());
1984
1985 base::MessageLoop::current()->RunUntilIdle();
1986 EXPECT_TRUE(session == NULL);
1987 }
1988
1989 // Create two streams that are set to close each other on close, and
1990 // then close the session. Nothing should blow up.
TEST_P(SpdySessionTest,CloseSessionWithTwoCreatedMutuallyClosingStreams)1991 TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) {
1992 session_deps_.host_resolver->set_synchronous_mode(true);
1993
1994 MockConnect connect_data(SYNCHRONOUS, OK);
1995
1996 // No actual data will be sent.
1997 MockWrite writes[] = {
1998 MockWrite(ASYNC, 0, 1) // EOF
1999 };
2000
2001 MockRead reads[] = {
2002 MockRead(ASYNC, 0, 0) // EOF
2003 };
2004 DeterministicSocketData data(reads, arraysize(reads),
2005 writes, arraysize(writes));
2006 data.set_connect_data(connect_data);
2007 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2008
2009 CreateDeterministicNetworkSession();
2010
2011 base::WeakPtr<SpdySession> session =
2012 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2013
2014 GURL url1(kDefaultURL);
2015 base::WeakPtr<SpdyStream> spdy_stream1 =
2016 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
2017 session, url1, HIGHEST, BoundNetLog());
2018 ASSERT_TRUE(spdy_stream1.get() != NULL);
2019 EXPECT_EQ(0u, spdy_stream1->stream_id());
2020
2021 GURL url2(kDefaultURL);
2022 base::WeakPtr<SpdyStream> spdy_stream2 =
2023 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
2024 session, url2, LOWEST, BoundNetLog());
2025 ASSERT_TRUE(spdy_stream2.get() != NULL);
2026 EXPECT_EQ(0u, spdy_stream2->stream_id());
2027
2028 // Make |spdy_stream1| close |spdy_stream2|.
2029 test::ClosingDelegate delegate1(spdy_stream2);
2030 spdy_stream1->SetDelegate(&delegate1);
2031
2032 // Make |spdy_stream2| close |spdy_stream1|.
2033 test::ClosingDelegate delegate2(spdy_stream1);
2034 spdy_stream2->SetDelegate(&delegate2);
2035
2036 scoped_ptr<SpdyHeaderBlock> headers(
2037 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2038 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
2039 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2040
2041 scoped_ptr<SpdyHeaderBlock> headers2(
2042 spdy_util_.ConstructGetHeaderBlock(url2.spec()));
2043 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
2044 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
2045
2046 // Ensure that the streams have not yet been activated and assigned an id.
2047 EXPECT_EQ(0u, spdy_stream1->stream_id());
2048 EXPECT_EQ(0u, spdy_stream2->stream_id());
2049
2050 // Ensure we don't crash while closing the session.
2051 session->CloseSessionOnError(ERR_ABORTED, std::string());
2052
2053 EXPECT_EQ(NULL, spdy_stream1.get());
2054 EXPECT_EQ(NULL, spdy_stream2.get());
2055
2056 EXPECT_TRUE(delegate1.StreamIsClosed());
2057 EXPECT_TRUE(delegate2.StreamIsClosed());
2058
2059 base::MessageLoop::current()->RunUntilIdle();
2060 EXPECT_TRUE(session == NULL);
2061 }
2062
2063 // Create two streams that are set to re-close themselves on close,
2064 // activate them, and then close the session. Nothing should blow up.
TEST_P(SpdySessionTest,CloseSessionWithTwoActivatedSelfClosingStreams)2065 TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) {
2066 session_deps_.host_resolver->set_synchronous_mode(true);
2067
2068 MockConnect connect_data(SYNCHRONOUS, OK);
2069
2070 scoped_ptr<SpdyFrame> req1(
2071 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
2072 scoped_ptr<SpdyFrame> req2(
2073 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
2074 MockWrite writes[] = {
2075 CreateMockWrite(*req1, 0),
2076 CreateMockWrite(*req2, 1),
2077 };
2078
2079 MockRead reads[] = {
2080 MockRead(ASYNC, 0, 2) // EOF
2081 };
2082
2083 DeterministicSocketData data(reads, arraysize(reads),
2084 writes, arraysize(writes));
2085 data.set_connect_data(connect_data);
2086 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2087
2088 CreateDeterministicNetworkSession();
2089
2090 base::WeakPtr<SpdySession> session =
2091 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2092
2093 GURL url1(kDefaultURL);
2094 base::WeakPtr<SpdyStream> spdy_stream1 =
2095 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2096 session, url1, MEDIUM, BoundNetLog());
2097 ASSERT_TRUE(spdy_stream1.get() != NULL);
2098 EXPECT_EQ(0u, spdy_stream1->stream_id());
2099
2100 GURL url2(kDefaultURL);
2101 base::WeakPtr<SpdyStream> spdy_stream2 =
2102 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2103 session, url2, MEDIUM, BoundNetLog());
2104 ASSERT_TRUE(spdy_stream2.get() != NULL);
2105 EXPECT_EQ(0u, spdy_stream2->stream_id());
2106
2107 test::ClosingDelegate delegate1(spdy_stream1);
2108 spdy_stream1->SetDelegate(&delegate1);
2109
2110 test::ClosingDelegate delegate2(spdy_stream2);
2111 spdy_stream2->SetDelegate(&delegate2);
2112
2113 scoped_ptr<SpdyHeaderBlock> headers(
2114 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2115 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
2116 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2117
2118 scoped_ptr<SpdyHeaderBlock> headers2(
2119 spdy_util_.ConstructGetHeaderBlock(url2.spec()));
2120 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
2121 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
2122
2123 // Ensure that the streams have not yet been activated and assigned an id.
2124 EXPECT_EQ(0u, spdy_stream1->stream_id());
2125 EXPECT_EQ(0u, spdy_stream2->stream_id());
2126
2127 data.RunFor(2);
2128
2129 EXPECT_EQ(1u, spdy_stream1->stream_id());
2130 EXPECT_EQ(3u, spdy_stream2->stream_id());
2131
2132 // Ensure we don't crash while closing the session.
2133 session->CloseSessionOnError(ERR_ABORTED, std::string());
2134
2135 EXPECT_EQ(NULL, spdy_stream1.get());
2136 EXPECT_EQ(NULL, spdy_stream2.get());
2137
2138 EXPECT_TRUE(delegate1.StreamIsClosed());
2139 EXPECT_TRUE(delegate2.StreamIsClosed());
2140
2141 base::MessageLoop::current()->RunUntilIdle();
2142 EXPECT_TRUE(session == NULL);
2143 }
2144
2145 // Create two streams that are set to close each other on close,
2146 // activate them, and then close the session. Nothing should blow up.
TEST_P(SpdySessionTest,CloseSessionWithTwoActivatedMutuallyClosingStreams)2147 TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) {
2148 session_deps_.host_resolver->set_synchronous_mode(true);
2149
2150 MockConnect connect_data(SYNCHRONOUS, OK);
2151
2152 scoped_ptr<SpdyFrame> req1(
2153 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
2154 scoped_ptr<SpdyFrame> req2(
2155 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
2156 MockWrite writes[] = {
2157 CreateMockWrite(*req1, 0),
2158 CreateMockWrite(*req2, 1),
2159 };
2160
2161 MockRead reads[] = {
2162 MockRead(ASYNC, 0, 2) // EOF
2163 };
2164
2165 DeterministicSocketData data(reads, arraysize(reads),
2166 writes, arraysize(writes));
2167 data.set_connect_data(connect_data);
2168 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2169
2170 CreateDeterministicNetworkSession();
2171
2172 base::WeakPtr<SpdySession> session =
2173 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2174
2175 GURL url1(kDefaultURL);
2176 base::WeakPtr<SpdyStream> spdy_stream1 =
2177 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2178 session, url1, MEDIUM, BoundNetLog());
2179 ASSERT_TRUE(spdy_stream1.get() != NULL);
2180 EXPECT_EQ(0u, spdy_stream1->stream_id());
2181
2182 GURL url2(kDefaultURL);
2183 base::WeakPtr<SpdyStream> spdy_stream2 =
2184 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2185 session, url2, MEDIUM, BoundNetLog());
2186 ASSERT_TRUE(spdy_stream2.get() != NULL);
2187 EXPECT_EQ(0u, spdy_stream2->stream_id());
2188
2189 // Make |spdy_stream1| close |spdy_stream2|.
2190 test::ClosingDelegate delegate1(spdy_stream2);
2191 spdy_stream1->SetDelegate(&delegate1);
2192
2193 // Make |spdy_stream2| close |spdy_stream1|.
2194 test::ClosingDelegate delegate2(spdy_stream1);
2195 spdy_stream2->SetDelegate(&delegate2);
2196
2197 scoped_ptr<SpdyHeaderBlock> headers(
2198 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2199 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
2200 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2201
2202 scoped_ptr<SpdyHeaderBlock> headers2(
2203 spdy_util_.ConstructGetHeaderBlock(url2.spec()));
2204 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
2205 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
2206
2207 // Ensure that the streams have not yet been activated and assigned an id.
2208 EXPECT_EQ(0u, spdy_stream1->stream_id());
2209 EXPECT_EQ(0u, spdy_stream2->stream_id());
2210
2211 data.RunFor(2);
2212
2213 EXPECT_EQ(1u, spdy_stream1->stream_id());
2214 EXPECT_EQ(3u, spdy_stream2->stream_id());
2215
2216 // Ensure we don't crash while closing the session.
2217 session->CloseSessionOnError(ERR_ABORTED, std::string());
2218
2219 EXPECT_EQ(NULL, spdy_stream1.get());
2220 EXPECT_EQ(NULL, spdy_stream2.get());
2221
2222 EXPECT_TRUE(delegate1.StreamIsClosed());
2223 EXPECT_TRUE(delegate2.StreamIsClosed());
2224
2225 base::MessageLoop::current()->RunUntilIdle();
2226 EXPECT_TRUE(session == NULL);
2227 }
2228
2229 // Delegate that closes a given session when the stream is closed.
2230 class SessionClosingDelegate : public test::StreamDelegateDoNothing {
2231 public:
SessionClosingDelegate(const base::WeakPtr<SpdyStream> & stream,const base::WeakPtr<SpdySession> & session_to_close)2232 SessionClosingDelegate(const base::WeakPtr<SpdyStream>& stream,
2233 const base::WeakPtr<SpdySession>& session_to_close)
2234 : StreamDelegateDoNothing(stream),
2235 session_to_close_(session_to_close) {}
2236
~SessionClosingDelegate()2237 virtual ~SessionClosingDelegate() {}
2238
OnClose(int status)2239 virtual void OnClose(int status) OVERRIDE {
2240 session_to_close_->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Error");
2241 }
2242
2243 private:
2244 base::WeakPtr<SpdySession> session_to_close_;
2245 };
2246
2247 // Close an activated stream that closes its session. Nothing should
2248 // blow up. This is a regression test for http://crbug.com/263691 .
TEST_P(SpdySessionTest,CloseActivatedStreamThatClosesSession)2249 TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) {
2250 session_deps_.host_resolver->set_synchronous_mode(true);
2251
2252 MockConnect connect_data(SYNCHRONOUS, OK);
2253
2254 scoped_ptr<SpdyFrame> req(
2255 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
2256 scoped_ptr<SpdyFrame> rst(
2257 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
2258 scoped_ptr<SpdyFrame> goaway(
2259 spdy_util_.ConstructSpdyGoAway(0, GOAWAY_PROTOCOL_ERROR, "Error"));
2260 // The GOAWAY has higher-priority than the RST_STREAM, and is written first
2261 // despite being queued second.
2262 MockWrite writes[] = {
2263 CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 1),
2264 CreateMockWrite(*rst, 2),
2265 };
2266
2267 MockRead reads[] = {
2268 MockRead(ASYNC, 0, 3) // EOF
2269 };
2270 DeterministicSocketData data(reads, arraysize(reads),
2271 writes, arraysize(writes));
2272 data.set_connect_data(connect_data);
2273 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2274
2275 CreateDeterministicNetworkSession();
2276
2277 base::WeakPtr<SpdySession> session =
2278 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2279
2280 GURL url(kDefaultURL);
2281 base::WeakPtr<SpdyStream> spdy_stream =
2282 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2283 session, url, MEDIUM, BoundNetLog());
2284 ASSERT_TRUE(spdy_stream.get() != NULL);
2285 EXPECT_EQ(0u, spdy_stream->stream_id());
2286
2287 SessionClosingDelegate delegate(spdy_stream, session);
2288 spdy_stream->SetDelegate(&delegate);
2289
2290 scoped_ptr<SpdyHeaderBlock> headers(
2291 spdy_util_.ConstructGetHeaderBlock(url.spec()));
2292 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
2293 EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
2294
2295 EXPECT_EQ(0u, spdy_stream->stream_id());
2296
2297 data.RunFor(1);
2298
2299 EXPECT_EQ(1u, spdy_stream->stream_id());
2300
2301 // Ensure we don't crash while closing the stream (which closes the
2302 // session).
2303 spdy_stream->Cancel();
2304
2305 EXPECT_EQ(NULL, spdy_stream.get());
2306 EXPECT_TRUE(delegate.StreamIsClosed());
2307
2308 data.RunFor(2); // Write the RST_STREAM & GOAWAY.
2309 base::MessageLoop::current()->RunUntilIdle();
2310 EXPECT_TRUE(session == NULL);
2311 }
2312
TEST_P(SpdySessionTest,DISABLED_VerifyDomainAuthentication)2313 TEST_P(SpdySessionTest, DISABLED_VerifyDomainAuthentication) {
2314 session_deps_.host_resolver->set_synchronous_mode(true);
2315
2316 MockConnect connect_data(SYNCHRONOUS, OK);
2317
2318 // No actual data will be sent.
2319 MockWrite writes[] = {
2320 MockWrite(ASYNC, 0, 1) // EOF
2321 };
2322
2323 MockRead reads[] = {
2324 MockRead(ASYNC, 0, 0) // EOF
2325 };
2326 DeterministicSocketData data(reads, arraysize(reads),
2327 writes, arraysize(writes));
2328 data.set_connect_data(connect_data);
2329 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2330
2331 // Load a cert that is valid for:
2332 // www.example.org
2333 // mail.example.org
2334 // www.example.com
2335 base::FilePath certs_dir = GetTestCertsDirectory();
2336 scoped_refptr<X509Certificate> test_cert(
2337 ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
2338 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
2339
2340 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
2341 ssl.cert = test_cert;
2342 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
2343
2344 CreateDeterministicNetworkSession();
2345
2346 base::WeakPtr<SpdySession> session =
2347 CreateSecureSpdySession(http_session_, key_, BoundNetLog());
2348
2349 EXPECT_TRUE(session->VerifyDomainAuthentication("www.example.org"));
2350 EXPECT_TRUE(session->VerifyDomainAuthentication("mail.example.org"));
2351 EXPECT_TRUE(session->VerifyDomainAuthentication("mail.example.com"));
2352 EXPECT_FALSE(session->VerifyDomainAuthentication("mail.google.com"));
2353 }
2354
2355 // TODO(rch): re-enable this.
TEST_P(SpdySessionTest,DISABLED_ConnectionPooledWithTlsChannelId)2356 TEST_P(SpdySessionTest, DISABLED_ConnectionPooledWithTlsChannelId) {
2357 session_deps_.host_resolver->set_synchronous_mode(true);
2358
2359 MockConnect connect_data(SYNCHRONOUS, OK);
2360
2361 // No actual data will be sent.
2362 MockWrite writes[] = {
2363 MockWrite(ASYNC, 0, 1) // EOF
2364 };
2365
2366 MockRead reads[] = {
2367 MockRead(ASYNC, 0, 0) // EOF
2368 };
2369 DeterministicSocketData data(reads, arraysize(reads),
2370 writes, arraysize(writes));
2371 data.set_connect_data(connect_data);
2372 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2373
2374 // Load a cert that is valid for:
2375 // www.example.org
2376 // mail.example.org
2377 // www.example.com
2378 base::FilePath certs_dir = GetTestCertsDirectory();
2379 scoped_refptr<X509Certificate> test_cert(
2380 ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
2381 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
2382
2383 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
2384 ssl.channel_id_sent = true;
2385 ssl.cert = test_cert;
2386 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
2387
2388 CreateDeterministicNetworkSession();
2389
2390 base::WeakPtr<SpdySession> session =
2391 CreateSecureSpdySession(http_session_, key_, BoundNetLog());
2392
2393 EXPECT_TRUE(session->VerifyDomainAuthentication("www.example.org"));
2394 EXPECT_TRUE(session->VerifyDomainAuthentication("mail.example.org"));
2395 EXPECT_FALSE(session->VerifyDomainAuthentication("mail.example.com"));
2396 EXPECT_FALSE(session->VerifyDomainAuthentication("mail.google.com"));
2397 }
2398
TEST_P(SpdySessionTest,CloseTwoStalledCreateStream)2399 TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) {
2400 // TODO(rtenneti): Define a helper class/methods and move the common code in
2401 // this file.
2402 MockConnect connect_data(SYNCHRONOUS, OK);
2403
2404 SettingsMap new_settings;
2405 const SpdySettingsIds kSpdySettingsIds1 = SETTINGS_MAX_CONCURRENT_STREAMS;
2406 const uint32 max_concurrent_streams = 1;
2407 new_settings[kSpdySettingsIds1] =
2408 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
2409
2410 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
2411 scoped_ptr<SpdyFrame> req1(
2412 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2413 scoped_ptr<SpdyFrame> req2(
2414 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
2415 scoped_ptr<SpdyFrame> req3(
2416 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true));
2417 MockWrite writes[] = {
2418 CreateMockWrite(*settings_ack, 1),
2419 CreateMockWrite(*req1, 2),
2420 CreateMockWrite(*req2, 5),
2421 CreateMockWrite(*req3, 8),
2422 };
2423
2424 // Set up the socket so we read a SETTINGS frame that sets max concurrent
2425 // streams to 1.
2426 scoped_ptr<SpdyFrame> settings_frame(
2427 spdy_util_.ConstructSpdySettings(new_settings));
2428
2429 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2430 scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true));
2431
2432 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
2433 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, true));
2434
2435 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
2436 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, true));
2437
2438 MockRead reads[] = {
2439 CreateMockRead(*settings_frame),
2440 CreateMockRead(*resp1, 3),
2441 CreateMockRead(*body1, 4),
2442 CreateMockRead(*resp2, 6),
2443 CreateMockRead(*body2, 7),
2444 CreateMockRead(*resp3, 9),
2445 CreateMockRead(*body3, 10),
2446 MockRead(ASYNC, 0, 11) // EOF
2447 };
2448
2449 DeterministicSocketData data(reads, arraysize(reads),
2450 writes, arraysize(writes));
2451 data.set_connect_data(connect_data);
2452 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2453
2454 CreateDeterministicNetworkSession();
2455
2456 base::WeakPtr<SpdySession> session =
2457 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2458
2459 // Read the settings frame.
2460 data.RunFor(1);
2461
2462 GURL url1(kDefaultURL);
2463 base::WeakPtr<SpdyStream> spdy_stream1 =
2464 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2465 session, url1, LOWEST, BoundNetLog());
2466 ASSERT_TRUE(spdy_stream1.get() != NULL);
2467 EXPECT_EQ(0u, spdy_stream1->stream_id());
2468 test::StreamDelegateDoNothing delegate1(spdy_stream1);
2469 spdy_stream1->SetDelegate(&delegate1);
2470
2471 TestCompletionCallback callback2;
2472 GURL url2(kDefaultURL);
2473 SpdyStreamRequest request2;
2474 ASSERT_EQ(ERR_IO_PENDING,
2475 request2.StartRequest(
2476 SPDY_REQUEST_RESPONSE_STREAM,
2477 session, url2, LOWEST, BoundNetLog(), callback2.callback()));
2478
2479 TestCompletionCallback callback3;
2480 GURL url3(kDefaultURL);
2481 SpdyStreamRequest request3;
2482 ASSERT_EQ(ERR_IO_PENDING,
2483 request3.StartRequest(
2484 SPDY_REQUEST_RESPONSE_STREAM,
2485 session, url3, LOWEST, BoundNetLog(), callback3.callback()));
2486
2487 EXPECT_EQ(0u, session->num_active_streams());
2488 EXPECT_EQ(1u, session->num_created_streams());
2489 EXPECT_EQ(2u, session->pending_create_stream_queue_size(LOWEST));
2490
2491 scoped_ptr<SpdyHeaderBlock> headers(
2492 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2493 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
2494 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2495
2496 // Run until 1st stream is activated and then closed.
2497 EXPECT_EQ(0u, delegate1.stream_id());
2498 data.RunFor(4);
2499 EXPECT_EQ(NULL, spdy_stream1.get());
2500 EXPECT_EQ(1u, delegate1.stream_id());
2501
2502 EXPECT_EQ(0u, session->num_active_streams());
2503 EXPECT_EQ(0u, session->num_created_streams());
2504 EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST));
2505
2506 // Pump loop for SpdySession::ProcessPendingStreamRequests() to
2507 // create the 2nd stream.
2508 base::MessageLoop::current()->RunUntilIdle();
2509
2510 EXPECT_EQ(0u, session->num_active_streams());
2511 EXPECT_EQ(1u, session->num_created_streams());
2512 EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST));
2513
2514 base::WeakPtr<SpdyStream> stream2 = request2.ReleaseStream();
2515 test::StreamDelegateDoNothing delegate2(stream2);
2516 stream2->SetDelegate(&delegate2);
2517 scoped_ptr<SpdyHeaderBlock> headers2(
2518 spdy_util_.ConstructGetHeaderBlock(url2.spec()));
2519 stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
2520 EXPECT_TRUE(stream2->HasUrlFromHeaders());
2521
2522 // Run until 2nd stream is activated and then closed.
2523 EXPECT_EQ(0u, delegate2.stream_id());
2524 data.RunFor(3);
2525 EXPECT_EQ(NULL, stream2.get());
2526 EXPECT_EQ(3u, delegate2.stream_id());
2527
2528 EXPECT_EQ(0u, session->num_active_streams());
2529 EXPECT_EQ(0u, session->num_created_streams());
2530 EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
2531
2532 // Pump loop for SpdySession::ProcessPendingStreamRequests() to
2533 // create the 3rd stream.
2534 base::MessageLoop::current()->RunUntilIdle();
2535
2536 EXPECT_EQ(0u, session->num_active_streams());
2537 EXPECT_EQ(1u, session->num_created_streams());
2538 EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
2539
2540 base::WeakPtr<SpdyStream> stream3 = request3.ReleaseStream();
2541 test::StreamDelegateDoNothing delegate3(stream3);
2542 stream3->SetDelegate(&delegate3);
2543 scoped_ptr<SpdyHeaderBlock> headers3(
2544 spdy_util_.ConstructGetHeaderBlock(url3.spec()));
2545 stream3->SendRequestHeaders(headers3.Pass(), NO_MORE_DATA_TO_SEND);
2546 EXPECT_TRUE(stream3->HasUrlFromHeaders());
2547
2548 // Run until 2nd stream is activated and then closed.
2549 EXPECT_EQ(0u, delegate3.stream_id());
2550 data.RunFor(3);
2551 EXPECT_EQ(NULL, stream3.get());
2552 EXPECT_EQ(5u, delegate3.stream_id());
2553
2554 EXPECT_EQ(0u, session->num_active_streams());
2555 EXPECT_EQ(0u, session->num_created_streams());
2556 EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
2557
2558 data.RunFor(1);
2559 }
2560
TEST_P(SpdySessionTest,CancelTwoStalledCreateStream)2561 TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) {
2562 session_deps_.host_resolver->set_synchronous_mode(true);
2563
2564 MockRead reads[] = {
2565 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
2566 };
2567
2568 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
2569 MockConnect connect_data(SYNCHRONOUS, OK);
2570
2571 data.set_connect_data(connect_data);
2572 session_deps_.socket_factory->AddSocketDataProvider(&data);
2573
2574 CreateNetworkSession();
2575
2576 base::WeakPtr<SpdySession> session =
2577 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2578
2579 // Leave room for only one more stream to be created.
2580 for (size_t i = 0; i < kInitialMaxConcurrentStreams - 1; ++i) {
2581 base::WeakPtr<SpdyStream> spdy_stream =
2582 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
2583 session, test_url_, MEDIUM, BoundNetLog());
2584 ASSERT_TRUE(spdy_stream != NULL);
2585 }
2586
2587 GURL url1(kDefaultURL);
2588 base::WeakPtr<SpdyStream> spdy_stream1 =
2589 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
2590 session, url1, LOWEST, BoundNetLog());
2591 ASSERT_TRUE(spdy_stream1.get() != NULL);
2592 EXPECT_EQ(0u, spdy_stream1->stream_id());
2593
2594 TestCompletionCallback callback2;
2595 GURL url2(kDefaultURL);
2596 SpdyStreamRequest request2;
2597 ASSERT_EQ(ERR_IO_PENDING,
2598 request2.StartRequest(
2599 SPDY_BIDIRECTIONAL_STREAM, session, url2, LOWEST, BoundNetLog(),
2600 callback2.callback()));
2601
2602 TestCompletionCallback callback3;
2603 GURL url3(kDefaultURL);
2604 SpdyStreamRequest request3;
2605 ASSERT_EQ(ERR_IO_PENDING,
2606 request3.StartRequest(
2607 SPDY_BIDIRECTIONAL_STREAM, session, url3, LOWEST, BoundNetLog(),
2608 callback3.callback()));
2609
2610 EXPECT_EQ(0u, session->num_active_streams());
2611 EXPECT_EQ(kInitialMaxConcurrentStreams, session->num_created_streams());
2612 EXPECT_EQ(2u, session->pending_create_stream_queue_size(LOWEST));
2613
2614 // Cancel the first stream; this will allow the second stream to be created.
2615 EXPECT_TRUE(spdy_stream1.get() != NULL);
2616 spdy_stream1->Cancel();
2617 EXPECT_EQ(NULL, spdy_stream1.get());
2618
2619 EXPECT_EQ(OK, callback2.WaitForResult());
2620 EXPECT_EQ(0u, session->num_active_streams());
2621 EXPECT_EQ(kInitialMaxConcurrentStreams, session->num_created_streams());
2622 EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST));
2623
2624 // Cancel the second stream; this will allow the third stream to be created.
2625 base::WeakPtr<SpdyStream> spdy_stream2 = request2.ReleaseStream();
2626 spdy_stream2->Cancel();
2627 EXPECT_EQ(NULL, spdy_stream2.get());
2628
2629 EXPECT_EQ(OK, callback3.WaitForResult());
2630 EXPECT_EQ(0u, session->num_active_streams());
2631 EXPECT_EQ(kInitialMaxConcurrentStreams, session->num_created_streams());
2632 EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
2633
2634 // Cancel the third stream.
2635 base::WeakPtr<SpdyStream> spdy_stream3 = request3.ReleaseStream();
2636 spdy_stream3->Cancel();
2637 EXPECT_EQ(NULL, spdy_stream3.get());
2638 EXPECT_EQ(0u, session->num_active_streams());
2639 EXPECT_EQ(kInitialMaxConcurrentStreams - 1, session->num_created_streams());
2640 EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
2641 }
2642
2643 // Test that SpdySession::DoReadLoop reads data from the socket
2644 // without yielding. This test makes 32k - 1 bytes of data available
2645 // on the socket for reading. It then verifies that it has read all
2646 // the available data without yielding.
TEST_P(SpdySessionTest,ReadDataWithoutYielding)2647 TEST_P(SpdySessionTest, ReadDataWithoutYielding) {
2648 MockConnect connect_data(SYNCHRONOUS, OK);
2649 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
2650
2651 scoped_ptr<SpdyFrame> req1(
2652 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
2653 MockWrite writes[] = {
2654 CreateMockWrite(*req1, 0),
2655 };
2656
2657 // Build buffer of size kMaxReadBytesWithoutYielding / 4
2658 // (-spdy_data_frame_size).
2659 ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding);
2660 const int kPayloadSize =
2661 kMaxReadBytesWithoutYielding / 4 - framer.GetControlFrameHeaderSize();
2662 TestDataStream test_stream;
2663 scoped_refptr<net::IOBuffer> payload(new net::IOBuffer(kPayloadSize));
2664 char* payload_data = payload->data();
2665 test_stream.GetBytes(payload_data, kPayloadSize);
2666
2667 scoped_ptr<SpdyFrame> partial_data_frame(
2668 framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_NONE));
2669 scoped_ptr<SpdyFrame> finish_data_frame(
2670 framer.CreateDataFrame(1, payload_data, kPayloadSize - 1, DATA_FLAG_FIN));
2671
2672 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2673
2674 // Write 1 byte less than kMaxReadBytes to check that DoRead reads up to 32k
2675 // bytes.
2676 MockRead reads[] = {
2677 CreateMockRead(*resp1, 1),
2678 CreateMockRead(*partial_data_frame, 2),
2679 CreateMockRead(*partial_data_frame, 3, SYNCHRONOUS),
2680 CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
2681 CreateMockRead(*finish_data_frame, 5, SYNCHRONOUS),
2682 MockRead(ASYNC, 0, 6) // EOF
2683 };
2684
2685 // Create SpdySession and SpdyStream and send the request.
2686 DeterministicSocketData data(reads, arraysize(reads),
2687 writes, arraysize(writes));
2688 data.set_connect_data(connect_data);
2689 session_deps_.host_resolver->set_synchronous_mode(true);
2690 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2691
2692 CreateDeterministicNetworkSession();
2693
2694 base::WeakPtr<SpdySession> session =
2695 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2696
2697 GURL url1(kDefaultURL);
2698 base::WeakPtr<SpdyStream> spdy_stream1 =
2699 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2700 session, url1, MEDIUM, BoundNetLog());
2701 ASSERT_TRUE(spdy_stream1.get() != NULL);
2702 EXPECT_EQ(0u, spdy_stream1->stream_id());
2703 test::StreamDelegateDoNothing delegate1(spdy_stream1);
2704 spdy_stream1->SetDelegate(&delegate1);
2705
2706 scoped_ptr<SpdyHeaderBlock> headers1(
2707 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2708 spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND);
2709 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2710
2711 // Set up the TaskObserver to verify SpdySession::DoReadLoop doesn't
2712 // post a task.
2713 SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop");
2714
2715 // Run until 1st read.
2716 EXPECT_EQ(0u, delegate1.stream_id());
2717 data.RunFor(2);
2718 EXPECT_EQ(1u, delegate1.stream_id());
2719 EXPECT_EQ(0u, observer.executed_count());
2720
2721 // Read all the data and verify SpdySession::DoReadLoop has not
2722 // posted a task.
2723 data.RunFor(4);
2724 EXPECT_EQ(NULL, spdy_stream1.get());
2725
2726 // Verify task observer's executed_count is zero, which indicates DoRead read
2727 // all the available data.
2728 EXPECT_EQ(0u, observer.executed_count());
2729 EXPECT_TRUE(data.at_write_eof());
2730 EXPECT_TRUE(data.at_read_eof());
2731 }
2732
2733 // Test that SpdySession::DoReadLoop yields while reading the
2734 // data. This test makes 32k + 1 bytes of data available on the socket
2735 // for reading. It then verifies that DoRead has yielded even though
2736 // there is data available for it to read (i.e, socket()->Read didn't
2737 // return ERR_IO_PENDING during socket reads).
TEST_P(SpdySessionTest,TestYieldingDuringReadData)2738 TEST_P(SpdySessionTest, TestYieldingDuringReadData) {
2739 MockConnect connect_data(SYNCHRONOUS, OK);
2740 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
2741
2742 scoped_ptr<SpdyFrame> req1(
2743 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
2744 MockWrite writes[] = {
2745 CreateMockWrite(*req1, 0),
2746 };
2747
2748 // Build buffer of size kMaxReadBytesWithoutYielding / 4
2749 // (-spdy_data_frame_size).
2750 ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding);
2751 const int kPayloadSize =
2752 kMaxReadBytesWithoutYielding / 4 - framer.GetControlFrameHeaderSize();
2753 TestDataStream test_stream;
2754 scoped_refptr<net::IOBuffer> payload(new net::IOBuffer(kPayloadSize));
2755 char* payload_data = payload->data();
2756 test_stream.GetBytes(payload_data, kPayloadSize);
2757
2758 scoped_ptr<SpdyFrame> partial_data_frame(
2759 framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_NONE));
2760 scoped_ptr<SpdyFrame> finish_data_frame(
2761 framer.CreateDataFrame(1, "h", 1, DATA_FLAG_FIN));
2762
2763 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2764
2765 // Write 1 byte more than kMaxReadBytes to check that DoRead yields.
2766 MockRead reads[] = {
2767 CreateMockRead(*resp1, 1),
2768 CreateMockRead(*partial_data_frame, 2),
2769 CreateMockRead(*partial_data_frame, 3, SYNCHRONOUS),
2770 CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
2771 CreateMockRead(*partial_data_frame, 5, SYNCHRONOUS),
2772 CreateMockRead(*finish_data_frame, 6, SYNCHRONOUS),
2773 MockRead(ASYNC, 0, 7) // EOF
2774 };
2775
2776 // Create SpdySession and SpdyStream and send the request.
2777 DeterministicSocketData data(reads, arraysize(reads),
2778 writes, arraysize(writes));
2779 data.set_connect_data(connect_data);
2780 session_deps_.host_resolver->set_synchronous_mode(true);
2781 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2782
2783 CreateDeterministicNetworkSession();
2784
2785 base::WeakPtr<SpdySession> session =
2786 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2787
2788 GURL url1(kDefaultURL);
2789 base::WeakPtr<SpdyStream> spdy_stream1 =
2790 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2791 session, url1, MEDIUM, BoundNetLog());
2792 ASSERT_TRUE(spdy_stream1.get() != NULL);
2793 EXPECT_EQ(0u, spdy_stream1->stream_id());
2794 test::StreamDelegateDoNothing delegate1(spdy_stream1);
2795 spdy_stream1->SetDelegate(&delegate1);
2796
2797 scoped_ptr<SpdyHeaderBlock> headers1(
2798 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2799 spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND);
2800 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2801
2802 // Set up the TaskObserver to verify SpdySession::DoReadLoop posts a
2803 // task.
2804 SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop");
2805
2806 // Run until 1st read.
2807 EXPECT_EQ(0u, delegate1.stream_id());
2808 data.RunFor(2);
2809 EXPECT_EQ(1u, delegate1.stream_id());
2810 EXPECT_EQ(0u, observer.executed_count());
2811
2812 // Read all the data and verify SpdySession::DoReadLoop has posted a
2813 // task.
2814 data.RunFor(6);
2815 EXPECT_EQ(NULL, spdy_stream1.get());
2816
2817 // Verify task observer's executed_count is 1, which indicates DoRead has
2818 // posted only one task and thus yielded though there is data available for it
2819 // to read.
2820 EXPECT_EQ(1u, observer.executed_count());
2821 EXPECT_TRUE(data.at_write_eof());
2822 EXPECT_TRUE(data.at_read_eof());
2823 }
2824
2825 // Test that SpdySession::DoReadLoop() tests interactions of yielding
2826 // + async, by doing the following MockReads.
2827 //
2828 // MockRead of SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K
2829 // ASYNC 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K.
2830 //
2831 // The above reads 26K synchronously. Since that is less that 32K, we
2832 // will attempt to read again. However, that DoRead() will return
2833 // ERR_IO_PENDING (because of async read), so DoReadLoop() will
2834 // yield. When we come back, DoRead() will read the results from the
2835 // async read, and rest of the data synchronously.
TEST_P(SpdySessionTest,TestYieldingDuringAsyncReadData)2836 TEST_P(SpdySessionTest, TestYieldingDuringAsyncReadData) {
2837 MockConnect connect_data(SYNCHRONOUS, OK);
2838 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
2839
2840 scoped_ptr<SpdyFrame> req1(
2841 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
2842 MockWrite writes[] = {
2843 CreateMockWrite(*req1, 0),
2844 };
2845
2846 // Build buffer of size kMaxReadBytesWithoutYielding / 4
2847 // (-spdy_data_frame_size).
2848 ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding);
2849 TestDataStream test_stream;
2850 const int kEightKPayloadSize =
2851 kMaxReadBytesWithoutYielding / 4 - framer.GetControlFrameHeaderSize();
2852 scoped_refptr<net::IOBuffer> eightk_payload(
2853 new net::IOBuffer(kEightKPayloadSize));
2854 char* eightk_payload_data = eightk_payload->data();
2855 test_stream.GetBytes(eightk_payload_data, kEightKPayloadSize);
2856
2857 // Build buffer of 2k size.
2858 TestDataStream test_stream2;
2859 const int kTwoKPayloadSize = kEightKPayloadSize - 6 * 1024;
2860 scoped_refptr<net::IOBuffer> twok_payload(
2861 new net::IOBuffer(kTwoKPayloadSize));
2862 char* twok_payload_data = twok_payload->data();
2863 test_stream2.GetBytes(twok_payload_data, kTwoKPayloadSize);
2864
2865 scoped_ptr<SpdyFrame> eightk_data_frame(framer.CreateDataFrame(
2866 1, eightk_payload_data, kEightKPayloadSize, DATA_FLAG_NONE));
2867 scoped_ptr<SpdyFrame> twok_data_frame(framer.CreateDataFrame(
2868 1, twok_payload_data, kTwoKPayloadSize, DATA_FLAG_NONE));
2869 scoped_ptr<SpdyFrame> finish_data_frame(framer.CreateDataFrame(
2870 1, "h", 1, DATA_FLAG_FIN));
2871
2872 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2873
2874 MockRead reads[] = {
2875 CreateMockRead(*resp1, 1),
2876 CreateMockRead(*eightk_data_frame, 2),
2877 CreateMockRead(*eightk_data_frame, 3, SYNCHRONOUS),
2878 CreateMockRead(*eightk_data_frame, 4, SYNCHRONOUS),
2879 CreateMockRead(*twok_data_frame, 5, SYNCHRONOUS),
2880 CreateMockRead(*eightk_data_frame, 6, ASYNC),
2881 CreateMockRead(*eightk_data_frame, 7, SYNCHRONOUS),
2882 CreateMockRead(*eightk_data_frame, 8, SYNCHRONOUS),
2883 CreateMockRead(*eightk_data_frame, 9, SYNCHRONOUS),
2884 CreateMockRead(*twok_data_frame, 10, SYNCHRONOUS),
2885 CreateMockRead(*finish_data_frame, 11, SYNCHRONOUS),
2886 MockRead(ASYNC, 0, 12) // EOF
2887 };
2888
2889 // Create SpdySession and SpdyStream and send the request.
2890 DeterministicSocketData data(reads, arraysize(reads),
2891 writes, arraysize(writes));
2892 data.set_connect_data(connect_data);
2893 session_deps_.host_resolver->set_synchronous_mode(true);
2894 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2895
2896 CreateDeterministicNetworkSession();
2897
2898 base::WeakPtr<SpdySession> session =
2899 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2900
2901 GURL url1(kDefaultURL);
2902 base::WeakPtr<SpdyStream> spdy_stream1 =
2903 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2904 session, url1, MEDIUM, BoundNetLog());
2905 ASSERT_TRUE(spdy_stream1.get() != NULL);
2906 EXPECT_EQ(0u, spdy_stream1->stream_id());
2907 test::StreamDelegateDoNothing delegate1(spdy_stream1);
2908 spdy_stream1->SetDelegate(&delegate1);
2909
2910 scoped_ptr<SpdyHeaderBlock> headers1(
2911 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2912 spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND);
2913 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2914
2915 // Set up the TaskObserver to monitor SpdySession::DoReadLoop
2916 // posting of tasks.
2917 SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop");
2918
2919 // Run until 1st read.
2920 EXPECT_EQ(0u, delegate1.stream_id());
2921 data.RunFor(2);
2922 EXPECT_EQ(1u, delegate1.stream_id());
2923 EXPECT_EQ(0u, observer.executed_count());
2924
2925 // Read all the data and verify SpdySession::DoReadLoop has posted a
2926 // task.
2927 data.RunFor(12);
2928 EXPECT_EQ(NULL, spdy_stream1.get());
2929
2930 // Verify task observer's executed_count is 1, which indicates DoRead has
2931 // posted only one task and thus yielded though there is data available for
2932 // it to read.
2933 EXPECT_EQ(1u, observer.executed_count());
2934 EXPECT_TRUE(data.at_write_eof());
2935 EXPECT_TRUE(data.at_read_eof());
2936 }
2937
2938 // Send a GoAway frame when SpdySession is in DoReadLoop. Make sure
2939 // nothing blows up.
TEST_P(SpdySessionTest,GoAwayWhileInDoReadLoop)2940 TEST_P(SpdySessionTest, GoAwayWhileInDoReadLoop) {
2941 MockConnect connect_data(SYNCHRONOUS, OK);
2942 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
2943
2944 scoped_ptr<SpdyFrame> req1(
2945 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
2946 MockWrite writes[] = {
2947 CreateMockWrite(*req1, 0),
2948 };
2949
2950 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2951 scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true));
2952 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway());
2953
2954 MockRead reads[] = {
2955 CreateMockRead(*resp1, 1),
2956 CreateMockRead(*body1, 2),
2957 CreateMockRead(*goaway, 3),
2958 };
2959
2960 // Create SpdySession and SpdyStream and send the request.
2961 DeterministicSocketData data(reads, arraysize(reads),
2962 writes, arraysize(writes));
2963 data.set_connect_data(connect_data);
2964 session_deps_.host_resolver->set_synchronous_mode(true);
2965 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2966
2967 CreateDeterministicNetworkSession();
2968
2969 base::WeakPtr<SpdySession> session =
2970 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2971
2972 GURL url1(kDefaultURL);
2973 base::WeakPtr<SpdyStream> spdy_stream1 =
2974 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2975 session, url1, MEDIUM, BoundNetLog());
2976 test::StreamDelegateDoNothing delegate1(spdy_stream1);
2977 spdy_stream1->SetDelegate(&delegate1);
2978 ASSERT_TRUE(spdy_stream1.get() != NULL);
2979 EXPECT_EQ(0u, spdy_stream1->stream_id());
2980
2981 scoped_ptr<SpdyHeaderBlock> headers1(
2982 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2983 spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND);
2984 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2985
2986 // Run until 1st read.
2987 EXPECT_EQ(0u, spdy_stream1->stream_id());
2988 data.RunFor(1);
2989 EXPECT_EQ(1u, spdy_stream1->stream_id());
2990
2991 // Run until GoAway.
2992 data.RunFor(3);
2993 EXPECT_EQ(NULL, spdy_stream1.get());
2994 EXPECT_TRUE(data.at_write_eof());
2995 EXPECT_TRUE(data.at_read_eof());
2996 EXPECT_TRUE(session == NULL);
2997 }
2998
2999 // Within this framework, a SpdySession should be initialized with
3000 // flow control disabled for protocol version 2, with flow control
3001 // enabled only for streams for protocol version 3, and with flow
3002 // control enabled for streams and sessions for higher versions.
TEST_P(SpdySessionTest,ProtocolNegotiation)3003 TEST_P(SpdySessionTest, ProtocolNegotiation) {
3004 session_deps_.host_resolver->set_synchronous_mode(true);
3005
3006 MockConnect connect_data(SYNCHRONOUS, OK);
3007 MockRead reads[] = {
3008 MockRead(SYNCHRONOUS, 0, 0) // EOF
3009 };
3010 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
3011 data.set_connect_data(connect_data);
3012 session_deps_.socket_factory->AddSocketDataProvider(&data);
3013
3014 CreateNetworkSession();
3015 base::WeakPtr<SpdySession> session =
3016 CreateFakeSpdySession(spdy_session_pool_, key_);
3017
3018 EXPECT_EQ(spdy_util_.spdy_version(),
3019 session->buffered_spdy_framer_->protocol_version());
3020 if (GetParam() == kProtoDeprecatedSPDY2) {
3021 EXPECT_EQ(SpdySession::FLOW_CONTROL_NONE, session->flow_control_state());
3022 EXPECT_EQ(0, session->session_send_window_size_);
3023 EXPECT_EQ(0, session->session_recv_window_size_);
3024 } else if (GetParam() == kProtoSPDY3) {
3025 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM, session->flow_control_state());
3026 EXPECT_EQ(0, session->session_send_window_size_);
3027 EXPECT_EQ(0, session->session_recv_window_size_);
3028 } else {
3029 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
3030 session->flow_control_state());
3031 EXPECT_EQ(kSpdySessionInitialWindowSize,
3032 session->session_send_window_size_);
3033 EXPECT_EQ(kSpdySessionInitialWindowSize,
3034 session->session_recv_window_size_);
3035 }
3036 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3037 }
3038
3039 // Tests the case of a non-SPDY request closing an idle SPDY session when no
3040 // pointers to the idle session are currently held.
TEST_P(SpdySessionTest,CloseOneIdleConnection)3041 TEST_P(SpdySessionTest, CloseOneIdleConnection) {
3042 ClientSocketPoolManager::set_max_sockets_per_group(
3043 HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
3044 ClientSocketPoolManager::set_max_sockets_per_pool(
3045 HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
3046
3047 MockConnect connect_data(SYNCHRONOUS, OK);
3048 MockRead reads[] = {
3049 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
3050 };
3051 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
3052 data.set_connect_data(connect_data);
3053 session_deps_.socket_factory->AddSocketDataProvider(&data);
3054 session_deps_.socket_factory->AddSocketDataProvider(&data);
3055
3056 CreateNetworkSession();
3057
3058 TransportClientSocketPool* pool =
3059 http_session_->GetTransportSocketPool(
3060 HttpNetworkSession::NORMAL_SOCKET_POOL);
3061
3062 // Create an idle SPDY session.
3063 SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(),
3064 PRIVACY_MODE_DISABLED);
3065 base::WeakPtr<SpdySession> session1 =
3066 CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
3067 EXPECT_FALSE(pool->IsStalled());
3068
3069 // Trying to create a new connection should cause the pool to be stalled, and
3070 // post a task asynchronously to try and close the session.
3071 TestCompletionCallback callback2;
3072 HostPortPair host_port2("2.com", 80);
3073 scoped_refptr<TransportSocketParams> params2(
3074 new TransportSocketParams(host_port2, false, false,
3075 OnHostResolutionCallback()));
3076 scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle);
3077 EXPECT_EQ(ERR_IO_PENDING,
3078 connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY,
3079 callback2.callback(), pool, BoundNetLog()));
3080 EXPECT_TRUE(pool->IsStalled());
3081
3082 // The socket pool should close the connection asynchronously and establish a
3083 // new connection.
3084 EXPECT_EQ(OK, callback2.WaitForResult());
3085 EXPECT_FALSE(pool->IsStalled());
3086 EXPECT_TRUE(session1 == NULL);
3087 }
3088
3089 // Tests the case of a non-SPDY request closing an idle SPDY session when no
3090 // pointers to the idle session are currently held, in the case the SPDY session
3091 // has an alias.
TEST_P(SpdySessionTest,CloseOneIdleConnectionWithAlias)3092 TEST_P(SpdySessionTest, CloseOneIdleConnectionWithAlias) {
3093 ClientSocketPoolManager::set_max_sockets_per_group(
3094 HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
3095 ClientSocketPoolManager::set_max_sockets_per_pool(
3096 HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
3097
3098 MockConnect connect_data(SYNCHRONOUS, OK);
3099 MockRead reads[] = {
3100 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
3101 };
3102 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
3103 data.set_connect_data(connect_data);
3104 session_deps_.socket_factory->AddSocketDataProvider(&data);
3105 session_deps_.socket_factory->AddSocketDataProvider(&data);
3106
3107 session_deps_.host_resolver->set_synchronous_mode(true);
3108 session_deps_.host_resolver->rules()->AddIPLiteralRule(
3109 "1.com", "192.168.0.2", std::string());
3110 session_deps_.host_resolver->rules()->AddIPLiteralRule(
3111 "2.com", "192.168.0.2", std::string());
3112 // Not strictly needed.
3113 session_deps_.host_resolver->rules()->AddIPLiteralRule(
3114 "3.com", "192.168.0.3", std::string());
3115
3116 CreateNetworkSession();
3117
3118 TransportClientSocketPool* pool =
3119 http_session_->GetTransportSocketPool(
3120 HttpNetworkSession::NORMAL_SOCKET_POOL);
3121
3122 // Create an idle SPDY session.
3123 SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(),
3124 PRIVACY_MODE_DISABLED);
3125 base::WeakPtr<SpdySession> session1 =
3126 CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
3127 EXPECT_FALSE(pool->IsStalled());
3128
3129 // Set up an alias for the idle SPDY session, increasing its ref count to 2.
3130 SpdySessionKey key2(HostPortPair("2.com", 80), ProxyServer::Direct(),
3131 PRIVACY_MODE_DISABLED);
3132 HostResolver::RequestInfo info(key2.host_port_pair());
3133 AddressList addresses;
3134 // Pre-populate the DNS cache, since a synchronous resolution is required in
3135 // order to create the alias.
3136 session_deps_.host_resolver->Resolve(info,
3137 DEFAULT_PRIORITY,
3138 &addresses,
3139 CompletionCallback(),
3140 NULL,
3141 BoundNetLog());
3142 // Get a session for |key2|, which should return the session created earlier.
3143 base::WeakPtr<SpdySession> session2 =
3144 spdy_session_pool_->FindAvailableSession(key2, BoundNetLog());
3145 ASSERT_EQ(session1.get(), session2.get());
3146 EXPECT_FALSE(pool->IsStalled());
3147
3148 // Trying to create a new connection should cause the pool to be stalled, and
3149 // post a task asynchronously to try and close the session.
3150 TestCompletionCallback callback3;
3151 HostPortPair host_port3("3.com", 80);
3152 scoped_refptr<TransportSocketParams> params3(
3153 new TransportSocketParams(host_port3, false, false,
3154 OnHostResolutionCallback()));
3155 scoped_ptr<ClientSocketHandle> connection3(new ClientSocketHandle);
3156 EXPECT_EQ(ERR_IO_PENDING,
3157 connection3->Init(host_port3.ToString(), params3, DEFAULT_PRIORITY,
3158 callback3.callback(), pool, BoundNetLog()));
3159 EXPECT_TRUE(pool->IsStalled());
3160
3161 // The socket pool should close the connection asynchronously and establish a
3162 // new connection.
3163 EXPECT_EQ(OK, callback3.WaitForResult());
3164 EXPECT_FALSE(pool->IsStalled());
3165 EXPECT_TRUE(session1 == NULL);
3166 EXPECT_TRUE(session2 == NULL);
3167 }
3168
3169 // Tests that when a SPDY session becomes idle, it closes itself if there is
3170 // a lower layer pool stalled on the per-pool socket limit.
TEST_P(SpdySessionTest,CloseSessionOnIdleWhenPoolStalled)3171 TEST_P(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) {
3172 ClientSocketPoolManager::set_max_sockets_per_group(
3173 HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
3174 ClientSocketPoolManager::set_max_sockets_per_pool(
3175 HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
3176
3177 MockConnect connect_data(SYNCHRONOUS, OK);
3178 MockRead reads[] = {
3179 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
3180 };
3181 scoped_ptr<SpdyFrame> req1(
3182 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
3183 scoped_ptr<SpdyFrame> cancel1(
3184 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
3185 MockWrite writes[] = {
3186 CreateMockWrite(*req1, 1),
3187 CreateMockWrite(*cancel1, 1),
3188 };
3189 StaticSocketDataProvider data(reads, arraysize(reads),
3190 writes, arraysize(writes));
3191 data.set_connect_data(connect_data);
3192 session_deps_.socket_factory->AddSocketDataProvider(&data);
3193
3194 MockRead http_reads[] = {
3195 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
3196 };
3197 StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
3198 NULL, 0);
3199 http_data.set_connect_data(connect_data);
3200 session_deps_.socket_factory->AddSocketDataProvider(&http_data);
3201
3202
3203 CreateNetworkSession();
3204
3205 TransportClientSocketPool* pool =
3206 http_session_->GetTransportSocketPool(
3207 HttpNetworkSession::NORMAL_SOCKET_POOL);
3208
3209 // Create a SPDY session.
3210 GURL url1(kDefaultURL);
3211 SpdySessionKey key1(HostPortPair(url1.host(), 80),
3212 ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
3213 base::WeakPtr<SpdySession> session1 =
3214 CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
3215 EXPECT_FALSE(pool->IsStalled());
3216
3217 // Create a stream using the session, and send a request.
3218
3219 TestCompletionCallback callback1;
3220 base::WeakPtr<SpdyStream> spdy_stream1 =
3221 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
3222 session1, url1, DEFAULT_PRIORITY,
3223 BoundNetLog());
3224 ASSERT_TRUE(spdy_stream1.get());
3225 test::StreamDelegateDoNothing delegate1(spdy_stream1);
3226 spdy_stream1->SetDelegate(&delegate1);
3227
3228 scoped_ptr<SpdyHeaderBlock> headers1(
3229 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
3230 EXPECT_EQ(ERR_IO_PENDING,
3231 spdy_stream1->SendRequestHeaders(
3232 headers1.Pass(), NO_MORE_DATA_TO_SEND));
3233 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
3234
3235 base::MessageLoop::current()->RunUntilIdle();
3236
3237 // Trying to create a new connection should cause the pool to be stalled, and
3238 // post a task asynchronously to try and close the session.
3239 TestCompletionCallback callback2;
3240 HostPortPair host_port2("2.com", 80);
3241 scoped_refptr<TransportSocketParams> params2(
3242 new TransportSocketParams(host_port2, false, false,
3243 OnHostResolutionCallback()));
3244 scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle);
3245 EXPECT_EQ(ERR_IO_PENDING,
3246 connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY,
3247 callback2.callback(), pool, BoundNetLog()));
3248 EXPECT_TRUE(pool->IsStalled());
3249
3250 // Running the message loop should cause the socket pool to ask the SPDY
3251 // session to close an idle socket, but since the socket is in use, nothing
3252 // happens.
3253 base::RunLoop().RunUntilIdle();
3254 EXPECT_TRUE(pool->IsStalled());
3255 EXPECT_FALSE(callback2.have_result());
3256
3257 // Cancelling the request should result in the session's socket being
3258 // closed, since the pool is stalled.
3259 ASSERT_TRUE(spdy_stream1.get());
3260 spdy_stream1->Cancel();
3261 base::RunLoop().RunUntilIdle();
3262 ASSERT_FALSE(pool->IsStalled());
3263 EXPECT_EQ(OK, callback2.WaitForResult());
3264 }
3265
3266 // Verify that SpdySessionKey and therefore SpdySession is different when
3267 // privacy mode is enabled or disabled.
TEST_P(SpdySessionTest,SpdySessionKeyPrivacyMode)3268 TEST_P(SpdySessionTest, SpdySessionKeyPrivacyMode) {
3269 CreateDeterministicNetworkSession();
3270
3271 HostPortPair host_port_pair("www.google.com", 443);
3272 SpdySessionKey key_privacy_enabled(host_port_pair, ProxyServer::Direct(),
3273 PRIVACY_MODE_ENABLED);
3274 SpdySessionKey key_privacy_disabled(host_port_pair, ProxyServer::Direct(),
3275 PRIVACY_MODE_DISABLED);
3276
3277 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
3278 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
3279
3280 // Add SpdySession with PrivacyMode Enabled to the pool.
3281 base::WeakPtr<SpdySession> session_privacy_enabled =
3282 CreateFakeSpdySession(spdy_session_pool_, key_privacy_enabled);
3283
3284 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
3285 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
3286
3287 // Add SpdySession with PrivacyMode Disabled to the pool.
3288 base::WeakPtr<SpdySession> session_privacy_disabled =
3289 CreateFakeSpdySession(spdy_session_pool_, key_privacy_disabled);
3290
3291 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
3292 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
3293
3294 session_privacy_enabled->CloseSessionOnError(ERR_ABORTED, std::string());
3295 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
3296 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
3297
3298 session_privacy_disabled->CloseSessionOnError(ERR_ABORTED, std::string());
3299 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
3300 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
3301 }
3302
3303 // Delegate that creates another stream when its stream is closed.
3304 class StreamCreatingDelegate : public test::StreamDelegateDoNothing {
3305 public:
StreamCreatingDelegate(const base::WeakPtr<SpdyStream> & stream,const base::WeakPtr<SpdySession> & session)3306 StreamCreatingDelegate(const base::WeakPtr<SpdyStream>& stream,
3307 const base::WeakPtr<SpdySession>& session)
3308 : StreamDelegateDoNothing(stream),
3309 session_(session) {}
3310
~StreamCreatingDelegate()3311 virtual ~StreamCreatingDelegate() {}
3312
OnClose(int status)3313 virtual void OnClose(int status) OVERRIDE {
3314 GURL url(kDefaultURL);
3315 ignore_result(
3316 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
3317 session_, url, MEDIUM, BoundNetLog()));
3318 }
3319
3320 private:
3321 const base::WeakPtr<SpdySession> session_;
3322 };
3323
3324 // Create another stream in response to a stream being reset. Nothing
3325 // should blow up. This is a regression test for
3326 // http://crbug.com/263690 .
TEST_P(SpdySessionTest,CreateStreamOnStreamReset)3327 TEST_P(SpdySessionTest, CreateStreamOnStreamReset) {
3328 session_deps_.host_resolver->set_synchronous_mode(true);
3329
3330 MockConnect connect_data(SYNCHRONOUS, OK);
3331
3332 scoped_ptr<SpdyFrame> req(
3333 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
3334 MockWrite writes[] = {
3335 CreateMockWrite(*req, 0),
3336 };
3337
3338 scoped_ptr<SpdyFrame> rst(
3339 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM));
3340 MockRead reads[] = {
3341 CreateMockRead(*rst, 1),
3342 MockRead(ASYNC, 0, 2) // EOF
3343 };
3344 DeterministicSocketData data(reads, arraysize(reads),
3345 writes, arraysize(writes));
3346 data.set_connect_data(connect_data);
3347 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3348
3349 CreateDeterministicNetworkSession();
3350
3351 base::WeakPtr<SpdySession> session =
3352 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3353
3354 GURL url(kDefaultURL);
3355 base::WeakPtr<SpdyStream> spdy_stream =
3356 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
3357 session, url, MEDIUM, BoundNetLog());
3358 ASSERT_TRUE(spdy_stream.get() != NULL);
3359 EXPECT_EQ(0u, spdy_stream->stream_id());
3360
3361 StreamCreatingDelegate delegate(spdy_stream, session);
3362 spdy_stream->SetDelegate(&delegate);
3363
3364 scoped_ptr<SpdyHeaderBlock> headers(
3365 spdy_util_.ConstructGetHeaderBlock(url.spec()));
3366 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
3367 EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
3368
3369 EXPECT_EQ(0u, spdy_stream->stream_id());
3370
3371 data.RunFor(1);
3372
3373 EXPECT_EQ(1u, spdy_stream->stream_id());
3374
3375 // Cause the stream to be reset, which should cause another stream
3376 // to be created.
3377 data.RunFor(1);
3378
3379 EXPECT_EQ(NULL, spdy_stream.get());
3380 EXPECT_TRUE(delegate.StreamIsClosed());
3381 EXPECT_EQ(0u, session->num_active_streams());
3382 EXPECT_EQ(1u, session->num_created_streams());
3383 }
3384
3385 // The tests below are only for SPDY/3 and above.
3386
TEST_P(SpdySessionTest,UpdateStreamsSendWindowSize)3387 TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) {
3388 if (GetParam() < kProtoSPDY3)
3389 return;
3390
3391 // Set SETTINGS_INITIAL_WINDOW_SIZE to a small number so that WINDOW_UPDATE
3392 // gets sent.
3393 SettingsMap new_settings;
3394 int32 window_size = 1;
3395 new_settings[SETTINGS_INITIAL_WINDOW_SIZE] =
3396 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, window_size);
3397
3398 // Set up the socket so we read a SETTINGS frame that sets
3399 // INITIAL_WINDOW_SIZE.
3400 MockConnect connect_data(SYNCHRONOUS, OK);
3401 scoped_ptr<SpdyFrame> settings_frame(
3402 spdy_util_.ConstructSpdySettings(new_settings));
3403 MockRead reads[] = {
3404 CreateMockRead(*settings_frame, 0),
3405 MockRead(ASYNC, 0, 1) // EOF
3406 };
3407
3408 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
3409 MockWrite writes[] = {
3410 CreateMockWrite(*settings_ack, 2),
3411 };
3412
3413 session_deps_.host_resolver->set_synchronous_mode(true);
3414
3415 DeterministicSocketData data(reads, arraysize(reads),
3416 writes, arraysize(writes));
3417 data.set_connect_data(connect_data);
3418 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3419
3420 CreateDeterministicNetworkSession();
3421
3422 base::WeakPtr<SpdySession> session =
3423 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3424 base::WeakPtr<SpdyStream> spdy_stream1 =
3425 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
3426 session, test_url_, MEDIUM, BoundNetLog());
3427 ASSERT_TRUE(spdy_stream1.get() != NULL);
3428 TestCompletionCallback callback1;
3429 EXPECT_NE(spdy_stream1->send_window_size(), window_size);
3430
3431 data.RunFor(1); // Process the SETTINGS frame, but not the EOF
3432 base::MessageLoop::current()->RunUntilIdle();
3433 EXPECT_EQ(session->stream_initial_send_window_size(), window_size);
3434 EXPECT_EQ(spdy_stream1->send_window_size(), window_size);
3435
3436 // Release the first one, this will allow the second to be created.
3437 spdy_stream1->Cancel();
3438 EXPECT_EQ(NULL, spdy_stream1.get());
3439
3440 base::WeakPtr<SpdyStream> spdy_stream2 =
3441 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
3442 session, test_url_, MEDIUM, BoundNetLog());
3443 ASSERT_TRUE(spdy_stream2.get() != NULL);
3444 EXPECT_EQ(spdy_stream2->send_window_size(), window_size);
3445 spdy_stream2->Cancel();
3446 EXPECT_EQ(NULL, spdy_stream2.get());
3447 }
3448
3449 // The tests below are only for SPDY/3.1 and above.
3450
3451 // SpdySession::{Increase,Decrease}RecvWindowSize should properly
3452 // adjust the session receive window size for SPDY 3.1 and higher. In
3453 // addition, SpdySession::IncreaseRecvWindowSize should trigger
3454 // sending a WINDOW_UPDATE frame for a large enough delta.
TEST_P(SpdySessionTest,AdjustRecvWindowSize)3455 TEST_P(SpdySessionTest, AdjustRecvWindowSize) {
3456 if (GetParam() < kProtoSPDY31)
3457 return;
3458
3459 session_deps_.host_resolver->set_synchronous_mode(true);
3460
3461 const int32 delta_window_size = 100;
3462
3463 MockConnect connect_data(SYNCHRONOUS, OK);
3464 MockRead reads[] = {
3465 MockRead(ASYNC, 0, 1) // EOF
3466 };
3467 scoped_ptr<SpdyFrame> window_update(
3468 spdy_util_.ConstructSpdyWindowUpdate(
3469 kSessionFlowControlStreamId,
3470 kSpdySessionInitialWindowSize + delta_window_size));
3471 MockWrite writes[] = {
3472 CreateMockWrite(*window_update, 0),
3473 };
3474 DeterministicSocketData data(reads, arraysize(reads),
3475 writes, arraysize(writes));
3476 data.set_connect_data(connect_data);
3477 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3478
3479 CreateDeterministicNetworkSession();
3480 base::WeakPtr<SpdySession> session =
3481 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3482 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
3483 session->flow_control_state());
3484
3485 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3486 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3487
3488 session->IncreaseRecvWindowSize(delta_window_size);
3489 EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size,
3490 session->session_recv_window_size_);
3491 EXPECT_EQ(delta_window_size, session->session_unacked_recv_window_bytes_);
3492
3493 // Should trigger sending a WINDOW_UPDATE frame.
3494 session->IncreaseRecvWindowSize(kSpdySessionInitialWindowSize);
3495 EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size +
3496 kSpdySessionInitialWindowSize,
3497 session->session_recv_window_size_);
3498 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3499
3500 data.RunFor(1);
3501
3502 // DecreaseRecvWindowSize() expects |in_io_loop_| to be true.
3503 session->in_io_loop_ = true;
3504 session->DecreaseRecvWindowSize(
3505 kSpdySessionInitialWindowSize + delta_window_size +
3506 kSpdySessionInitialWindowSize);
3507 session->in_io_loop_ = false;
3508 EXPECT_EQ(0, session->session_recv_window_size_);
3509 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3510 }
3511
3512 // SpdySession::{Increase,Decrease}SendWindowSize should properly
3513 // adjust the session send window size when the "enable_spdy_31" flag
3514 // is set.
TEST_P(SpdySessionTest,AdjustSendWindowSize)3515 TEST_P(SpdySessionTest, AdjustSendWindowSize) {
3516 if (GetParam() < kProtoSPDY31)
3517 return;
3518
3519 session_deps_.host_resolver->set_synchronous_mode(true);
3520
3521 MockConnect connect_data(SYNCHRONOUS, OK);
3522 MockRead reads[] = {
3523 MockRead(SYNCHRONOUS, 0, 0) // EOF
3524 };
3525 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
3526 data.set_connect_data(connect_data);
3527 session_deps_.socket_factory->AddSocketDataProvider(&data);
3528
3529 CreateNetworkSession();
3530 base::WeakPtr<SpdySession> session =
3531 CreateFakeSpdySession(spdy_session_pool_, key_);
3532 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
3533 session->flow_control_state());
3534
3535 const int32 delta_window_size = 100;
3536
3537 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3538
3539 session->IncreaseSendWindowSize(delta_window_size);
3540 EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size,
3541 session->session_send_window_size_);
3542
3543 session->DecreaseSendWindowSize(delta_window_size);
3544 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3545 }
3546
3547 // Incoming data for an inactive stream should not cause the session
3548 // receive window size to decrease, but it should cause the unacked
3549 // bytes to increase.
TEST_P(SpdySessionTest,SessionFlowControlInactiveStream)3550 TEST_P(SpdySessionTest, SessionFlowControlInactiveStream) {
3551 if (GetParam() < kProtoSPDY31)
3552 return;
3553
3554 session_deps_.host_resolver->set_synchronous_mode(true);
3555
3556 MockConnect connect_data(SYNCHRONOUS, OK);
3557 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyBodyFrame(1, false));
3558 MockRead reads[] = {
3559 CreateMockRead(*resp, 0),
3560 MockRead(ASYNC, 0, 1) // EOF
3561 };
3562 DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
3563 data.set_connect_data(connect_data);
3564 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3565
3566 CreateDeterministicNetworkSession();
3567 base::WeakPtr<SpdySession> session =
3568 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3569 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
3570 session->flow_control_state());
3571
3572 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3573 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3574
3575 data.RunFor(1);
3576
3577 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3578 EXPECT_EQ(kUploadDataSize, session->session_unacked_recv_window_bytes_);
3579
3580 data.RunFor(1);
3581 }
3582
3583 // A delegate that drops any received data.
3584 class DropReceivedDataDelegate : public test::StreamDelegateSendImmediate {
3585 public:
DropReceivedDataDelegate(const base::WeakPtr<SpdyStream> & stream,base::StringPiece data)3586 DropReceivedDataDelegate(const base::WeakPtr<SpdyStream>& stream,
3587 base::StringPiece data)
3588 : StreamDelegateSendImmediate(stream, data) {}
3589
~DropReceivedDataDelegate()3590 virtual ~DropReceivedDataDelegate() {}
3591
3592 // Drop any received data.
OnDataReceived(scoped_ptr<SpdyBuffer> buffer)3593 virtual void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) OVERRIDE {}
3594 };
3595
3596 // Send data back and forth but use a delegate that drops its received
3597 // data. The receive window should still increase to its original
3598 // value, i.e. we shouldn't "leak" receive window bytes.
TEST_P(SpdySessionTest,SessionFlowControlNoReceiveLeaks)3599 TEST_P(SpdySessionTest, SessionFlowControlNoReceiveLeaks) {
3600 if (GetParam() < kProtoSPDY31)
3601 return;
3602
3603 const char kStreamUrl[] = "http://www.google.com/";
3604
3605 const int32 msg_data_size = 100;
3606 const std::string msg_data(msg_data_size, 'a');
3607
3608 MockConnect connect_data(SYNCHRONOUS, OK);
3609
3610 scoped_ptr<SpdyFrame> req(
3611 spdy_util_.ConstructSpdyPost(
3612 kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0));
3613 scoped_ptr<SpdyFrame> msg(
3614 spdy_util_.ConstructSpdyBodyFrame(
3615 1, msg_data.data(), msg_data_size, false));
3616 MockWrite writes[] = {
3617 CreateMockWrite(*req, 0),
3618 CreateMockWrite(*msg, 2),
3619 };
3620
3621 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3622 scoped_ptr<SpdyFrame> echo(
3623 spdy_util_.ConstructSpdyBodyFrame(
3624 1, msg_data.data(), msg_data_size, false));
3625 scoped_ptr<SpdyFrame> window_update(
3626 spdy_util_.ConstructSpdyWindowUpdate(
3627 kSessionFlowControlStreamId, msg_data_size));
3628 MockRead reads[] = {
3629 CreateMockRead(*resp, 1),
3630 CreateMockRead(*echo, 3),
3631 MockRead(ASYNC, 0, 4) // EOF
3632 };
3633
3634 // Create SpdySession and SpdyStream and send the request.
3635 DeterministicSocketData data(reads, arraysize(reads),
3636 writes, arraysize(writes));
3637 data.set_connect_data(connect_data);
3638 session_deps_.host_resolver->set_synchronous_mode(true);
3639 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3640
3641 CreateDeterministicNetworkSession();
3642
3643 base::WeakPtr<SpdySession> session =
3644 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3645
3646 GURL url(kStreamUrl);
3647 base::WeakPtr<SpdyStream> stream =
3648 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
3649 session, url, MEDIUM, BoundNetLog());
3650 ASSERT_TRUE(stream.get() != NULL);
3651 EXPECT_EQ(0u, stream->stream_id());
3652
3653 DropReceivedDataDelegate delegate(stream, msg_data);
3654 stream->SetDelegate(&delegate);
3655
3656 scoped_ptr<SpdyHeaderBlock> headers(
3657 spdy_util_.ConstructPostHeaderBlock(url.spec(), msg_data_size));
3658 EXPECT_EQ(ERR_IO_PENDING,
3659 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
3660 EXPECT_TRUE(stream->HasUrlFromHeaders());
3661
3662 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3663 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3664
3665 data.RunFor(4);
3666
3667 EXPECT_TRUE(data.at_write_eof());
3668 EXPECT_TRUE(data.at_read_eof());
3669
3670 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3671 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
3672
3673 stream->Close();
3674 EXPECT_EQ(NULL, stream.get());
3675
3676 EXPECT_EQ(OK, delegate.WaitForClose());
3677
3678 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3679 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
3680 }
3681
3682 // Send data back and forth but close the stream before its data frame
3683 // can be written to the socket. The send window should then increase
3684 // to its original value, i.e. we shouldn't "leak" send window bytes.
TEST_P(SpdySessionTest,SessionFlowControlNoSendLeaks)3685 TEST_P(SpdySessionTest, SessionFlowControlNoSendLeaks) {
3686 if (GetParam() < kProtoSPDY31)
3687 return;
3688
3689 const char kStreamUrl[] = "http://www.google.com/";
3690
3691 const int32 msg_data_size = 100;
3692 const std::string msg_data(msg_data_size, 'a');
3693
3694 MockConnect connect_data(SYNCHRONOUS, OK);
3695
3696 scoped_ptr<SpdyFrame> req(
3697 spdy_util_.ConstructSpdyPost(
3698 kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0));
3699 MockWrite writes[] = {
3700 CreateMockWrite(*req, 0),
3701 };
3702
3703 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3704 MockRead reads[] = {
3705 CreateMockRead(*resp, 1),
3706 MockRead(ASYNC, 0, 2) // EOF
3707 };
3708
3709 // Create SpdySession and SpdyStream and send the request.
3710 DeterministicSocketData data(reads, arraysize(reads),
3711 writes, arraysize(writes));
3712 data.set_connect_data(connect_data);
3713 session_deps_.host_resolver->set_synchronous_mode(true);
3714 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3715
3716 CreateDeterministicNetworkSession();
3717
3718 base::WeakPtr<SpdySession> session =
3719 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3720
3721 GURL url(kStreamUrl);
3722 base::WeakPtr<SpdyStream> stream =
3723 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
3724 session, url, MEDIUM, BoundNetLog());
3725 ASSERT_TRUE(stream.get() != NULL);
3726 EXPECT_EQ(0u, stream->stream_id());
3727
3728 test::StreamDelegateSendImmediate delegate(stream, msg_data);
3729 stream->SetDelegate(&delegate);
3730
3731 scoped_ptr<SpdyHeaderBlock> headers(
3732 spdy_util_.ConstructPostHeaderBlock(url.spec(), msg_data_size));
3733 EXPECT_EQ(ERR_IO_PENDING,
3734 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
3735 EXPECT_TRUE(stream->HasUrlFromHeaders());
3736
3737 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3738
3739 data.RunFor(1);
3740
3741 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3742
3743 data.RunFor(1);
3744
3745 EXPECT_TRUE(data.at_write_eof());
3746 EXPECT_TRUE(data.at_read_eof());
3747
3748 EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
3749 session->session_send_window_size_);
3750
3751 // Closing the stream should increase the session's send window.
3752 stream->Close();
3753 EXPECT_EQ(NULL, stream.get());
3754
3755 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3756
3757 EXPECT_EQ(OK, delegate.WaitForClose());
3758 }
3759
3760 // Send data back and forth; the send and receive windows should
3761 // change appropriately.
TEST_P(SpdySessionTest,SessionFlowControlEndToEnd)3762 TEST_P(SpdySessionTest, SessionFlowControlEndToEnd) {
3763 if (GetParam() < kProtoSPDY31)
3764 return;
3765
3766 const char kStreamUrl[] = "http://www.google.com/";
3767
3768 const int32 msg_data_size = 100;
3769 const std::string msg_data(msg_data_size, 'a');
3770
3771 MockConnect connect_data(SYNCHRONOUS, OK);
3772
3773 scoped_ptr<SpdyFrame> req(
3774 spdy_util_.ConstructSpdyPost(
3775 kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0));
3776 scoped_ptr<SpdyFrame> msg(
3777 spdy_util_.ConstructSpdyBodyFrame(
3778 1, msg_data.data(), msg_data_size, false));
3779 MockWrite writes[] = {
3780 CreateMockWrite(*req, 0),
3781 CreateMockWrite(*msg, 2),
3782 };
3783
3784 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3785 scoped_ptr<SpdyFrame> echo(
3786 spdy_util_.ConstructSpdyBodyFrame(
3787 1, msg_data.data(), msg_data_size, false));
3788 scoped_ptr<SpdyFrame> window_update(
3789 spdy_util_.ConstructSpdyWindowUpdate(
3790 kSessionFlowControlStreamId, msg_data_size));
3791 MockRead reads[] = {
3792 CreateMockRead(*resp, 1),
3793 CreateMockRead(*echo, 3),
3794 CreateMockRead(*window_update, 4),
3795 MockRead(ASYNC, 0, 5) // EOF
3796 };
3797
3798 // Create SpdySession and SpdyStream and send the request.
3799 DeterministicSocketData data(reads, arraysize(reads),
3800 writes, arraysize(writes));
3801 data.set_connect_data(connect_data);
3802 session_deps_.host_resolver->set_synchronous_mode(true);
3803 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3804
3805 CreateDeterministicNetworkSession();
3806
3807 base::WeakPtr<SpdySession> session =
3808 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3809
3810 GURL url(kStreamUrl);
3811 base::WeakPtr<SpdyStream> stream =
3812 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
3813 session, url, MEDIUM, BoundNetLog());
3814 ASSERT_TRUE(stream.get() != NULL);
3815 EXPECT_EQ(0u, stream->stream_id());
3816
3817 test::StreamDelegateSendImmediate delegate(stream, msg_data);
3818 stream->SetDelegate(&delegate);
3819
3820 scoped_ptr<SpdyHeaderBlock> headers(
3821 spdy_util_.ConstructPostHeaderBlock(url.spec(), msg_data_size));
3822 EXPECT_EQ(ERR_IO_PENDING,
3823 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
3824 EXPECT_TRUE(stream->HasUrlFromHeaders());
3825
3826 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3827 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3828 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3829
3830 data.RunFor(1);
3831
3832 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3833 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3834 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3835
3836 data.RunFor(1);
3837
3838 EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
3839 session->session_send_window_size_);
3840 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3841 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3842
3843 data.RunFor(1);
3844
3845 EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
3846 session->session_send_window_size_);
3847 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3848 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3849
3850 data.RunFor(1);
3851
3852 EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
3853 session->session_send_window_size_);
3854 EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
3855 session->session_recv_window_size_);
3856 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3857
3858 data.RunFor(1);
3859
3860 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3861 EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
3862 session->session_recv_window_size_);
3863 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3864
3865 EXPECT_TRUE(data.at_write_eof());
3866 EXPECT_TRUE(data.at_read_eof());
3867
3868 EXPECT_EQ(msg_data, delegate.TakeReceivedData());
3869
3870 // Draining the delegate's read queue should increase the session's
3871 // receive window.
3872 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3873 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3874 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
3875
3876 stream->Close();
3877 EXPECT_EQ(NULL, stream.get());
3878
3879 EXPECT_EQ(OK, delegate.WaitForClose());
3880
3881 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3882 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3883 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
3884 }
3885
3886 // Given a stall function and an unstall function, runs a test to make
3887 // sure that a stream resumes after unstall.
RunResumeAfterUnstallTest(const base::Callback<void (SpdySession *,SpdyStream *)> & stall_function,const base::Callback<void (SpdySession *,SpdyStream *,int32)> & unstall_function)3888 void SpdySessionTest::RunResumeAfterUnstallTest(
3889 const base::Callback<void(SpdySession*, SpdyStream*)>& stall_function,
3890 const base::Callback<void(SpdySession*, SpdyStream*, int32)>&
3891 unstall_function) {
3892 const char kStreamUrl[] = "http://www.google.com/";
3893 GURL url(kStreamUrl);
3894
3895 session_deps_.host_resolver->set_synchronous_mode(true);
3896
3897 scoped_ptr<SpdyFrame> req(
3898 spdy_util_.ConstructSpdyPost(
3899 kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
3900 scoped_ptr<SpdyFrame> body(
3901 spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, true));
3902 MockWrite writes[] = {
3903 CreateMockWrite(*req, 0),
3904 CreateMockWrite(*body, 1),
3905 };
3906
3907 scoped_ptr<SpdyFrame> resp(
3908 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3909 scoped_ptr<SpdyFrame> echo(
3910 spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false));
3911 MockRead reads[] = {
3912 CreateMockRead(*resp, 2),
3913 MockRead(ASYNC, 0, 0, 3), // EOF
3914 };
3915
3916 DeterministicSocketData data(reads, arraysize(reads),
3917 writes, arraysize(writes));
3918 MockConnect connect_data(SYNCHRONOUS, OK);
3919 data.set_connect_data(connect_data);
3920
3921 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3922
3923 CreateDeterministicNetworkSession();
3924 base::WeakPtr<SpdySession> session =
3925 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3926 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
3927 session->flow_control_state());
3928
3929 base::WeakPtr<SpdyStream> stream =
3930 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
3931 session, url, LOWEST, BoundNetLog());
3932 ASSERT_TRUE(stream.get() != NULL);
3933
3934 test::StreamDelegateWithBody delegate(stream, kBodyDataStringPiece);
3935 stream->SetDelegate(&delegate);
3936
3937 EXPECT_FALSE(stream->HasUrlFromHeaders());
3938 EXPECT_FALSE(stream->send_stalled_by_flow_control());
3939
3940 scoped_ptr<SpdyHeaderBlock> headers(
3941 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
3942 EXPECT_EQ(ERR_IO_PENDING,
3943 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
3944 EXPECT_TRUE(stream->HasUrlFromHeaders());
3945 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
3946
3947 stall_function.Run(session.get(), stream.get());
3948
3949 data.RunFor(1);
3950
3951 EXPECT_TRUE(stream->send_stalled_by_flow_control());
3952
3953 unstall_function.Run(session.get(), stream.get(), kBodyDataSize);
3954
3955 EXPECT_FALSE(stream->send_stalled_by_flow_control());
3956
3957 data.RunFor(3);
3958
3959 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
3960
3961 EXPECT_TRUE(delegate.send_headers_completed());
3962 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
3963 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
3964 EXPECT_TRUE(data.at_write_eof());
3965 }
3966
3967 // Run the resume-after-unstall test with all possible stall and
3968 // unstall sequences.
3969
TEST_P(SpdySessionTest,ResumeAfterUnstallSession)3970 TEST_P(SpdySessionTest, ResumeAfterUnstallSession) {
3971 if (GetParam() < kProtoSPDY31)
3972 return;
3973
3974 RunResumeAfterUnstallTest(
3975 base::Bind(&SpdySessionTest::StallSessionOnly,
3976 base::Unretained(this)),
3977 base::Bind(&SpdySessionTest::UnstallSessionOnly,
3978 base::Unretained(this)));
3979 }
3980
3981 // Equivalent to
3982 // SpdyStreamTest.ResumeAfterSendWindowSizeIncrease.
TEST_P(SpdySessionTest,ResumeAfterUnstallStream)3983 TEST_P(SpdySessionTest, ResumeAfterUnstallStream) {
3984 if (GetParam() < kProtoSPDY31)
3985 return;
3986
3987 RunResumeAfterUnstallTest(
3988 base::Bind(&SpdySessionTest::StallStreamOnly,
3989 base::Unretained(this)),
3990 base::Bind(&SpdySessionTest::UnstallStreamOnly,
3991 base::Unretained(this)));
3992 }
3993
TEST_P(SpdySessionTest,StallSessionStreamResumeAfterUnstallSessionStream)3994 TEST_P(SpdySessionTest, StallSessionStreamResumeAfterUnstallSessionStream) {
3995 if (GetParam() < kProtoSPDY31)
3996 return;
3997
3998 RunResumeAfterUnstallTest(
3999 base::Bind(&SpdySessionTest::StallSessionStream,
4000 base::Unretained(this)),
4001 base::Bind(&SpdySessionTest::UnstallSessionStream,
4002 base::Unretained(this)));
4003 }
4004
TEST_P(SpdySessionTest,StallStreamSessionResumeAfterUnstallSessionStream)4005 TEST_P(SpdySessionTest, StallStreamSessionResumeAfterUnstallSessionStream) {
4006 if (GetParam() < kProtoSPDY31)
4007 return;
4008
4009 RunResumeAfterUnstallTest(
4010 base::Bind(&SpdySessionTest::StallStreamSession,
4011 base::Unretained(this)),
4012 base::Bind(&SpdySessionTest::UnstallSessionStream,
4013 base::Unretained(this)));
4014 }
4015
TEST_P(SpdySessionTest,StallStreamSessionResumeAfterUnstallStreamSession)4016 TEST_P(SpdySessionTest, StallStreamSessionResumeAfterUnstallStreamSession) {
4017 if (GetParam() < kProtoSPDY31)
4018 return;
4019
4020 RunResumeAfterUnstallTest(
4021 base::Bind(&SpdySessionTest::StallStreamSession,
4022 base::Unretained(this)),
4023 base::Bind(&SpdySessionTest::UnstallStreamSession,
4024 base::Unretained(this)));
4025 }
4026
TEST_P(SpdySessionTest,StallSessionStreamResumeAfterUnstallStreamSession)4027 TEST_P(SpdySessionTest, StallSessionStreamResumeAfterUnstallStreamSession) {
4028 if (GetParam() < kProtoSPDY31)
4029 return;
4030
4031 RunResumeAfterUnstallTest(
4032 base::Bind(&SpdySessionTest::StallSessionStream,
4033 base::Unretained(this)),
4034 base::Bind(&SpdySessionTest::UnstallStreamSession,
4035 base::Unretained(this)));
4036 }
4037
4038 // Cause a stall by reducing the flow control send window to 0. The
4039 // streams should resume in priority order when that window is then
4040 // increased.
TEST_P(SpdySessionTest,ResumeByPriorityAfterSendWindowSizeIncrease)4041 TEST_P(SpdySessionTest, ResumeByPriorityAfterSendWindowSizeIncrease) {
4042 if (GetParam() < kProtoSPDY31)
4043 return;
4044
4045 const char kStreamUrl[] = "http://www.google.com/";
4046 GURL url(kStreamUrl);
4047
4048 session_deps_.host_resolver->set_synchronous_mode(true);
4049
4050 scoped_ptr<SpdyFrame> req1(
4051 spdy_util_.ConstructSpdyPost(
4052 kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
4053 scoped_ptr<SpdyFrame> req2(
4054 spdy_util_.ConstructSpdyPost(
4055 kStreamUrl, 3, kBodyDataSize, MEDIUM, NULL, 0));
4056 scoped_ptr<SpdyFrame> body1(
4057 spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, true));
4058 scoped_ptr<SpdyFrame> body2(
4059 spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true));
4060 MockWrite writes[] = {
4061 CreateMockWrite(*req1, 0),
4062 CreateMockWrite(*req2, 1),
4063 CreateMockWrite(*body2, 2),
4064 CreateMockWrite(*body1, 3),
4065 };
4066
4067 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4068 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
4069 MockRead reads[] = {
4070 CreateMockRead(*resp1, 4),
4071 CreateMockRead(*resp2, 5),
4072 MockRead(ASYNC, 0, 0, 6), // EOF
4073 };
4074
4075 DeterministicSocketData data(reads, arraysize(reads),
4076 writes, arraysize(writes));
4077 MockConnect connect_data(SYNCHRONOUS, OK);
4078 data.set_connect_data(connect_data);
4079
4080 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
4081
4082 CreateDeterministicNetworkSession();
4083 base::WeakPtr<SpdySession> session =
4084 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
4085 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
4086 session->flow_control_state());
4087
4088 base::WeakPtr<SpdyStream> stream1 =
4089 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
4090 session, url, LOWEST, BoundNetLog());
4091 ASSERT_TRUE(stream1.get() != NULL);
4092
4093 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
4094 stream1->SetDelegate(&delegate1);
4095
4096 EXPECT_FALSE(stream1->HasUrlFromHeaders());
4097
4098 base::WeakPtr<SpdyStream> stream2 =
4099 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
4100 session, url, MEDIUM, BoundNetLog());
4101 ASSERT_TRUE(stream2.get() != NULL);
4102
4103 test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece);
4104 stream2->SetDelegate(&delegate2);
4105
4106 EXPECT_FALSE(stream2->HasUrlFromHeaders());
4107
4108 EXPECT_FALSE(stream1->send_stalled_by_flow_control());
4109 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
4110
4111 StallSessionSend(session.get());
4112
4113 scoped_ptr<SpdyHeaderBlock> headers1(
4114 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
4115 EXPECT_EQ(ERR_IO_PENDING,
4116 stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND));
4117 EXPECT_TRUE(stream1->HasUrlFromHeaders());
4118 EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec());
4119
4120 data.RunFor(1);
4121 EXPECT_EQ(1u, stream1->stream_id());
4122 EXPECT_TRUE(stream1->send_stalled_by_flow_control());
4123
4124 scoped_ptr<SpdyHeaderBlock> headers2(
4125 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
4126 EXPECT_EQ(ERR_IO_PENDING,
4127 stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND));
4128 EXPECT_TRUE(stream2->HasUrlFromHeaders());
4129 EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec());
4130
4131 data.RunFor(1);
4132 EXPECT_EQ(3u, stream2->stream_id());
4133 EXPECT_TRUE(stream2->send_stalled_by_flow_control());
4134
4135 // This should unstall only stream2.
4136 UnstallSessionSend(session.get(), kBodyDataSize);
4137
4138 EXPECT_TRUE(stream1->send_stalled_by_flow_control());
4139 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
4140
4141 data.RunFor(1);
4142
4143 EXPECT_TRUE(stream1->send_stalled_by_flow_control());
4144 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
4145
4146 // This should then unstall stream1.
4147 UnstallSessionSend(session.get(), kBodyDataSize);
4148
4149 EXPECT_FALSE(stream1->send_stalled_by_flow_control());
4150 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
4151
4152 data.RunFor(4);
4153
4154 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
4155 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
4156
4157 EXPECT_TRUE(delegate1.send_headers_completed());
4158 EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status"));
4159 EXPECT_EQ(std::string(), delegate1.TakeReceivedData());
4160
4161 EXPECT_TRUE(delegate2.send_headers_completed());
4162 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status"));
4163 EXPECT_EQ(std::string(), delegate2.TakeReceivedData());
4164
4165 EXPECT_TRUE(data.at_write_eof());
4166 }
4167
4168 // Delegate that closes a given stream after sending its body.
4169 class StreamClosingDelegate : public test::StreamDelegateWithBody {
4170 public:
StreamClosingDelegate(const base::WeakPtr<SpdyStream> & stream,base::StringPiece data)4171 StreamClosingDelegate(const base::WeakPtr<SpdyStream>& stream,
4172 base::StringPiece data)
4173 : StreamDelegateWithBody(stream, data) {}
4174
~StreamClosingDelegate()4175 virtual ~StreamClosingDelegate() {}
4176
set_stream_to_close(const base::WeakPtr<SpdyStream> & stream_to_close)4177 void set_stream_to_close(const base::WeakPtr<SpdyStream>& stream_to_close) {
4178 stream_to_close_ = stream_to_close;
4179 }
4180
OnDataSent()4181 virtual void OnDataSent() OVERRIDE {
4182 test::StreamDelegateWithBody::OnDataSent();
4183 if (stream_to_close_.get()) {
4184 stream_to_close_->Close();
4185 EXPECT_EQ(NULL, stream_to_close_.get());
4186 }
4187 }
4188
4189 private:
4190 base::WeakPtr<SpdyStream> stream_to_close_;
4191 };
4192
4193 // Cause a stall by reducing the flow control send window to
4194 // 0. Unstalling the session should properly handle deleted streams.
TEST_P(SpdySessionTest,SendWindowSizeIncreaseWithDeletedStreams)4195 TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) {
4196 if (GetParam() < kProtoSPDY31)
4197 return;
4198
4199 const char kStreamUrl[] = "http://www.google.com/";
4200 GURL url(kStreamUrl);
4201
4202 session_deps_.host_resolver->set_synchronous_mode(true);
4203
4204 scoped_ptr<SpdyFrame> req1(
4205 spdy_util_.ConstructSpdyPost(
4206 kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
4207 scoped_ptr<SpdyFrame> req2(
4208 spdy_util_.ConstructSpdyPost(
4209 kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0));
4210 scoped_ptr<SpdyFrame> req3(
4211 spdy_util_.ConstructSpdyPost(
4212 kStreamUrl, 5, kBodyDataSize, LOWEST, NULL, 0));
4213 scoped_ptr<SpdyFrame> body2(
4214 spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true));
4215 MockWrite writes[] = {
4216 CreateMockWrite(*req1, 0),
4217 CreateMockWrite(*req2, 1),
4218 CreateMockWrite(*req3, 2),
4219 CreateMockWrite(*body2, 3),
4220 };
4221
4222 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
4223 MockRead reads[] = {
4224 CreateMockRead(*resp2, 4),
4225 MockRead(ASYNC, 0, 0, 5), // EOF
4226 };
4227
4228 DeterministicSocketData data(reads, arraysize(reads),
4229 writes, arraysize(writes));
4230 MockConnect connect_data(SYNCHRONOUS, OK);
4231 data.set_connect_data(connect_data);
4232
4233 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
4234
4235 CreateDeterministicNetworkSession();
4236 base::WeakPtr<SpdySession> session =
4237 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
4238 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
4239 session->flow_control_state());
4240
4241 base::WeakPtr<SpdyStream> stream1 =
4242 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
4243 session, url, LOWEST, BoundNetLog());
4244 ASSERT_TRUE(stream1.get() != NULL);
4245
4246 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
4247 stream1->SetDelegate(&delegate1);
4248
4249 EXPECT_FALSE(stream1->HasUrlFromHeaders());
4250
4251 base::WeakPtr<SpdyStream> stream2 =
4252 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
4253 session, url, LOWEST, BoundNetLog());
4254 ASSERT_TRUE(stream2.get() != NULL);
4255
4256 StreamClosingDelegate delegate2(stream2, kBodyDataStringPiece);
4257 stream2->SetDelegate(&delegate2);
4258
4259 EXPECT_FALSE(stream2->HasUrlFromHeaders());
4260
4261 base::WeakPtr<SpdyStream> stream3 =
4262 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
4263 session, url, LOWEST, BoundNetLog());
4264 ASSERT_TRUE(stream3.get() != NULL);
4265
4266 test::StreamDelegateWithBody delegate3(stream3, kBodyDataStringPiece);
4267 stream3->SetDelegate(&delegate3);
4268
4269 EXPECT_FALSE(stream3->HasUrlFromHeaders());
4270
4271 EXPECT_FALSE(stream1->send_stalled_by_flow_control());
4272 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
4273 EXPECT_FALSE(stream3->send_stalled_by_flow_control());
4274
4275 StallSessionSend(session.get());
4276
4277 scoped_ptr<SpdyHeaderBlock> headers1(
4278 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
4279 EXPECT_EQ(ERR_IO_PENDING,
4280 stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND));
4281 EXPECT_TRUE(stream1->HasUrlFromHeaders());
4282 EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec());
4283
4284 data.RunFor(1);
4285 EXPECT_EQ(1u, stream1->stream_id());
4286 EXPECT_TRUE(stream1->send_stalled_by_flow_control());
4287
4288 scoped_ptr<SpdyHeaderBlock> headers2(
4289 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
4290 EXPECT_EQ(ERR_IO_PENDING,
4291 stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND));
4292 EXPECT_TRUE(stream2->HasUrlFromHeaders());
4293 EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec());
4294
4295 data.RunFor(1);
4296 EXPECT_EQ(3u, stream2->stream_id());
4297 EXPECT_TRUE(stream2->send_stalled_by_flow_control());
4298
4299 scoped_ptr<SpdyHeaderBlock> headers3(
4300 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
4301 EXPECT_EQ(ERR_IO_PENDING,
4302 stream3->SendRequestHeaders(headers3.Pass(), MORE_DATA_TO_SEND));
4303 EXPECT_TRUE(stream3->HasUrlFromHeaders());
4304 EXPECT_EQ(kStreamUrl, stream3->GetUrlFromHeaders().spec());
4305
4306 data.RunFor(1);
4307 EXPECT_EQ(5u, stream3->stream_id());
4308 EXPECT_TRUE(stream3->send_stalled_by_flow_control());
4309
4310 SpdyStreamId stream_id1 = stream1->stream_id();
4311 SpdyStreamId stream_id2 = stream2->stream_id();
4312 SpdyStreamId stream_id3 = stream3->stream_id();
4313
4314 // Close stream1 preemptively.
4315 session->CloseActiveStream(stream_id1, ERR_CONNECTION_CLOSED);
4316 EXPECT_EQ(NULL, stream1.get());
4317
4318 EXPECT_FALSE(session->IsStreamActive(stream_id1));
4319 EXPECT_TRUE(session->IsStreamActive(stream_id2));
4320 EXPECT_TRUE(session->IsStreamActive(stream_id3));
4321
4322 // Unstall stream2, which should then close stream3.
4323 delegate2.set_stream_to_close(stream3);
4324 UnstallSessionSend(session.get(), kBodyDataSize);
4325
4326 data.RunFor(1);
4327 EXPECT_EQ(NULL, stream3.get());
4328
4329 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
4330 EXPECT_FALSE(session->IsStreamActive(stream_id1));
4331 EXPECT_TRUE(session->IsStreamActive(stream_id2));
4332 EXPECT_FALSE(session->IsStreamActive(stream_id3));
4333
4334 data.RunFor(2);
4335 EXPECT_EQ(NULL, stream2.get());
4336
4337 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
4338 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
4339 EXPECT_EQ(OK, delegate3.WaitForClose());
4340
4341 EXPECT_TRUE(delegate1.send_headers_completed());
4342 EXPECT_EQ(std::string(), delegate1.TakeReceivedData());
4343
4344 EXPECT_TRUE(delegate2.send_headers_completed());
4345 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status"));
4346 EXPECT_EQ(std::string(), delegate2.TakeReceivedData());
4347
4348 EXPECT_TRUE(delegate3.send_headers_completed());
4349 EXPECT_EQ(std::string(), delegate3.TakeReceivedData());
4350
4351 EXPECT_TRUE(data.at_write_eof());
4352 }
4353
4354 // Cause a stall by reducing the flow control send window to
4355 // 0. Unstalling the session should properly handle the session itself
4356 // being closed.
TEST_P(SpdySessionTest,SendWindowSizeIncreaseWithDeletedSession)4357 TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) {
4358 if (GetParam() < kProtoSPDY31)
4359 return;
4360
4361 const char kStreamUrl[] = "http://www.google.com/";
4362 GURL url(kStreamUrl);
4363
4364 session_deps_.host_resolver->set_synchronous_mode(true);
4365
4366 scoped_ptr<SpdyFrame> req1(
4367 spdy_util_.ConstructSpdyPost(
4368 kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
4369 scoped_ptr<SpdyFrame> req2(
4370 spdy_util_.ConstructSpdyPost(
4371 kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0));
4372 scoped_ptr<SpdyFrame> body1(
4373 spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false));
4374 MockWrite writes[] = {
4375 CreateMockWrite(*req1, 0),
4376 CreateMockWrite(*req2, 1),
4377 };
4378
4379 MockRead reads[] = {
4380 MockRead(ASYNC, 0, 0, 2), // EOF
4381 };
4382
4383 DeterministicSocketData data(reads, arraysize(reads),
4384 writes, arraysize(writes));
4385 MockConnect connect_data(SYNCHRONOUS, OK);
4386 data.set_connect_data(connect_data);
4387
4388 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
4389
4390 CreateDeterministicNetworkSession();
4391 base::WeakPtr<SpdySession> session =
4392 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
4393 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
4394 session->flow_control_state());
4395
4396 base::WeakPtr<SpdyStream> stream1 =
4397 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
4398 session, url, LOWEST, BoundNetLog());
4399 ASSERT_TRUE(stream1.get() != NULL);
4400
4401 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
4402 stream1->SetDelegate(&delegate1);
4403
4404 EXPECT_FALSE(stream1->HasUrlFromHeaders());
4405
4406 base::WeakPtr<SpdyStream> stream2 =
4407 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
4408 session, url, LOWEST, BoundNetLog());
4409 ASSERT_TRUE(stream2.get() != NULL);
4410
4411 test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece);
4412 stream2->SetDelegate(&delegate2);
4413
4414 EXPECT_FALSE(stream2->HasUrlFromHeaders());
4415
4416 EXPECT_FALSE(stream1->send_stalled_by_flow_control());
4417 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
4418
4419 StallSessionSend(session.get());
4420
4421 scoped_ptr<SpdyHeaderBlock> headers1(
4422 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
4423 EXPECT_EQ(ERR_IO_PENDING,
4424 stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND));
4425 EXPECT_TRUE(stream1->HasUrlFromHeaders());
4426 EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec());
4427
4428 data.RunFor(1);
4429 EXPECT_EQ(1u, stream1->stream_id());
4430 EXPECT_TRUE(stream1->send_stalled_by_flow_control());
4431
4432 scoped_ptr<SpdyHeaderBlock> headers2(
4433 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
4434 EXPECT_EQ(ERR_IO_PENDING,
4435 stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND));
4436 EXPECT_TRUE(stream2->HasUrlFromHeaders());
4437 EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec());
4438
4439 data.RunFor(1);
4440 EXPECT_EQ(3u, stream2->stream_id());
4441 EXPECT_TRUE(stream2->send_stalled_by_flow_control());
4442
4443 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
4444
4445 // Unstall stream1.
4446 UnstallSessionSend(session.get(), kBodyDataSize);
4447
4448 // Close the session (since we can't do it from within the delegate
4449 // method, since it's in the stream's loop).
4450 session->CloseSessionOnError(ERR_CONNECTION_CLOSED, "Closing session");
4451 base::RunLoop().RunUntilIdle();
4452 EXPECT_TRUE(session == NULL);
4453
4454 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
4455
4456 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
4457 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
4458
4459 EXPECT_TRUE(delegate1.send_headers_completed());
4460 EXPECT_EQ(std::string(), delegate1.TakeReceivedData());
4461
4462 EXPECT_TRUE(delegate2.send_headers_completed());
4463 EXPECT_EQ(std::string(), delegate2.TakeReceivedData());
4464
4465 EXPECT_TRUE(data.at_write_eof());
4466 }
4467
TEST_P(SpdySessionTest,GoAwayOnSessionFlowControlError)4468 TEST_P(SpdySessionTest, GoAwayOnSessionFlowControlError) {
4469 if (GetParam() < kProtoSPDY31)
4470 return;
4471
4472 MockConnect connect_data(SYNCHRONOUS, OK);
4473
4474 scoped_ptr<SpdyFrame> req(
4475 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
4476 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
4477 0,
4478 GOAWAY_FLOW_CONTROL_ERROR,
4479 "delta_window_size is 6 in DecreaseRecvWindowSize, which is larger than "
4480 "the receive window size of 1"));
4481 MockWrite writes[] = {
4482 CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 3),
4483 };
4484
4485 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
4486 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
4487 MockRead reads[] = {
4488 CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
4489 };
4490
4491 DeterministicSocketData data(
4492 reads, arraysize(reads), writes, arraysize(writes));
4493 data.set_connect_data(connect_data);
4494 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
4495
4496 CreateDeterministicNetworkSession();
4497
4498 base::WeakPtr<SpdySession> session =
4499 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
4500
4501 GURL url(kDefaultURL);
4502 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
4503 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
4504 ASSERT_TRUE(spdy_stream.get() != NULL);
4505 test::StreamDelegateDoNothing delegate(spdy_stream);
4506 spdy_stream->SetDelegate(&delegate);
4507
4508 scoped_ptr<SpdyHeaderBlock> headers(
4509 spdy_util_.ConstructGetHeaderBlock(url.spec()));
4510 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
4511
4512 data.RunFor(1); // Write request.
4513
4514 // Put session on the edge of overflowing it's recv window.
4515 session->session_recv_window_size_ = 1;
4516
4517 // Read response headers & body. Body overflows the session window, and a
4518 // goaway is written.
4519 data.RunFor(3);
4520 base::MessageLoop::current()->RunUntilIdle();
4521
4522 EXPECT_EQ(ERR_SPDY_FLOW_CONTROL_ERROR, delegate.WaitForClose());
4523 EXPECT_TRUE(session == NULL);
4524 }
4525
TEST_P(SpdySessionTest,SplitHeaders)4526 TEST_P(SpdySessionTest, SplitHeaders) {
4527 GURL kStreamUrl("http://www.google.com/foo.dat");
4528 SpdyHeaderBlock headers;
4529 spdy_util_.AddUrlToHeaderBlock(kStreamUrl.spec(), &headers);
4530 headers["alpha"] = "beta";
4531
4532 SpdyHeaderBlock request_headers;
4533 SpdyHeaderBlock response_headers;
4534
4535 SplitPushedHeadersToRequestAndResponse(
4536 headers, spdy_util_.spdy_version(), &request_headers, &response_headers);
4537
4538 SpdyHeaderBlock::const_iterator it = response_headers.find("alpha");
4539 std::string alpha_val =
4540 (it == response_headers.end()) ? std::string() : it->second;
4541 EXPECT_EQ("beta", alpha_val);
4542
4543 GURL request_url =
4544 GetUrlFromHeaderBlock(request_headers, spdy_util_.spdy_version(), true);
4545 EXPECT_EQ(kStreamUrl, request_url);
4546 }
4547
TEST(MapFramerErrorToProtocolError,MapsValues)4548 TEST(MapFramerErrorToProtocolError, MapsValues) {
4549 CHECK_EQ(
4550 SPDY_ERROR_INVALID_CONTROL_FRAME,
4551 MapFramerErrorToProtocolError(SpdyFramer::SPDY_INVALID_CONTROL_FRAME));
4552 CHECK_EQ(
4553 SPDY_ERROR_INVALID_DATA_FRAME_FLAGS,
4554 MapFramerErrorToProtocolError(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS));
4555 CHECK_EQ(
4556 SPDY_ERROR_GOAWAY_FRAME_CORRUPT,
4557 MapFramerErrorToProtocolError(SpdyFramer::SPDY_GOAWAY_FRAME_CORRUPT));
4558 CHECK_EQ(SPDY_ERROR_UNEXPECTED_FRAME,
4559 MapFramerErrorToProtocolError(SpdyFramer::SPDY_UNEXPECTED_FRAME));
4560 }
4561
TEST(MapFramerErrorToNetError,MapsValue)4562 TEST(MapFramerErrorToNetError, MapsValue) {
4563 CHECK_EQ(ERR_SPDY_PROTOCOL_ERROR,
4564 MapFramerErrorToNetError(SpdyFramer::SPDY_INVALID_CONTROL_FRAME));
4565 CHECK_EQ(ERR_SPDY_COMPRESSION_ERROR,
4566 MapFramerErrorToNetError(SpdyFramer::SPDY_COMPRESS_FAILURE));
4567 CHECK_EQ(ERR_SPDY_COMPRESSION_ERROR,
4568 MapFramerErrorToNetError(SpdyFramer::SPDY_DECOMPRESS_FAILURE));
4569 CHECK_EQ(
4570 ERR_SPDY_FRAME_SIZE_ERROR,
4571 MapFramerErrorToNetError(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE));
4572 }
4573
TEST(MapRstStreamStatusToProtocolError,MapsValues)4574 TEST(MapRstStreamStatusToProtocolError, MapsValues) {
4575 CHECK_EQ(STATUS_CODE_PROTOCOL_ERROR,
4576 MapRstStreamStatusToProtocolError(RST_STREAM_PROTOCOL_ERROR));
4577 CHECK_EQ(STATUS_CODE_FRAME_SIZE_ERROR,
4578 MapRstStreamStatusToProtocolError(RST_STREAM_FRAME_SIZE_ERROR));
4579 CHECK_EQ(STATUS_CODE_ENHANCE_YOUR_CALM,
4580 MapRstStreamStatusToProtocolError(RST_STREAM_ENHANCE_YOUR_CALM));
4581 }
4582
TEST(MapNetErrorToGoAwayStatus,MapsValue)4583 TEST(MapNetErrorToGoAwayStatus, MapsValue) {
4584 CHECK_EQ(GOAWAY_INADEQUATE_SECURITY,
4585 MapNetErrorToGoAwayStatus(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY));
4586 CHECK_EQ(GOAWAY_FLOW_CONTROL_ERROR,
4587 MapNetErrorToGoAwayStatus(ERR_SPDY_FLOW_CONTROL_ERROR));
4588 CHECK_EQ(GOAWAY_PROTOCOL_ERROR,
4589 MapNetErrorToGoAwayStatus(ERR_SPDY_PROTOCOL_ERROR));
4590 CHECK_EQ(GOAWAY_COMPRESSION_ERROR,
4591 MapNetErrorToGoAwayStatus(ERR_SPDY_COMPRESSION_ERROR));
4592 CHECK_EQ(GOAWAY_FRAME_SIZE_ERROR,
4593 MapNetErrorToGoAwayStatus(ERR_SPDY_FRAME_SIZE_ERROR));
4594 CHECK_EQ(GOAWAY_PROTOCOL_ERROR, MapNetErrorToGoAwayStatus(ERR_UNEXPECTED));
4595 }
4596
4597 } // namespace net
4598