Fix infinite recursion on hiding panel when created during fullscreen mode.
[chromium-blink-merge.git] / net / spdy / spdy_session_unittest.cc
bloba5d9292741c26ca45ba8f9c1a543b9a8a8da22ba
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.
5 #include "net/spdy/spdy_session.h"
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"
30 namespace net {
32 namespace {
34 static const char kTestUrl[] = "http://www.example.org/";
35 static const char kTestHost[] = "www.example.org";
36 static const int kTestPort = 80;
38 const char kBodyData[] = "Body data";
39 const size_t kBodyDataSize = arraysize(kBodyData);
40 const base::StringPiece kBodyDataStringPiece(kBodyData, kBodyDataSize);
42 static base::TimeDelta g_time_delta;
43 base::TimeTicks TheNearFuture() {
44 return base::TimeTicks::Now() + g_time_delta;
47 } // namespace
49 class SpdySessionTest : public PlatformTest,
50 public ::testing::WithParamInterface<NextProto> {
51 public:
52 // Functions used with RunResumeAfterUnstallTest().
54 void StallSessionOnly(SpdySession* session, SpdyStream* stream) {
55 StallSessionSend(session);
58 void StallStreamOnly(SpdySession* session, SpdyStream* stream) {
59 StallStreamSend(stream);
62 void StallSessionStream(SpdySession* session, SpdyStream* stream) {
63 StallSessionSend(session);
64 StallStreamSend(stream);
67 void StallStreamSession(SpdySession* session, SpdyStream* stream) {
68 StallStreamSend(stream);
69 StallSessionSend(session);
72 void UnstallSessionOnly(SpdySession* session,
73 SpdyStream* stream,
74 int32 delta_window_size) {
75 UnstallSessionSend(session, delta_window_size);
78 void UnstallStreamOnly(SpdySession* session,
79 SpdyStream* stream,
80 int32 delta_window_size) {
81 UnstallStreamSend(stream, 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);
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);
98 protected:
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 kPrivacyModeDisabled) {
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_);
122 virtual void SetUp() OVERRIDE {
123 g_time_delta = base::TimeDelta();
126 void CreateDeterministicNetworkSession() {
127 http_session_ =
128 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
129 spdy_session_pool_ = http_session_->spdy_session_pool();
132 void CreateNetworkSession() {
133 http_session_ =
134 SpdySessionDependencies::SpdyCreateSession(&session_deps_);
135 spdy_session_pool_ = http_session_->spdy_session_pool();
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_));
146 void UnstallSessionSend(SpdySession* session, int32 delta_window_size) {
147 session->IncreaseSendWindowSize(delta_window_size);
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()));
158 void UnstallStreamSend(SpdyStream* stream, int32 delta_window_size) {
159 stream->IncreaseSendWindowSize(delta_window_size);
162 void RunResumeAfterUnstallTest(
163 const base::Callback<void(SpdySession*, SpdyStream*)>& stall_function,
164 const base::Callback<void(SpdySession*, SpdyStream*, int32)>&
165 unstall_function);
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_;
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_;
181 INSTANTIATE_TEST_CASE_P(
182 NextProto,
183 SpdySessionTest,
184 testing::Values(kProtoDeprecatedSPDY2,
185 kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
186 kProtoHTTP2Draft04));
188 // Try to create a SPDY session that will fail during
189 // initialization. Nothing should blow up.
190 TEST_P(SpdySessionTest, InitialReadError) {
191 CreateDeterministicNetworkSession();
193 base::WeakPtr<SpdySession> session = TryCreateFakeSpdySessionExpectingFailure(
194 spdy_session_pool_, key_, ERR_FAILED);
195 EXPECT_TRUE(session);
196 // Flush the read.
197 base::RunLoop().RunUntilIdle();
198 EXPECT_FALSE(session);
201 namespace {
203 // A helper class that vends a callback that, when fired, destroys a
204 // given SpdyStreamRequest.
205 class StreamRequestDestroyingCallback : public TestCompletionCallbackBase {
206 public:
207 StreamRequestDestroyingCallback() {}
209 virtual ~StreamRequestDestroyingCallback() {}
211 void SetRequestToDestroy(scoped_ptr<SpdyStreamRequest> request) {
212 request_ = request.Pass();
215 CompletionCallback MakeCallback() {
216 return base::Bind(&StreamRequestDestroyingCallback::OnComplete,
217 base::Unretained(this));
220 private:
221 void OnComplete(int result) {
222 request_.reset();
223 SetResult(result);
226 scoped_ptr<SpdyStreamRequest> request_;
229 } // namespace
231 // Request kInitialMaxConcurrentStreams streams. Request two more
232 // streams, but have the callback for one destroy the second stream
233 // request. Close the session. Nothing should blow up. This is a
234 // regression test for http://crbug.com/250841 .
235 TEST_P(SpdySessionTest, PendingStreamCancellingAnother) {
236 session_deps_.host_resolver->set_synchronous_mode(true);
238 MockRead reads[] = {MockRead(ASYNC, 0, 0), };
240 DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
241 MockConnect connect_data(SYNCHRONOUS, OK);
242 data.set_connect_data(connect_data);
243 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
245 CreateDeterministicNetworkSession();
247 base::WeakPtr<SpdySession> session =
248 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
250 // Create the maximum number of concurrent streams.
251 for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
252 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
253 SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM, BoundNetLog());
254 ASSERT_TRUE(spdy_stream != NULL);
257 SpdyStreamRequest request1;
258 scoped_ptr<SpdyStreamRequest> request2(new SpdyStreamRequest);
260 StreamRequestDestroyingCallback callback1;
261 ASSERT_EQ(ERR_IO_PENDING,
262 request1.StartRequest(SPDY_BIDIRECTIONAL_STREAM,
263 session,
264 test_url_,
265 MEDIUM,
266 BoundNetLog(),
267 callback1.MakeCallback()));
269 // |callback2| is never called.
270 TestCompletionCallback callback2;
271 ASSERT_EQ(ERR_IO_PENDING,
272 request2->StartRequest(SPDY_BIDIRECTIONAL_STREAM,
273 session,
274 test_url_,
275 MEDIUM,
276 BoundNetLog(),
277 callback2.callback()));
279 callback1.SetRequestToDestroy(request2.Pass());
281 session->CloseSessionOnError(ERR_ABORTED, "Aborting session");
283 EXPECT_EQ(ERR_ABORTED, callback1.WaitForResult());
286 // A session receiving a GOAWAY frame with no active streams should
287 // immediately close.
288 TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) {
289 session_deps_.host_resolver->set_synchronous_mode(true);
291 MockConnect connect_data(SYNCHRONOUS, OK);
292 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
293 MockRead reads[] = {
294 CreateMockRead(*goaway, 0),
296 DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
297 data.set_connect_data(connect_data);
298 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
300 CreateDeterministicNetworkSession();
302 base::WeakPtr<SpdySession> session =
303 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
305 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
307 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
309 // Read and process the GOAWAY frame.
310 data.RunFor(1);
312 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
314 EXPECT_TRUE(session == NULL);
317 // A session receiving a GOAWAY frame immediately with no active
318 // streams should then close.
319 TEST_P(SpdySessionTest, GoAwayImmediatelyWithNoActiveStreams) {
320 session_deps_.host_resolver->set_synchronous_mode(true);
322 MockConnect connect_data(SYNCHRONOUS, OK);
323 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
324 MockRead reads[] = {
325 CreateMockRead(*goaway, 0, SYNCHRONOUS),
327 DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
328 data.set_connect_data(connect_data);
329 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
331 CreateDeterministicNetworkSession();
333 data.StopAfter(1);
335 base::WeakPtr<SpdySession> session =
336 TryCreateInsecureSpdySessionExpectingFailure(
337 http_session_, key_, ERR_CONNECTION_CLOSED, BoundNetLog());
338 base::RunLoop().RunUntilIdle();
340 EXPECT_FALSE(session);
341 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
344 // A session receiving a GOAWAY frame with active streams should close
345 // when the last active stream is closed.
346 TEST_P(SpdySessionTest, GoAwayWithActiveStreams) {
347 session_deps_.host_resolver->set_synchronous_mode(true);
349 MockConnect connect_data(SYNCHRONOUS, OK);
350 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
351 MockRead reads[] = {
352 CreateMockRead(*goaway, 2),
353 MockRead(ASYNC, 0, 3) // EOF
355 scoped_ptr<SpdyFrame> req1(
356 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
357 scoped_ptr<SpdyFrame> req2(
358 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
359 MockWrite writes[] = {
360 CreateMockWrite(*req1, 0),
361 CreateMockWrite(*req2, 1),
363 DeterministicSocketData data(reads, arraysize(reads),
364 writes, arraysize(writes));
365 data.set_connect_data(connect_data);
366 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
368 CreateDeterministicNetworkSession();
370 base::WeakPtr<SpdySession> session =
371 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
373 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
375 GURL url(kDefaultURL);
376 base::WeakPtr<SpdyStream> spdy_stream1 =
377 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
378 session, url, MEDIUM, BoundNetLog());
379 test::StreamDelegateDoNothing delegate1(spdy_stream1);
380 spdy_stream1->SetDelegate(&delegate1);
382 base::WeakPtr<SpdyStream> spdy_stream2 =
383 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
384 session, url, MEDIUM, BoundNetLog());
385 test::StreamDelegateDoNothing delegate2(spdy_stream2);
386 spdy_stream2->SetDelegate(&delegate2);
388 scoped_ptr<SpdyHeaderBlock> headers(
389 spdy_util_.ConstructGetHeaderBlock(url.spec()));
390 scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(*headers));
392 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
393 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
394 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
395 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
397 data.RunFor(2);
399 EXPECT_EQ(1u, spdy_stream1->stream_id());
400 EXPECT_EQ(3u, spdy_stream2->stream_id());
402 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
404 // Read and process the GOAWAY frame.
405 data.RunFor(1);
407 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
409 EXPECT_FALSE(session->IsStreamActive(3));
410 EXPECT_EQ(NULL, spdy_stream2.get());
411 EXPECT_TRUE(session->IsStreamActive(1));
413 EXPECT_FALSE(session->IsClosed());
415 // Should close the session.
416 spdy_stream1->Close();
417 EXPECT_EQ(NULL, spdy_stream1.get());
419 EXPECT_TRUE(session == NULL);
422 // Have a session receive two GOAWAY frames, with the last one causing
423 // the last active stream to be closed. The session should then be
424 // closed after the second GOAWAY frame.
425 TEST_P(SpdySessionTest, GoAwayTwice) {
426 session_deps_.host_resolver->set_synchronous_mode(true);
428 MockConnect connect_data(SYNCHRONOUS, OK);
429 scoped_ptr<SpdyFrame> goaway1(spdy_util_.ConstructSpdyGoAway(1));
430 scoped_ptr<SpdyFrame> goaway2(spdy_util_.ConstructSpdyGoAway(0));
431 MockRead reads[] = {
432 CreateMockRead(*goaway1, 2),
433 CreateMockRead(*goaway2, 3),
434 MockRead(ASYNC, 0, 4) // EOF
436 scoped_ptr<SpdyFrame> req1(
437 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
438 scoped_ptr<SpdyFrame> req2(
439 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
440 MockWrite writes[] = {
441 CreateMockWrite(*req1, 0),
442 CreateMockWrite(*req2, 1),
444 DeterministicSocketData data(reads, arraysize(reads),
445 writes, arraysize(writes));
446 data.set_connect_data(connect_data);
447 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
449 CreateDeterministicNetworkSession();
451 base::WeakPtr<SpdySession> session =
452 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
454 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
456 GURL url(kDefaultURL);
457 base::WeakPtr<SpdyStream> spdy_stream1 =
458 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
459 session, url, MEDIUM, BoundNetLog());
460 test::StreamDelegateDoNothing delegate1(spdy_stream1);
461 spdy_stream1->SetDelegate(&delegate1);
463 base::WeakPtr<SpdyStream> spdy_stream2 =
464 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
465 session, url, MEDIUM, BoundNetLog());
466 test::StreamDelegateDoNothing delegate2(spdy_stream2);
467 spdy_stream2->SetDelegate(&delegate2);
469 scoped_ptr<SpdyHeaderBlock> headers(
470 spdy_util_.ConstructGetHeaderBlock(url.spec()));
471 scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(*headers));
473 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
474 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
475 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
476 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
478 data.RunFor(2);
480 EXPECT_EQ(1u, spdy_stream1->stream_id());
481 EXPECT_EQ(3u, spdy_stream2->stream_id());
483 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
485 // Read and process the first GOAWAY frame.
486 data.RunFor(1);
488 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
490 EXPECT_FALSE(session->IsStreamActive(3));
491 EXPECT_EQ(NULL, spdy_stream2.get());
492 EXPECT_TRUE(session->IsStreamActive(1));
494 EXPECT_FALSE(session->IsClosed());
496 // Read and process the second GOAWAY frame, which should close the
497 // session.
498 data.RunFor(1);
500 EXPECT_TRUE(session == NULL);
503 // Have a session with active streams receive a GOAWAY frame and then
504 // close it. It should handle the close properly (i.e., not try to
505 // make itself unavailable in its pool twice).
506 TEST_P(SpdySessionTest, GoAwayWithActiveStreamsThenClose) {
507 session_deps_.host_resolver->set_synchronous_mode(true);
509 MockConnect connect_data(SYNCHRONOUS, OK);
510 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
511 MockRead reads[] = {
512 CreateMockRead(*goaway, 2),
513 MockRead(ASYNC, 0, 3) // EOF
515 scoped_ptr<SpdyFrame> req1(
516 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
517 scoped_ptr<SpdyFrame> req2(
518 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
519 MockWrite writes[] = {
520 CreateMockWrite(*req1, 0),
521 CreateMockWrite(*req2, 1),
523 DeterministicSocketData data(reads, arraysize(reads),
524 writes, arraysize(writes));
525 data.set_connect_data(connect_data);
526 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
528 CreateDeterministicNetworkSession();
530 base::WeakPtr<SpdySession> session =
531 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
533 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
535 GURL url(kDefaultURL);
536 base::WeakPtr<SpdyStream> spdy_stream1 =
537 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
538 session, url, MEDIUM, BoundNetLog());
539 test::StreamDelegateDoNothing delegate1(spdy_stream1);
540 spdy_stream1->SetDelegate(&delegate1);
542 base::WeakPtr<SpdyStream> spdy_stream2 =
543 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
544 session, url, MEDIUM, BoundNetLog());
545 test::StreamDelegateDoNothing delegate2(spdy_stream2);
546 spdy_stream2->SetDelegate(&delegate2);
548 scoped_ptr<SpdyHeaderBlock> headers(
549 spdy_util_.ConstructGetHeaderBlock(url.spec()));
550 scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(*headers));
552 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
553 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
554 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
555 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
557 data.RunFor(2);
559 EXPECT_EQ(1u, spdy_stream1->stream_id());
560 EXPECT_EQ(3u, spdy_stream2->stream_id());
562 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
564 // Read and process the GOAWAY frame.
565 data.RunFor(1);
567 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
569 EXPECT_FALSE(session->IsStreamActive(3));
570 EXPECT_EQ(NULL, spdy_stream2.get());
571 EXPECT_TRUE(session->IsStreamActive(1));
573 EXPECT_FALSE(session->IsClosed());
575 session->CloseSessionOnError(ERR_ABORTED, "Aborting session");
577 EXPECT_EQ(NULL, spdy_stream1.get());
578 EXPECT_TRUE(session == NULL);
581 // Try to create a stream after receiving a GOAWAY frame. It should
582 // fail.
583 TEST_P(SpdySessionTest, CreateStreamAfterGoAway) {
584 session_deps_.host_resolver->set_synchronous_mode(true);
586 MockConnect connect_data(SYNCHRONOUS, OK);
587 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
588 MockRead reads[] = {
589 CreateMockRead(*goaway, 1),
590 MockRead(ASYNC, 0, 2) // EOF
592 scoped_ptr<SpdyFrame> req(
593 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
594 MockWrite writes[] = {
595 CreateMockWrite(*req, 0),
597 DeterministicSocketData data(reads, arraysize(reads),
598 writes, arraysize(writes));
599 data.set_connect_data(connect_data);
600 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
602 CreateDeterministicNetworkSession();
604 base::WeakPtr<SpdySession> session =
605 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
607 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
609 GURL url(kDefaultURL);
610 base::WeakPtr<SpdyStream> spdy_stream =
611 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
612 session, url, MEDIUM, BoundNetLog());
613 test::StreamDelegateDoNothing delegate(spdy_stream);
614 spdy_stream->SetDelegate(&delegate);
616 scoped_ptr<SpdyHeaderBlock> headers(
617 spdy_util_.ConstructGetHeaderBlock(url.spec()));
618 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
619 EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
621 data.RunFor(1);
623 EXPECT_EQ(1u, spdy_stream->stream_id());
625 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
627 // Read and process the GOAWAY frame.
628 data.RunFor(1);
630 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
631 EXPECT_TRUE(session->IsStreamActive(1));
633 SpdyStreamRequest stream_request;
634 int rv = stream_request.StartRequest(
635 SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog(),
636 CompletionCallback());
637 EXPECT_EQ(ERR_FAILED, rv);
639 // Read and process EOF.
640 data.RunFor(1);
642 EXPECT_TRUE(session == NULL);
645 // Receiving a SYN_STREAM frame after a GOAWAY frame should result in
646 // the stream being refused.
647 TEST_P(SpdySessionTest, SynStreamAfterGoAway) {
648 session_deps_.host_resolver->set_synchronous_mode(true);
650 MockConnect connect_data(SYNCHRONOUS, OK);
651 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
652 scoped_ptr<SpdyFrame>
653 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kDefaultURL));
654 MockRead reads[] = {
655 CreateMockRead(*goaway, 1),
656 CreateMockRead(*push, 2),
657 MockRead(ASYNC, 0, 4) // EOF
659 scoped_ptr<SpdyFrame> req(
660 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
661 scoped_ptr<SpdyFrame> rst(
662 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
663 MockWrite writes[] = {
664 CreateMockWrite(*req, 0),
665 CreateMockWrite(*rst, 3)
667 DeterministicSocketData data(reads, arraysize(reads),
668 writes, arraysize(writes));
669 data.set_connect_data(connect_data);
670 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
672 CreateDeterministicNetworkSession();
674 base::WeakPtr<SpdySession> session =
675 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
677 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
679 GURL url(kDefaultURL);
680 base::WeakPtr<SpdyStream> spdy_stream =
681 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
682 session, url, MEDIUM, BoundNetLog());
683 test::StreamDelegateDoNothing delegate(spdy_stream);
684 spdy_stream->SetDelegate(&delegate);
686 scoped_ptr<SpdyHeaderBlock> headers(
687 spdy_util_.ConstructGetHeaderBlock(url.spec()));
688 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
689 EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
691 data.RunFor(1);
693 EXPECT_EQ(1u, spdy_stream->stream_id());
695 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
697 // Read and process the GOAWAY frame.
698 data.RunFor(1);
700 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
701 EXPECT_TRUE(session->IsStreamActive(1));
703 // Read and process the SYN_STREAM frame, the subsequent RST_STREAM,
704 // and EOF.
705 data.RunFor(3);
707 EXPECT_TRUE(session == NULL);
710 // A session observing a network change with active streams should close
711 // when the last active stream is closed.
712 TEST_P(SpdySessionTest, NetworkChangeWithActiveStreams) {
713 session_deps_.host_resolver->set_synchronous_mode(true);
715 MockConnect connect_data(SYNCHRONOUS, OK);
716 MockRead reads[] = {
717 MockRead(ASYNC, 0, 1) // EOF
719 scoped_ptr<SpdyFrame> req1(
720 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
721 MockWrite writes[] = {
722 CreateMockWrite(*req1, 0),
724 DeterministicSocketData data(reads, arraysize(reads),
725 writes, arraysize(writes));
726 data.set_connect_data(connect_data);
727 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
729 CreateDeterministicNetworkSession();
731 base::WeakPtr<SpdySession> session =
732 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
734 EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
736 base::WeakPtr<SpdyStream> spdy_stream =
737 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session,
738 GURL(kDefaultURL), MEDIUM, BoundNetLog());
739 test::StreamDelegateDoNothing delegate(spdy_stream);
740 spdy_stream->SetDelegate(&delegate);
742 scoped_ptr<SpdyHeaderBlock> headers(
743 spdy_util_.ConstructGetHeaderBlock(kDefaultURL));
745 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
746 EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
748 data.RunFor(1);
750 EXPECT_EQ(1u, spdy_stream->stream_id());
752 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
754 spdy_session_pool_->OnIPAddressChanged();
756 // The SpdySessionPool behavior differs based on how the OSs reacts to
757 // network changes; see comment in SpdySessionPool::OnIPAddressChanged().
758 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
759 // For OSs where the TCP connections will close upon relevant network
760 // changes, SpdySessionPool doesn't need to force them to close, so in these
761 // cases verify the session has become unavailable but remains open and the
762 // pre-existing stream is still active.
763 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
765 EXPECT_FALSE(session->IsClosed());
767 EXPECT_TRUE(session->IsStreamActive(1));
769 // Should close the session.
770 spdy_stream->Close();
771 #endif
772 EXPECT_EQ(NULL, spdy_stream.get());
774 EXPECT_TRUE(session == NULL);
777 TEST_P(SpdySessionTest, ClientPing) {
778 session_deps_.enable_ping = true;
779 session_deps_.host_resolver->set_synchronous_mode(true);
781 MockConnect connect_data(SYNCHRONOUS, OK);
782 scoped_ptr<SpdyFrame> read_ping(spdy_util_.ConstructSpdyPing(1, true));
783 MockRead reads[] = {
784 CreateMockRead(*read_ping, 1),
785 MockRead(ASYNC, 0, 0, 2) // EOF
787 scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false));
788 MockWrite writes[] = {
789 CreateMockWrite(*write_ping, 0),
791 DeterministicSocketData data(
792 reads, arraysize(reads), writes, arraysize(writes));
793 data.set_connect_data(connect_data);
794 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
796 CreateDeterministicNetworkSession();
798 base::WeakPtr<SpdySession> session =
799 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
801 base::WeakPtr<SpdyStream> spdy_stream1 =
802 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
803 session, test_url_, MEDIUM, BoundNetLog());
804 ASSERT_TRUE(spdy_stream1.get() != NULL);
805 test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL);
806 spdy_stream1->SetDelegate(&delegate);
808 base::TimeTicks before_ping_time = base::TimeTicks::Now();
810 session->set_connection_at_risk_of_loss_time(
811 base::TimeDelta::FromSeconds(-1));
812 session->set_hung_interval(base::TimeDelta::FromMilliseconds(50));
814 session->SendPrefacePingIfNoneInFlight();
816 data.RunFor(2);
818 session->CheckPingStatus(before_ping_time);
820 EXPECT_EQ(0, session->pings_in_flight());
821 EXPECT_GE(session->next_ping_id(), static_cast<uint32>(1));
822 EXPECT_FALSE(session->check_ping_status_pending());
823 EXPECT_GE(session->last_activity_time(), before_ping_time);
825 data.RunFor(1);
827 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
829 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
830 EXPECT_TRUE(session == NULL);
833 TEST_P(SpdySessionTest, ServerPing) {
834 session_deps_.host_resolver->set_synchronous_mode(true);
836 MockConnect connect_data(SYNCHRONOUS, OK);
837 scoped_ptr<SpdyFrame> read_ping(spdy_util_.ConstructSpdyPing(2, false));
838 MockRead reads[] = {
839 CreateMockRead(*read_ping),
840 MockRead(SYNCHRONOUS, 0, 0) // EOF
842 scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(2, true));
843 MockWrite writes[] = {
844 CreateMockWrite(*write_ping),
846 StaticSocketDataProvider data(
847 reads, arraysize(reads), writes, arraysize(writes));
848 data.set_connect_data(connect_data);
849 session_deps_.socket_factory->AddSocketDataProvider(&data);
851 CreateNetworkSession();
853 base::WeakPtr<SpdySession> session =
854 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
856 base::WeakPtr<SpdyStream> spdy_stream1 =
857 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
858 session, test_url_, MEDIUM, BoundNetLog());
859 ASSERT_TRUE(spdy_stream1.get() != NULL);
860 test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL);
861 spdy_stream1->SetDelegate(&delegate);
863 // Flush the read completion task.
864 base::MessageLoop::current()->RunUntilIdle();
866 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
868 EXPECT_TRUE(session == NULL);
869 EXPECT_EQ(NULL, spdy_stream1.get());
872 // Cause a ping to be sent out while producing a write. The write loop
873 // should handle this properly, i.e. another DoWriteLoop task should
874 // not be posted. This is a regression test for
875 // http://crbug.com/261043 .
876 TEST_P(SpdySessionTest, PingAndWriteLoop) {
877 session_deps_.enable_ping = true;
878 session_deps_.time_func = TheNearFuture;
880 MockConnect connect_data(SYNCHRONOUS, OK);
881 scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false));
882 scoped_ptr<SpdyFrame> req(
883 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
884 MockWrite writes[] = {
885 CreateMockWrite(*req, 0),
886 CreateMockWrite(*write_ping, 1),
889 MockRead reads[] = {
890 MockRead(ASYNC, 0, 2) // EOF
893 session_deps_.host_resolver->set_synchronous_mode(true);
895 DeterministicSocketData data(reads, arraysize(reads),
896 writes, arraysize(writes));
897 data.set_connect_data(connect_data);
898 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
900 CreateDeterministicNetworkSession();
902 base::WeakPtr<SpdySession> session =
903 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
905 GURL url(kDefaultURL);
906 base::WeakPtr<SpdyStream> spdy_stream =
907 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
908 session, url, LOWEST, BoundNetLog());
909 test::StreamDelegateDoNothing delegate(spdy_stream);
910 spdy_stream->SetDelegate(&delegate);
912 scoped_ptr<SpdyHeaderBlock> headers(
913 spdy_util_.ConstructGetHeaderBlock(url.spec()));
914 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
916 // Shift time so that a ping will be sent out.
917 g_time_delta = base::TimeDelta::FromSeconds(11);
919 data.RunFor(2);
921 session->CloseSessionOnError(ERR_ABORTED, "Aborting");
924 TEST_P(SpdySessionTest, DeleteExpiredPushStreams) {
925 session_deps_.host_resolver->set_synchronous_mode(true);
926 session_deps_.time_func = TheNearFuture;
928 scoped_ptr<SpdyFrame> req(
929 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
930 scoped_ptr<SpdyFrame> rst(
931 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
933 scoped_ptr<SpdyFrame> push_a(spdy_util_.ConstructSpdyPush(
934 NULL, 0, 2, 1, "http://www.google.com/a.dat"));
935 scoped_ptr<SpdyFrame> push_a_body(
936 spdy_util_.ConstructSpdyBodyFrame(2, false));
937 scoped_ptr<SpdyFrame> push_b(spdy_util_.ConstructSpdyPush(
938 NULL, 0, 4, 1, "http://www.google.com/b.dat"));
939 MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4)};
940 MockRead reads[] = {
941 CreateMockRead(*push_a, 1), CreateMockRead(*push_a_body, 2),
942 CreateMockRead(*push_b, 3), MockRead(ASYNC, 0, 5), // EOF
944 DeterministicSocketData data(
945 reads, arraysize(reads), writes, arraysize(writes));
947 MockConnect connect_data(SYNCHRONOUS, OK);
948 data.set_connect_data(connect_data);
949 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
951 CreateDeterministicNetworkSession();
952 base::WeakPtr<SpdySession> session =
953 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
955 // Process the principal request, and the first push stream request & body.
956 GURL url(kDefaultURL);
957 base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
958 SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
959 test::StreamDelegateDoNothing delegate(spdy_stream);
960 spdy_stream->SetDelegate(&delegate);
962 scoped_ptr<SpdyHeaderBlock> headers(
963 spdy_util_.ConstructGetHeaderBlock(url.spec()));
964 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
966 data.RunFor(3);
968 // Verify that there is one unclaimed push stream.
969 EXPECT_EQ(1u, session->num_unclaimed_pushed_streams());
970 SpdySession::PushedStreamMap::iterator iter =
971 session->unclaimed_pushed_streams_.find(
972 GURL("http://www.google.com/a.dat"));
973 EXPECT_TRUE(session->unclaimed_pushed_streams_.end() != iter);
975 if (session->flow_control_state_ ==
976 SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) {
977 // Unclaimed push body consumed bytes from the session window.
978 EXPECT_EQ(kSpdySessionInitialWindowSize - kUploadDataSize,
979 session->session_recv_window_size_);
980 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
983 // Shift time to expire the push stream. Read the second SYN_STREAM,
984 // and verify a RST_STREAM was written.
985 g_time_delta = base::TimeDelta::FromSeconds(301);
986 data.RunFor(2);
988 // Verify that the second pushed stream evicted the first pushed stream.
989 EXPECT_EQ(1u, session->num_unclaimed_pushed_streams());
990 iter = session->unclaimed_pushed_streams_.find(
991 GURL("http://www.google.com/b.dat"));
992 EXPECT_TRUE(session->unclaimed_pushed_streams_.end() != iter);
994 if (session->flow_control_state_ ==
995 SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) {
996 // Verify that the session window reclaimed the evicted stream body.
997 EXPECT_EQ(kSpdySessionInitialWindowSize,
998 session->session_recv_window_size_);
999 EXPECT_EQ(kUploadDataSize, session->session_unacked_recv_window_bytes_);
1002 // Read and process EOF.
1003 data.RunFor(1);
1004 EXPECT_TRUE(session == NULL);
1007 TEST_P(SpdySessionTest, FailedPing) {
1008 session_deps_.host_resolver->set_synchronous_mode(true);
1010 MockConnect connect_data(SYNCHRONOUS, OK);
1011 MockRead reads[] = {
1012 MockRead(ASYNC, 0, 0, 0) // EOF
1014 scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false));
1015 DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
1016 data.set_connect_data(connect_data);
1017 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1019 CreateDeterministicNetworkSession();
1021 base::WeakPtr<SpdySession> session =
1022 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1024 base::WeakPtr<SpdyStream> spdy_stream1 =
1025 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1026 session, test_url_, MEDIUM, BoundNetLog());
1027 ASSERT_TRUE(spdy_stream1.get() != NULL);
1028 test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL);
1029 spdy_stream1->SetDelegate(&delegate);
1031 session->set_connection_at_risk_of_loss_time(base::TimeDelta::FromSeconds(0));
1032 session->set_hung_interval(base::TimeDelta::FromSeconds(0));
1034 // Send a PING frame.
1035 session->WritePingFrame(1, false);
1036 EXPECT_LT(0, session->pings_in_flight());
1037 EXPECT_GE(session->next_ping_id(), static_cast<uint32>(1));
1038 EXPECT_TRUE(session->check_ping_status_pending());
1040 // Assert session is not closed.
1041 EXPECT_FALSE(session->IsClosed());
1042 EXPECT_LT(0u, session->num_active_streams() + session->num_created_streams());
1043 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
1045 // We set last time we have received any data in 1 sec less than now.
1046 // CheckPingStatus will trigger timeout because hung interval is zero.
1047 base::TimeTicks now = base::TimeTicks::Now();
1048 session->last_activity_time_ = now - base::TimeDelta::FromSeconds(1);
1049 session->CheckPingStatus(now);
1051 EXPECT_TRUE(session == NULL);
1052 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
1053 EXPECT_EQ(NULL, spdy_stream1.get());
1056 // Request kInitialMaxConcurrentStreams + 1 streams. Receive a
1057 // settings frame increasing the max concurrent streams by 1. Make
1058 // sure nothing blows up. This is a regression test for
1059 // http://crbug.com/57331 .
1060 TEST_P(SpdySessionTest, OnSettings) {
1061 session_deps_.host_resolver->set_synchronous_mode(true);
1063 const SpdySettingsIds kSpdySettingsIds = SETTINGS_MAX_CONCURRENT_STREAMS;
1065 SettingsMap new_settings;
1066 const uint32 max_concurrent_streams = kInitialMaxConcurrentStreams + 1;
1067 new_settings[kSpdySettingsIds] =
1068 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1069 scoped_ptr<SpdyFrame> settings_frame(
1070 spdy_util_.ConstructSpdySettings(new_settings));
1071 MockRead reads[] = {
1072 CreateMockRead(*settings_frame, 0),
1073 MockRead(ASYNC, 0, 1),
1076 DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
1077 MockConnect connect_data(SYNCHRONOUS, OK);
1078 data.set_connect_data(connect_data);
1079 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1081 CreateDeterministicNetworkSession();
1083 base::WeakPtr<SpdySession> session =
1084 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1086 // Create the maximum number of concurrent streams.
1087 for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
1088 base::WeakPtr<SpdyStream> spdy_stream =
1089 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1090 session, test_url_, MEDIUM, BoundNetLog());
1091 ASSERT_TRUE(spdy_stream != NULL);
1094 StreamReleaserCallback stream_releaser;
1095 SpdyStreamRequest request;
1096 ASSERT_EQ(ERR_IO_PENDING,
1097 request.StartRequest(
1098 SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM,
1099 BoundNetLog(),
1100 stream_releaser.MakeCallback(&request)));
1102 data.RunFor(1);
1104 EXPECT_EQ(OK, stream_releaser.WaitForResult());
1106 data.RunFor(1);
1107 EXPECT_TRUE(session == NULL);
1110 // Start with a persisted value for max concurrent streams. Receive a
1111 // settings frame increasing the max concurrent streams by 1 and which
1112 // also clears the persisted data. Verify that persisted data is
1113 // correct.
1114 TEST_P(SpdySessionTest, ClearSettings) {
1115 if (spdy_util_.spdy_version() >= SPDY4) {
1116 // SPDY4 doesn't include settings persistence, or a CLEAR_SETTINGS flag.
1117 // Flag 0x1, CLEAR_SETTINGS in SPDY3, is instead settings ACK in SPDY4.
1118 return;
1120 session_deps_.host_resolver->set_synchronous_mode(true);
1122 SettingsMap new_settings;
1123 const uint32 max_concurrent_streams = kInitialMaxConcurrentStreams + 1;
1124 new_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1125 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
1126 scoped_ptr<SpdyFrame> settings_frame(
1127 spdy_util_.ConstructSpdySettings(new_settings));
1128 uint8 flags = SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS;
1129 test::SetFrameFlags(settings_frame.get(), flags, spdy_util_.spdy_version());
1130 MockRead reads[] = {
1131 CreateMockRead(*settings_frame, 0),
1132 MockRead(ASYNC, 0, 1),
1135 DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
1136 MockConnect connect_data(SYNCHRONOUS, OK);
1137 data.set_connect_data(connect_data);
1138 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1140 CreateDeterministicNetworkSession();
1142 // Initialize the SpdySetting with the default.
1143 spdy_session_pool_->http_server_properties()->SetSpdySetting(
1144 test_host_port_pair_,
1145 SETTINGS_MAX_CONCURRENT_STREAMS,
1146 SETTINGS_FLAG_PLEASE_PERSIST,
1147 kInitialMaxConcurrentStreams);
1149 EXPECT_FALSE(
1150 spdy_session_pool_->http_server_properties()->GetSpdySettings(
1151 test_host_port_pair_).empty());
1153 base::WeakPtr<SpdySession> session =
1154 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1156 // Create the maximum number of concurrent streams.
1157 for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
1158 base::WeakPtr<SpdyStream> spdy_stream =
1159 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1160 session, test_url_, MEDIUM, BoundNetLog());
1161 ASSERT_TRUE(spdy_stream != NULL);
1164 StreamReleaserCallback stream_releaser;
1166 SpdyStreamRequest request;
1167 ASSERT_EQ(ERR_IO_PENDING,
1168 request.StartRequest(
1169 SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM,
1170 BoundNetLog(),
1171 stream_releaser.MakeCallback(&request)));
1173 data.RunFor(1);
1175 EXPECT_EQ(OK, stream_releaser.WaitForResult());
1177 // Make sure that persisted data is cleared.
1178 EXPECT_TRUE(
1179 spdy_session_pool_->http_server_properties()->GetSpdySettings(
1180 test_host_port_pair_).empty());
1182 // Make sure session's max_concurrent_streams is correct.
1183 EXPECT_EQ(kInitialMaxConcurrentStreams + 1,
1184 session->max_concurrent_streams());
1186 data.RunFor(1);
1187 EXPECT_TRUE(session == NULL);
1190 // Start with max concurrent streams set to 1. Request two streams.
1191 // When the first completes, have the callback close its stream, which
1192 // should trigger the second stream creation. Then cancel that one
1193 // immediately. Don't crash. This is a regression test for
1194 // http://crbug.com/63532 .
1195 TEST_P(SpdySessionTest, CancelPendingCreateStream) {
1196 session_deps_.host_resolver->set_synchronous_mode(true);
1198 MockRead reads[] = {
1199 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
1202 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
1203 MockConnect connect_data(SYNCHRONOUS, OK);
1205 data.set_connect_data(connect_data);
1206 session_deps_.socket_factory->AddSocketDataProvider(&data);
1208 CreateNetworkSession();
1210 // Initialize the SpdySetting with 1 max concurrent streams.
1211 spdy_session_pool_->http_server_properties()->SetSpdySetting(
1212 test_host_port_pair_,
1213 SETTINGS_MAX_CONCURRENT_STREAMS,
1214 SETTINGS_FLAG_PLEASE_PERSIST,
1217 base::WeakPtr<SpdySession> session =
1218 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1220 // Leave room for only one more stream to be created.
1221 for (size_t i = 0; i < kInitialMaxConcurrentStreams - 1; ++i) {
1222 base::WeakPtr<SpdyStream> spdy_stream =
1223 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1224 session, test_url_, MEDIUM, BoundNetLog());
1225 ASSERT_TRUE(spdy_stream != NULL);
1228 // Create 2 more streams. First will succeed. Second will be pending.
1229 base::WeakPtr<SpdyStream> spdy_stream1 =
1230 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1231 session, test_url_, MEDIUM, BoundNetLog());
1232 ASSERT_TRUE(spdy_stream1.get() != NULL);
1234 // Use scoped_ptr to let us invalidate the memory when we want to, to trigger
1235 // a valgrind error if the callback is invoked when it's not supposed to be.
1236 scoped_ptr<TestCompletionCallback> callback(new TestCompletionCallback);
1238 SpdyStreamRequest request;
1239 ASSERT_EQ(ERR_IO_PENDING,
1240 request.StartRequest(
1241 SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM,
1242 BoundNetLog(),
1243 callback->callback()));
1245 // Release the first one, this will allow the second to be created.
1246 spdy_stream1->Cancel();
1247 EXPECT_EQ(NULL, spdy_stream1.get());
1249 request.CancelRequest();
1250 callback.reset();
1252 // Should not crash when running the pending callback.
1253 base::MessageLoop::current()->RunUntilIdle();
1256 TEST_P(SpdySessionTest, SendInitialDataOnNewSession) {
1257 session_deps_.host_resolver->set_synchronous_mode(true);
1259 MockRead reads[] = {
1260 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
1263 SettingsMap settings;
1264 const SpdySettingsIds kSpdySettingsIds1 = SETTINGS_MAX_CONCURRENT_STREAMS;
1265 const SpdySettingsIds kSpdySettingsIds2 = SETTINGS_INITIAL_WINDOW_SIZE;
1266 const uint32 kInitialRecvWindowSize = 10 * 1024 * 1024;
1267 settings[kSpdySettingsIds1] =
1268 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
1269 if (spdy_util_.spdy_version() >= SPDY3) {
1270 settings[kSpdySettingsIds2] =
1271 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kInitialRecvWindowSize);
1273 MockConnect connect_data(SYNCHRONOUS, OK);
1274 scoped_ptr<SpdyFrame> settings_frame(
1275 spdy_util_.ConstructSpdySettings(settings));
1276 scoped_ptr<SpdyFrame> initial_window_update(
1277 spdy_util_.ConstructSpdyWindowUpdate(
1278 kSessionFlowControlStreamId,
1279 kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
1280 std::vector<MockWrite> writes;
1281 if (GetParam() == kProtoHTTP2Draft04) {
1282 writes.push_back(
1283 MockWrite(ASYNC,
1284 kHttp2ConnectionHeaderPrefix,
1285 kHttp2ConnectionHeaderPrefixSize));
1287 writes.push_back(CreateMockWrite(*settings_frame));
1288 if (GetParam() >= kProtoSPDY31) {
1289 writes.push_back(CreateMockWrite(*initial_window_update));
1292 SettingsMap server_settings;
1293 const uint32 initial_max_concurrent_streams = 1;
1294 server_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
1295 SettingsFlagsAndValue(SETTINGS_FLAG_PERSISTED,
1296 initial_max_concurrent_streams);
1297 scoped_ptr<SpdyFrame> server_settings_frame(
1298 spdy_util_.ConstructSpdySettings(server_settings));
1299 writes.push_back(CreateMockWrite(*server_settings_frame));
1301 session_deps_.stream_initial_recv_window_size = kInitialRecvWindowSize;
1303 StaticSocketDataProvider data(reads, arraysize(reads),
1304 vector_as_array(&writes), writes.size());
1305 data.set_connect_data(connect_data);
1306 session_deps_.socket_factory->AddSocketDataProvider(&data);
1308 CreateNetworkSession();
1310 spdy_session_pool_->http_server_properties()->SetSpdySetting(
1311 test_host_port_pair_,
1312 SETTINGS_MAX_CONCURRENT_STREAMS,
1313 SETTINGS_FLAG_PLEASE_PERSIST,
1314 initial_max_concurrent_streams);
1316 SpdySessionPoolPeer pool_peer(spdy_session_pool_);
1317 pool_peer.SetEnableSendingInitialData(true);
1319 base::WeakPtr<SpdySession> session =
1320 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1322 base::MessageLoop::current()->RunUntilIdle();
1323 EXPECT_TRUE(data.at_write_eof());
1326 TEST_P(SpdySessionTest, ClearSettingsStorageOnIPAddressChanged) {
1327 CreateNetworkSession();
1329 base::WeakPtr<HttpServerProperties> test_http_server_properties =
1330 spdy_session_pool_->http_server_properties();
1331 SettingsFlagsAndValue flags_and_value1(SETTINGS_FLAG_PLEASE_PERSIST, 2);
1332 test_http_server_properties->SetSpdySetting(
1333 test_host_port_pair_,
1334 SETTINGS_MAX_CONCURRENT_STREAMS,
1335 SETTINGS_FLAG_PLEASE_PERSIST,
1337 EXPECT_NE(0u, test_http_server_properties->GetSpdySettings(
1338 test_host_port_pair_).size());
1339 spdy_session_pool_->OnIPAddressChanged();
1340 EXPECT_EQ(0u, test_http_server_properties->GetSpdySettings(
1341 test_host_port_pair_).size());
1344 TEST_P(SpdySessionTest, Initialize) {
1345 CapturingBoundNetLog log;
1346 session_deps_.net_log = log.bound().net_log();
1347 session_deps_.host_resolver->set_synchronous_mode(true);
1349 MockConnect connect_data(SYNCHRONOUS, OK);
1350 MockRead reads[] = {
1351 MockRead(ASYNC, 0, 0) // EOF
1354 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
1355 data.set_connect_data(connect_data);
1356 session_deps_.socket_factory->AddSocketDataProvider(&data);
1358 CreateNetworkSession();
1360 base::WeakPtr<SpdySession> session =
1361 CreateInsecureSpdySession(http_session_, key_, log.bound());
1362 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
1364 // Flush the read completion task.
1365 base::MessageLoop::current()->RunUntilIdle();
1367 net::CapturingNetLog::CapturedEntryList entries;
1368 log.GetEntries(&entries);
1369 EXPECT_LT(0u, entries.size());
1371 // Check that we logged TYPE_SPDY_SESSION_INITIALIZED correctly.
1372 int pos = net::ExpectLogContainsSomewhere(
1373 entries, 0,
1374 net::NetLog::TYPE_SPDY_SESSION_INITIALIZED,
1375 net::NetLog::PHASE_NONE);
1376 EXPECT_LT(0, pos);
1378 CapturingNetLog::CapturedEntry entry = entries[pos];
1379 NetLog::Source socket_source;
1380 EXPECT_TRUE(NetLog::Source::FromEventParameters(entry.params.get(),
1381 &socket_source));
1382 EXPECT_TRUE(socket_source.IsValid());
1383 EXPECT_NE(log.bound().source().id, socket_source.id);
1386 TEST_P(SpdySessionTest, CloseSessionOnError) {
1387 session_deps_.host_resolver->set_synchronous_mode(true);
1389 MockConnect connect_data(SYNCHRONOUS, OK);
1390 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway());
1391 MockRead reads[] = {
1392 CreateMockRead(*goaway),
1393 MockRead(SYNCHRONOUS, 0, 0) // EOF
1396 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
1397 data.set_connect_data(connect_data);
1398 session_deps_.socket_factory->AddSocketDataProvider(&data);
1400 CreateNetworkSession();
1402 CapturingBoundNetLog log;
1403 base::WeakPtr<SpdySession> session =
1404 CreateInsecureSpdySession(http_session_, key_, log.bound());
1405 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
1407 // Flush the read completion task.
1408 base::MessageLoop::current()->RunUntilIdle();
1410 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
1411 EXPECT_TRUE(session == NULL);
1413 // Check that the NetLog was filled reasonably.
1414 net::CapturingNetLog::CapturedEntryList entries;
1415 log.GetEntries(&entries);
1416 EXPECT_LT(0u, entries.size());
1418 // Check that we logged SPDY_SESSION_CLOSE correctly.
1419 int pos = net::ExpectLogContainsSomewhere(
1420 entries, 0,
1421 net::NetLog::TYPE_SPDY_SESSION_CLOSE,
1422 net::NetLog::PHASE_NONE);
1424 if (pos < static_cast<int>(entries.size())) {
1425 CapturingNetLog::CapturedEntry entry = entries[pos];
1426 int error_code = 0;
1427 ASSERT_TRUE(entry.GetNetErrorCode(&error_code));
1428 EXPECT_EQ(ERR_CONNECTION_CLOSED, error_code);
1429 } else {
1430 ADD_FAILURE();
1434 // Queue up a low-priority SYN_STREAM followed by a high-priority
1435 // one. The high priority one should still send first and receive
1436 // first.
1437 TEST_P(SpdySessionTest, OutOfOrderSynStreams) {
1438 // Construct the request.
1439 MockConnect connect_data(SYNCHRONOUS, OK);
1440 scoped_ptr<SpdyFrame> req_highest(
1441 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, HIGHEST, true));
1442 scoped_ptr<SpdyFrame> req_lowest(
1443 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
1444 MockWrite writes[] = {
1445 CreateMockWrite(*req_highest, 0),
1446 CreateMockWrite(*req_lowest, 1),
1449 scoped_ptr<SpdyFrame> resp_highest(
1450 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1451 scoped_ptr<SpdyFrame> body_highest(
1452 spdy_util_.ConstructSpdyBodyFrame(1, true));
1453 scoped_ptr<SpdyFrame> resp_lowest(
1454 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
1455 scoped_ptr<SpdyFrame> body_lowest(
1456 spdy_util_.ConstructSpdyBodyFrame(3, true));
1457 MockRead reads[] = {
1458 CreateMockRead(*resp_highest, 2),
1459 CreateMockRead(*body_highest, 3),
1460 CreateMockRead(*resp_lowest, 4),
1461 CreateMockRead(*body_lowest, 5),
1462 MockRead(ASYNC, 0, 6) // EOF
1465 session_deps_.host_resolver->set_synchronous_mode(true);
1467 DeterministicSocketData data(reads, arraysize(reads),
1468 writes, arraysize(writes));
1469 data.set_connect_data(connect_data);
1470 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1472 CreateDeterministicNetworkSession();
1474 base::WeakPtr<SpdySession> session =
1475 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1477 GURL url(kDefaultURL);
1479 base::WeakPtr<SpdyStream> spdy_stream_lowest =
1480 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1481 session, url, LOWEST, BoundNetLog());
1482 ASSERT_TRUE(spdy_stream_lowest);
1483 EXPECT_EQ(0u, spdy_stream_lowest->stream_id());
1484 test::StreamDelegateDoNothing delegate_lowest(spdy_stream_lowest);
1485 spdy_stream_lowest->SetDelegate(&delegate_lowest);
1487 base::WeakPtr<SpdyStream> spdy_stream_highest =
1488 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1489 session, url, HIGHEST, BoundNetLog());
1490 ASSERT_TRUE(spdy_stream_highest);
1491 EXPECT_EQ(0u, spdy_stream_highest->stream_id());
1492 test::StreamDelegateDoNothing delegate_highest(spdy_stream_highest);
1493 spdy_stream_highest->SetDelegate(&delegate_highest);
1495 // Queue the lower priority one first.
1497 scoped_ptr<SpdyHeaderBlock> headers_lowest(
1498 spdy_util_.ConstructGetHeaderBlock(url.spec()));
1499 spdy_stream_lowest->SendRequestHeaders(
1500 headers_lowest.Pass(), NO_MORE_DATA_TO_SEND);
1501 EXPECT_TRUE(spdy_stream_lowest->HasUrlFromHeaders());
1503 scoped_ptr<SpdyHeaderBlock> headers_highest(
1504 spdy_util_.ConstructGetHeaderBlock(url.spec()));
1505 spdy_stream_highest->SendRequestHeaders(
1506 headers_highest.Pass(), NO_MORE_DATA_TO_SEND);
1507 EXPECT_TRUE(spdy_stream_highest->HasUrlFromHeaders());
1509 data.RunFor(7);
1511 EXPECT_FALSE(spdy_stream_lowest);
1512 EXPECT_FALSE(spdy_stream_highest);
1513 EXPECT_EQ(3u, delegate_lowest.stream_id());
1514 EXPECT_EQ(1u, delegate_highest.stream_id());
1517 TEST_P(SpdySessionTest, CancelStream) {
1518 MockConnect connect_data(SYNCHRONOUS, OK);
1519 // Request 1, at HIGHEST priority, will be cancelled before it writes data.
1520 // Request 2, at LOWEST priority, will be a full request and will be id 1.
1521 scoped_ptr<SpdyFrame> req2(
1522 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1523 MockWrite writes[] = {
1524 CreateMockWrite(*req2, 0),
1527 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1528 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
1529 MockRead reads[] = {
1530 CreateMockRead(*resp2, 1),
1531 CreateMockRead(*body2, 2),
1532 MockRead(ASYNC, 0, 3) // EOF
1535 session_deps_.host_resolver->set_synchronous_mode(true);
1537 DeterministicSocketData data(reads, arraysize(reads),
1538 writes, arraysize(writes));
1539 data.set_connect_data(connect_data);
1540 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1542 CreateDeterministicNetworkSession();
1544 base::WeakPtr<SpdySession> session =
1545 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1547 GURL url1(kDefaultURL);
1548 base::WeakPtr<SpdyStream> spdy_stream1 =
1549 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1550 session, url1, HIGHEST, BoundNetLog());
1551 ASSERT_TRUE(spdy_stream1.get() != NULL);
1552 EXPECT_EQ(0u, spdy_stream1->stream_id());
1553 test::StreamDelegateDoNothing delegate1(spdy_stream1);
1554 spdy_stream1->SetDelegate(&delegate1);
1556 GURL url2(kDefaultURL);
1557 base::WeakPtr<SpdyStream> spdy_stream2 =
1558 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1559 session, url2, LOWEST, BoundNetLog());
1560 ASSERT_TRUE(spdy_stream2.get() != NULL);
1561 EXPECT_EQ(0u, spdy_stream2->stream_id());
1562 test::StreamDelegateDoNothing delegate2(spdy_stream2);
1563 spdy_stream2->SetDelegate(&delegate2);
1565 scoped_ptr<SpdyHeaderBlock> headers(
1566 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
1567 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
1568 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
1570 scoped_ptr<SpdyHeaderBlock> headers2(
1571 spdy_util_.ConstructGetHeaderBlock(url2.spec()));
1572 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
1573 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
1575 EXPECT_EQ(0u, spdy_stream1->stream_id());
1577 spdy_stream1->Cancel();
1578 EXPECT_EQ(NULL, spdy_stream1.get());
1580 EXPECT_EQ(0u, delegate1.stream_id());
1582 data.RunFor(1);
1584 EXPECT_EQ(0u, delegate1.stream_id());
1585 EXPECT_EQ(1u, delegate2.stream_id());
1587 spdy_stream2->Cancel();
1588 EXPECT_EQ(NULL, spdy_stream2.get());
1591 // Create two streams that are set to re-close themselves on close,
1592 // and then close the session. Nothing should blow up. Also a
1593 // regression test for http://crbug.com/139518 .
1594 TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) {
1595 session_deps_.host_resolver->set_synchronous_mode(true);
1597 MockConnect connect_data(SYNCHRONOUS, OK);
1599 // No actual data will be sent.
1600 MockWrite writes[] = {
1601 MockWrite(ASYNC, 0, 1) // EOF
1604 MockRead reads[] = {
1605 MockRead(ASYNC, 0, 0) // EOF
1607 DeterministicSocketData data(reads, arraysize(reads),
1608 writes, arraysize(writes));
1609 data.set_connect_data(connect_data);
1610 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1612 CreateDeterministicNetworkSession();
1614 base::WeakPtr<SpdySession> session =
1615 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1617 GURL url1(kDefaultURL);
1618 base::WeakPtr<SpdyStream> spdy_stream1 =
1619 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1620 session, url1, HIGHEST, BoundNetLog());
1621 ASSERT_TRUE(spdy_stream1.get() != NULL);
1622 EXPECT_EQ(0u, spdy_stream1->stream_id());
1624 GURL url2(kDefaultURL);
1625 base::WeakPtr<SpdyStream> spdy_stream2 =
1626 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1627 session, url2, LOWEST, BoundNetLog());
1628 ASSERT_TRUE(spdy_stream2.get() != NULL);
1629 EXPECT_EQ(0u, spdy_stream2->stream_id());
1631 test::ClosingDelegate delegate1(spdy_stream1);
1632 spdy_stream1->SetDelegate(&delegate1);
1634 test::ClosingDelegate delegate2(spdy_stream2);
1635 spdy_stream2->SetDelegate(&delegate2);
1637 scoped_ptr<SpdyHeaderBlock> headers(
1638 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
1639 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
1640 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
1642 scoped_ptr<SpdyHeaderBlock> headers2(
1643 spdy_util_.ConstructGetHeaderBlock(url2.spec()));
1644 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
1645 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
1647 // Ensure that the streams have not yet been activated and assigned an id.
1648 EXPECT_EQ(0u, spdy_stream1->stream_id());
1649 EXPECT_EQ(0u, spdy_stream2->stream_id());
1651 // Ensure we don't crash while closing the session.
1652 session->CloseSessionOnError(ERR_ABORTED, std::string());
1654 EXPECT_EQ(NULL, spdy_stream1.get());
1655 EXPECT_EQ(NULL, spdy_stream2.get());
1657 EXPECT_TRUE(delegate1.StreamIsClosed());
1658 EXPECT_TRUE(delegate2.StreamIsClosed());
1660 EXPECT_TRUE(session == NULL);
1663 // Create two streams that are set to close each other on close, and
1664 // then close the session. Nothing should blow up.
1665 TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) {
1666 session_deps_.host_resolver->set_synchronous_mode(true);
1668 MockConnect connect_data(SYNCHRONOUS, OK);
1670 // No actual data will be sent.
1671 MockWrite writes[] = {
1672 MockWrite(ASYNC, 0, 1) // EOF
1675 MockRead reads[] = {
1676 MockRead(ASYNC, 0, 0) // EOF
1678 DeterministicSocketData data(reads, arraysize(reads),
1679 writes, arraysize(writes));
1680 data.set_connect_data(connect_data);
1681 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1683 CreateDeterministicNetworkSession();
1685 base::WeakPtr<SpdySession> session =
1686 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1688 GURL url1(kDefaultURL);
1689 base::WeakPtr<SpdyStream> spdy_stream1 =
1690 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1691 session, url1, HIGHEST, BoundNetLog());
1692 ASSERT_TRUE(spdy_stream1.get() != NULL);
1693 EXPECT_EQ(0u, spdy_stream1->stream_id());
1695 GURL url2(kDefaultURL);
1696 base::WeakPtr<SpdyStream> spdy_stream2 =
1697 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
1698 session, url2, LOWEST, BoundNetLog());
1699 ASSERT_TRUE(spdy_stream2.get() != NULL);
1700 EXPECT_EQ(0u, spdy_stream2->stream_id());
1702 // Make |spdy_stream1| close |spdy_stream2|.
1703 test::ClosingDelegate delegate1(spdy_stream2);
1704 spdy_stream1->SetDelegate(&delegate1);
1706 // Make |spdy_stream2| close |spdy_stream1|.
1707 test::ClosingDelegate delegate2(spdy_stream1);
1708 spdy_stream2->SetDelegate(&delegate2);
1710 scoped_ptr<SpdyHeaderBlock> headers(
1711 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
1712 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
1713 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
1715 scoped_ptr<SpdyHeaderBlock> headers2(
1716 spdy_util_.ConstructGetHeaderBlock(url2.spec()));
1717 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
1718 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
1720 // Ensure that the streams have not yet been activated and assigned an id.
1721 EXPECT_EQ(0u, spdy_stream1->stream_id());
1722 EXPECT_EQ(0u, spdy_stream2->stream_id());
1724 // Ensure we don't crash while closing the session.
1725 session->CloseSessionOnError(ERR_ABORTED, std::string());
1727 EXPECT_EQ(NULL, spdy_stream1.get());
1728 EXPECT_EQ(NULL, spdy_stream2.get());
1730 EXPECT_TRUE(delegate1.StreamIsClosed());
1731 EXPECT_TRUE(delegate2.StreamIsClosed());
1733 EXPECT_TRUE(session == NULL);
1736 // Create two streams that are set to re-close themselves on close,
1737 // activate them, and then close the session. Nothing should blow up.
1738 TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) {
1739 session_deps_.host_resolver->set_synchronous_mode(true);
1741 MockConnect connect_data(SYNCHRONOUS, OK);
1743 scoped_ptr<SpdyFrame> req1(
1744 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
1745 scoped_ptr<SpdyFrame> req2(
1746 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
1747 MockWrite writes[] = {
1748 CreateMockWrite(*req1, 0),
1749 CreateMockWrite(*req2, 1),
1752 MockRead reads[] = {
1753 MockRead(ASYNC, 0, 2) // EOF
1756 DeterministicSocketData data(reads, arraysize(reads),
1757 writes, arraysize(writes));
1758 data.set_connect_data(connect_data);
1759 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1761 CreateDeterministicNetworkSession();
1763 base::WeakPtr<SpdySession> session =
1764 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1766 GURL url1(kDefaultURL);
1767 base::WeakPtr<SpdyStream> spdy_stream1 =
1768 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1769 session, url1, MEDIUM, BoundNetLog());
1770 ASSERT_TRUE(spdy_stream1.get() != NULL);
1771 EXPECT_EQ(0u, spdy_stream1->stream_id());
1773 GURL url2(kDefaultURL);
1774 base::WeakPtr<SpdyStream> spdy_stream2 =
1775 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1776 session, url2, MEDIUM, BoundNetLog());
1777 ASSERT_TRUE(spdy_stream2.get() != NULL);
1778 EXPECT_EQ(0u, spdy_stream2->stream_id());
1780 test::ClosingDelegate delegate1(spdy_stream1);
1781 spdy_stream1->SetDelegate(&delegate1);
1783 test::ClosingDelegate delegate2(spdy_stream2);
1784 spdy_stream2->SetDelegate(&delegate2);
1786 scoped_ptr<SpdyHeaderBlock> headers(
1787 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
1788 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
1789 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
1791 scoped_ptr<SpdyHeaderBlock> headers2(
1792 spdy_util_.ConstructGetHeaderBlock(url2.spec()));
1793 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
1794 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
1796 // Ensure that the streams have not yet been activated and assigned an id.
1797 EXPECT_EQ(0u, spdy_stream1->stream_id());
1798 EXPECT_EQ(0u, spdy_stream2->stream_id());
1800 data.RunFor(2);
1802 EXPECT_EQ(1u, spdy_stream1->stream_id());
1803 EXPECT_EQ(3u, spdy_stream2->stream_id());
1805 // Ensure we don't crash while closing the session.
1806 session->CloseSessionOnError(ERR_ABORTED, std::string());
1808 EXPECT_EQ(NULL, spdy_stream1.get());
1809 EXPECT_EQ(NULL, spdy_stream2.get());
1811 EXPECT_TRUE(delegate1.StreamIsClosed());
1812 EXPECT_TRUE(delegate2.StreamIsClosed());
1814 EXPECT_TRUE(session == NULL);
1817 // Create two streams that are set to close each other on close,
1818 // activate them, and then close the session. Nothing should blow up.
1819 TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) {
1820 session_deps_.host_resolver->set_synchronous_mode(true);
1822 MockConnect connect_data(SYNCHRONOUS, OK);
1824 scoped_ptr<SpdyFrame> req1(
1825 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
1826 scoped_ptr<SpdyFrame> req2(
1827 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
1828 MockWrite writes[] = {
1829 CreateMockWrite(*req1, 0),
1830 CreateMockWrite(*req2, 1),
1833 MockRead reads[] = {
1834 MockRead(ASYNC, 0, 2) // EOF
1837 DeterministicSocketData data(reads, arraysize(reads),
1838 writes, arraysize(writes));
1839 data.set_connect_data(connect_data);
1840 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1842 CreateDeterministicNetworkSession();
1844 base::WeakPtr<SpdySession> session =
1845 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1847 GURL url1(kDefaultURL);
1848 base::WeakPtr<SpdyStream> spdy_stream1 =
1849 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1850 session, url1, MEDIUM, BoundNetLog());
1851 ASSERT_TRUE(spdy_stream1.get() != NULL);
1852 EXPECT_EQ(0u, spdy_stream1->stream_id());
1854 GURL url2(kDefaultURL);
1855 base::WeakPtr<SpdyStream> spdy_stream2 =
1856 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1857 session, url2, MEDIUM, BoundNetLog());
1858 ASSERT_TRUE(spdy_stream2.get() != NULL);
1859 EXPECT_EQ(0u, spdy_stream2->stream_id());
1861 // Make |spdy_stream1| close |spdy_stream2|.
1862 test::ClosingDelegate delegate1(spdy_stream2);
1863 spdy_stream1->SetDelegate(&delegate1);
1865 // Make |spdy_stream2| close |spdy_stream1|.
1866 test::ClosingDelegate delegate2(spdy_stream1);
1867 spdy_stream2->SetDelegate(&delegate2);
1869 scoped_ptr<SpdyHeaderBlock> headers(
1870 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
1871 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
1872 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
1874 scoped_ptr<SpdyHeaderBlock> headers2(
1875 spdy_util_.ConstructGetHeaderBlock(url2.spec()));
1876 spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
1877 EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
1879 // Ensure that the streams have not yet been activated and assigned an id.
1880 EXPECT_EQ(0u, spdy_stream1->stream_id());
1881 EXPECT_EQ(0u, spdy_stream2->stream_id());
1883 data.RunFor(2);
1885 EXPECT_EQ(1u, spdy_stream1->stream_id());
1886 EXPECT_EQ(3u, spdy_stream2->stream_id());
1888 // Ensure we don't crash while closing the session.
1889 session->CloseSessionOnError(ERR_ABORTED, std::string());
1891 EXPECT_EQ(NULL, spdy_stream1.get());
1892 EXPECT_EQ(NULL, spdy_stream2.get());
1894 EXPECT_TRUE(delegate1.StreamIsClosed());
1895 EXPECT_TRUE(delegate2.StreamIsClosed());
1897 EXPECT_TRUE(session == NULL);
1900 // Delegate that closes a given session when the stream is closed.
1901 class SessionClosingDelegate : public test::StreamDelegateDoNothing {
1902 public:
1903 SessionClosingDelegate(const base::WeakPtr<SpdyStream>& stream,
1904 const base::WeakPtr<SpdySession>& session_to_close)
1905 : StreamDelegateDoNothing(stream),
1906 session_to_close_(session_to_close) {}
1908 virtual ~SessionClosingDelegate() {}
1910 virtual void OnClose(int status) OVERRIDE {
1911 session_to_close_->CloseSessionOnError(ERR_ABORTED, "Aborted");
1914 private:
1915 base::WeakPtr<SpdySession> session_to_close_;
1918 // Close an activated stream that closes its session. Nothing should
1919 // blow up. This is a regression test for http://crbug.com/263691 .
1920 TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) {
1921 session_deps_.host_resolver->set_synchronous_mode(true);
1923 MockConnect connect_data(SYNCHRONOUS, OK);
1925 scoped_ptr<SpdyFrame> req(
1926 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
1927 MockWrite writes[] = {
1928 CreateMockWrite(*req, 0),
1931 MockRead reads[] = {
1932 MockRead(ASYNC, 0, 1) // EOF
1934 DeterministicSocketData data(reads, arraysize(reads),
1935 writes, arraysize(writes));
1936 data.set_connect_data(connect_data);
1937 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1939 CreateDeterministicNetworkSession();
1941 base::WeakPtr<SpdySession> session =
1942 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
1944 GURL url(kDefaultURL);
1945 base::WeakPtr<SpdyStream> spdy_stream =
1946 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
1947 session, url, MEDIUM, BoundNetLog());
1948 ASSERT_TRUE(spdy_stream.get() != NULL);
1949 EXPECT_EQ(0u, spdy_stream->stream_id());
1951 SessionClosingDelegate delegate(spdy_stream, session);
1952 spdy_stream->SetDelegate(&delegate);
1954 scoped_ptr<SpdyHeaderBlock> headers(
1955 spdy_util_.ConstructGetHeaderBlock(url.spec()));
1956 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
1957 EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
1959 EXPECT_EQ(0u, spdy_stream->stream_id());
1961 data.RunFor(1);
1963 EXPECT_EQ(1u, spdy_stream->stream_id());
1965 // Ensure we don't crash while closing the stream (which closes the
1966 // session).
1967 spdy_stream->Cancel();
1969 EXPECT_EQ(NULL, spdy_stream.get());
1970 EXPECT_TRUE(delegate.StreamIsClosed());
1971 EXPECT_TRUE(session == NULL);
1974 TEST_P(SpdySessionTest, VerifyDomainAuthentication) {
1975 session_deps_.host_resolver->set_synchronous_mode(true);
1977 MockConnect connect_data(SYNCHRONOUS, OK);
1979 // No actual data will be sent.
1980 MockWrite writes[] = {
1981 MockWrite(ASYNC, 0, 1) // EOF
1984 MockRead reads[] = {
1985 MockRead(ASYNC, 0, 0) // EOF
1987 DeterministicSocketData data(reads, arraysize(reads),
1988 writes, arraysize(writes));
1989 data.set_connect_data(connect_data);
1990 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1992 // Load a cert that is valid for:
1993 // www.example.org
1994 // mail.example.org
1995 // www.example.com
1996 base::FilePath certs_dir = GetTestCertsDirectory();
1997 scoped_refptr<X509Certificate> test_cert(
1998 ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
1999 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
2001 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
2002 ssl.cert = test_cert;
2003 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
2005 CreateDeterministicNetworkSession();
2007 base::WeakPtr<SpdySession> session =
2008 CreateSecureSpdySession(http_session_, key_, BoundNetLog());
2010 EXPECT_TRUE(session->VerifyDomainAuthentication("www.example.org"));
2011 EXPECT_TRUE(session->VerifyDomainAuthentication("mail.example.org"));
2012 EXPECT_TRUE(session->VerifyDomainAuthentication("mail.example.com"));
2013 EXPECT_FALSE(session->VerifyDomainAuthentication("mail.google.com"));
2016 TEST_P(SpdySessionTest, ConnectionPooledWithTlsChannelId) {
2017 session_deps_.host_resolver->set_synchronous_mode(true);
2019 MockConnect connect_data(SYNCHRONOUS, OK);
2021 // No actual data will be sent.
2022 MockWrite writes[] = {
2023 MockWrite(ASYNC, 0, 1) // EOF
2026 MockRead reads[] = {
2027 MockRead(ASYNC, 0, 0) // EOF
2029 DeterministicSocketData data(reads, arraysize(reads),
2030 writes, arraysize(writes));
2031 data.set_connect_data(connect_data);
2032 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2034 // Load a cert that is valid for:
2035 // www.example.org
2036 // mail.example.org
2037 // www.example.com
2038 base::FilePath certs_dir = GetTestCertsDirectory();
2039 scoped_refptr<X509Certificate> test_cert(
2040 ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
2041 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
2043 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
2044 ssl.channel_id_sent = true;
2045 ssl.cert = test_cert;
2046 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
2048 CreateDeterministicNetworkSession();
2050 base::WeakPtr<SpdySession> session =
2051 CreateSecureSpdySession(http_session_, key_, BoundNetLog());
2053 EXPECT_TRUE(session->VerifyDomainAuthentication("www.example.org"));
2054 EXPECT_TRUE(session->VerifyDomainAuthentication("mail.example.org"));
2055 EXPECT_FALSE(session->VerifyDomainAuthentication("mail.example.com"));
2056 EXPECT_FALSE(session->VerifyDomainAuthentication("mail.google.com"));
2059 TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) {
2060 // TODO(rtenneti): Define a helper class/methods and move the common code in
2061 // this file.
2062 MockConnect connect_data(SYNCHRONOUS, OK);
2064 SettingsMap new_settings;
2065 const SpdySettingsIds kSpdySettingsIds1 = SETTINGS_MAX_CONCURRENT_STREAMS;
2066 const uint32 max_concurrent_streams = 1;
2067 new_settings[kSpdySettingsIds1] =
2068 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
2070 scoped_ptr<SpdyFrame> req1(
2071 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2072 scoped_ptr<SpdyFrame> req2(
2073 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
2074 scoped_ptr<SpdyFrame> req3(
2075 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true));
2076 MockWrite writes[] = {
2077 CreateMockWrite(*req1, 1),
2078 CreateMockWrite(*req2, 4),
2079 CreateMockWrite(*req3, 7),
2082 // Set up the socket so we read a SETTINGS frame that sets max concurrent
2083 // streams to 1.
2084 scoped_ptr<SpdyFrame> settings_frame(
2085 spdy_util_.ConstructSpdySettings(new_settings));
2087 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2088 scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true));
2090 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
2091 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, true));
2093 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
2094 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, true));
2096 MockRead reads[] = {
2097 CreateMockRead(*settings_frame),
2098 CreateMockRead(*resp1, 2),
2099 CreateMockRead(*body1, 3),
2100 CreateMockRead(*resp2, 5),
2101 CreateMockRead(*body2, 6),
2102 CreateMockRead(*resp3, 8),
2103 CreateMockRead(*body3, 9),
2104 MockRead(ASYNC, 0, 10) // EOF
2107 DeterministicSocketData data(reads, arraysize(reads),
2108 writes, arraysize(writes));
2109 data.set_connect_data(connect_data);
2110 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2112 CreateDeterministicNetworkSession();
2114 base::WeakPtr<SpdySession> session =
2115 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2117 // Read the settings frame.
2118 data.RunFor(1);
2120 GURL url1(kDefaultURL);
2121 base::WeakPtr<SpdyStream> spdy_stream1 =
2122 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2123 session, url1, LOWEST, BoundNetLog());
2124 ASSERT_TRUE(spdy_stream1.get() != NULL);
2125 EXPECT_EQ(0u, spdy_stream1->stream_id());
2126 test::StreamDelegateDoNothing delegate1(spdy_stream1);
2127 spdy_stream1->SetDelegate(&delegate1);
2129 TestCompletionCallback callback2;
2130 GURL url2(kDefaultURL);
2131 SpdyStreamRequest request2;
2132 ASSERT_EQ(ERR_IO_PENDING,
2133 request2.StartRequest(
2134 SPDY_REQUEST_RESPONSE_STREAM,
2135 session, url2, LOWEST, BoundNetLog(), callback2.callback()));
2137 TestCompletionCallback callback3;
2138 GURL url3(kDefaultURL);
2139 SpdyStreamRequest request3;
2140 ASSERT_EQ(ERR_IO_PENDING,
2141 request3.StartRequest(
2142 SPDY_REQUEST_RESPONSE_STREAM,
2143 session, url3, LOWEST, BoundNetLog(), callback3.callback()));
2145 EXPECT_EQ(0u, session->num_active_streams());
2146 EXPECT_EQ(1u, session->num_created_streams());
2147 EXPECT_EQ(2u, session->pending_create_stream_queue_size(LOWEST));
2149 scoped_ptr<SpdyHeaderBlock> headers(
2150 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2151 spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
2152 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2154 // Run until 1st stream is activated and then closed.
2155 EXPECT_EQ(0u, delegate1.stream_id());
2156 data.RunFor(3);
2157 EXPECT_EQ(NULL, spdy_stream1.get());
2158 EXPECT_EQ(1u, delegate1.stream_id());
2160 EXPECT_EQ(0u, session->num_active_streams());
2161 EXPECT_EQ(0u, session->num_created_streams());
2162 EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST));
2164 // Pump loop for SpdySession::ProcessPendingStreamRequests() to
2165 // create the 2nd stream.
2166 base::MessageLoop::current()->RunUntilIdle();
2168 EXPECT_EQ(0u, session->num_active_streams());
2169 EXPECT_EQ(1u, session->num_created_streams());
2170 EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST));
2172 base::WeakPtr<SpdyStream> stream2 = request2.ReleaseStream();
2173 test::StreamDelegateDoNothing delegate2(stream2);
2174 stream2->SetDelegate(&delegate2);
2175 scoped_ptr<SpdyHeaderBlock> headers2(
2176 spdy_util_.ConstructGetHeaderBlock(url2.spec()));
2177 stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
2178 EXPECT_TRUE(stream2->HasUrlFromHeaders());
2180 // Run until 2nd stream is activated and then closed.
2181 EXPECT_EQ(0u, delegate2.stream_id());
2182 data.RunFor(3);
2183 EXPECT_EQ(NULL, stream2.get());
2184 EXPECT_EQ(3u, delegate2.stream_id());
2186 EXPECT_EQ(0u, session->num_active_streams());
2187 EXPECT_EQ(0u, session->num_created_streams());
2188 EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
2190 // Pump loop for SpdySession::ProcessPendingStreamRequests() to
2191 // create the 3rd stream.
2192 base::MessageLoop::current()->RunUntilIdle();
2194 EXPECT_EQ(0u, session->num_active_streams());
2195 EXPECT_EQ(1u, session->num_created_streams());
2196 EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
2198 base::WeakPtr<SpdyStream> stream3 = request3.ReleaseStream();
2199 test::StreamDelegateDoNothing delegate3(stream3);
2200 stream3->SetDelegate(&delegate3);
2201 scoped_ptr<SpdyHeaderBlock> headers3(
2202 spdy_util_.ConstructGetHeaderBlock(url3.spec()));
2203 stream3->SendRequestHeaders(headers3.Pass(), NO_MORE_DATA_TO_SEND);
2204 EXPECT_TRUE(stream3->HasUrlFromHeaders());
2206 // Run until 2nd stream is activated and then closed.
2207 EXPECT_EQ(0u, delegate3.stream_id());
2208 data.RunFor(3);
2209 EXPECT_EQ(NULL, stream3.get());
2210 EXPECT_EQ(5u, delegate3.stream_id());
2212 EXPECT_EQ(0u, session->num_active_streams());
2213 EXPECT_EQ(0u, session->num_created_streams());
2214 EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
2216 data.RunFor(1);
2219 TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) {
2220 session_deps_.host_resolver->set_synchronous_mode(true);
2222 MockRead reads[] = {
2223 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
2226 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
2227 MockConnect connect_data(SYNCHRONOUS, OK);
2229 data.set_connect_data(connect_data);
2230 session_deps_.socket_factory->AddSocketDataProvider(&data);
2232 CreateNetworkSession();
2234 base::WeakPtr<SpdySession> session =
2235 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2237 // Leave room for only one more stream to be created.
2238 for (size_t i = 0; i < kInitialMaxConcurrentStreams - 1; ++i) {
2239 base::WeakPtr<SpdyStream> spdy_stream =
2240 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
2241 session, test_url_, MEDIUM, BoundNetLog());
2242 ASSERT_TRUE(spdy_stream != NULL);
2245 GURL url1(kDefaultURL);
2246 base::WeakPtr<SpdyStream> spdy_stream1 =
2247 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
2248 session, url1, LOWEST, BoundNetLog());
2249 ASSERT_TRUE(spdy_stream1.get() != NULL);
2250 EXPECT_EQ(0u, spdy_stream1->stream_id());
2252 TestCompletionCallback callback2;
2253 GURL url2(kDefaultURL);
2254 SpdyStreamRequest request2;
2255 ASSERT_EQ(ERR_IO_PENDING,
2256 request2.StartRequest(
2257 SPDY_BIDIRECTIONAL_STREAM, session, url2, LOWEST, BoundNetLog(),
2258 callback2.callback()));
2260 TestCompletionCallback callback3;
2261 GURL url3(kDefaultURL);
2262 SpdyStreamRequest request3;
2263 ASSERT_EQ(ERR_IO_PENDING,
2264 request3.StartRequest(
2265 SPDY_BIDIRECTIONAL_STREAM, session, url3, LOWEST, BoundNetLog(),
2266 callback3.callback()));
2268 EXPECT_EQ(0u, session->num_active_streams());
2269 EXPECT_EQ(kInitialMaxConcurrentStreams, session->num_created_streams());
2270 EXPECT_EQ(2u, session->pending_create_stream_queue_size(LOWEST));
2272 // Cancel the first stream; this will allow the second stream to be created.
2273 EXPECT_TRUE(spdy_stream1.get() != NULL);
2274 spdy_stream1->Cancel();
2275 EXPECT_EQ(NULL, spdy_stream1.get());
2277 EXPECT_EQ(OK, callback2.WaitForResult());
2278 EXPECT_EQ(0u, session->num_active_streams());
2279 EXPECT_EQ(kInitialMaxConcurrentStreams, session->num_created_streams());
2280 EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST));
2282 // Cancel the second stream; this will allow the third stream to be created.
2283 base::WeakPtr<SpdyStream> spdy_stream2 = request2.ReleaseStream();
2284 spdy_stream2->Cancel();
2285 EXPECT_EQ(NULL, spdy_stream2.get());
2287 EXPECT_EQ(OK, callback3.WaitForResult());
2288 EXPECT_EQ(0u, session->num_active_streams());
2289 EXPECT_EQ(kInitialMaxConcurrentStreams, session->num_created_streams());
2290 EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
2292 // Cancel the third stream.
2293 base::WeakPtr<SpdyStream> spdy_stream3 = request3.ReleaseStream();
2294 spdy_stream3->Cancel();
2295 EXPECT_EQ(NULL, spdy_stream3.get());
2296 EXPECT_EQ(0u, session->num_active_streams());
2297 EXPECT_EQ(kInitialMaxConcurrentStreams - 1, session->num_created_streams());
2298 EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
2301 // Test that SpdySession::DoReadLoop reads data from the socket
2302 // without yielding. This test makes 32k - 1 bytes of data available
2303 // on the socket for reading. It then verifies that it has read all
2304 // the available data without yielding.
2305 TEST_P(SpdySessionTest, ReadDataWithoutYielding) {
2306 MockConnect connect_data(SYNCHRONOUS, OK);
2307 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
2309 scoped_ptr<SpdyFrame> req1(
2310 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
2311 MockWrite writes[] = {
2312 CreateMockWrite(*req1, 0),
2315 // Build buffer of size kMaxReadBytesWithoutYielding / 4
2316 // (-spdy_data_frame_size).
2317 ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding);
2318 const int kPayloadSize =
2319 kMaxReadBytesWithoutYielding / 4 - framer.GetControlFrameHeaderSize();
2320 TestDataStream test_stream;
2321 scoped_refptr<net::IOBuffer> payload(new net::IOBuffer(kPayloadSize));
2322 char* payload_data = payload->data();
2323 test_stream.GetBytes(payload_data, kPayloadSize);
2325 scoped_ptr<SpdyFrame> partial_data_frame(
2326 framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_NONE));
2327 scoped_ptr<SpdyFrame> finish_data_frame(
2328 framer.CreateDataFrame(1, payload_data, kPayloadSize - 1, DATA_FLAG_FIN));
2330 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2332 // Write 1 byte less than kMaxReadBytes to check that DoRead reads up to 32k
2333 // bytes.
2334 MockRead reads[] = {
2335 CreateMockRead(*resp1, 1),
2336 CreateMockRead(*partial_data_frame, 2),
2337 CreateMockRead(*partial_data_frame, 3, SYNCHRONOUS),
2338 CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
2339 CreateMockRead(*finish_data_frame, 5, SYNCHRONOUS),
2340 MockRead(ASYNC, 0, 6) // EOF
2343 // Create SpdySession and SpdyStream and send the request.
2344 DeterministicSocketData data(reads, arraysize(reads),
2345 writes, arraysize(writes));
2346 data.set_connect_data(connect_data);
2347 session_deps_.host_resolver->set_synchronous_mode(true);
2348 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2350 CreateDeterministicNetworkSession();
2352 base::WeakPtr<SpdySession> session =
2353 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2355 GURL url1(kDefaultURL);
2356 base::WeakPtr<SpdyStream> spdy_stream1 =
2357 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2358 session, url1, MEDIUM, BoundNetLog());
2359 ASSERT_TRUE(spdy_stream1.get() != NULL);
2360 EXPECT_EQ(0u, spdy_stream1->stream_id());
2361 test::StreamDelegateDoNothing delegate1(spdy_stream1);
2362 spdy_stream1->SetDelegate(&delegate1);
2364 scoped_ptr<SpdyHeaderBlock> headers1(
2365 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2366 spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND);
2367 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2369 // Set up the TaskObserver to verify SpdySession::DoReadLoop doesn't
2370 // post a task.
2371 SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop");
2373 // Run until 1st read.
2374 EXPECT_EQ(0u, delegate1.stream_id());
2375 data.RunFor(2);
2376 EXPECT_EQ(1u, delegate1.stream_id());
2377 EXPECT_EQ(0u, observer.executed_count());
2379 // Read all the data and verify SpdySession::DoReadLoop has not
2380 // posted a task.
2381 data.RunFor(4);
2382 EXPECT_EQ(NULL, spdy_stream1.get());
2384 // Verify task observer's executed_count is zero, which indicates DoRead read
2385 // all the available data.
2386 EXPECT_EQ(0u, observer.executed_count());
2387 EXPECT_TRUE(data.at_write_eof());
2388 EXPECT_TRUE(data.at_read_eof());
2391 // Test that SpdySession::DoReadLoop yields while reading the
2392 // data. This test makes 32k + 1 bytes of data available on the socket
2393 // for reading. It then verifies that DoRead has yielded even though
2394 // there is data available for it to read (i.e, socket()->Read didn't
2395 // return ERR_IO_PENDING during socket reads).
2396 TEST_P(SpdySessionTest, TestYieldingDuringReadData) {
2397 MockConnect connect_data(SYNCHRONOUS, OK);
2398 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
2400 scoped_ptr<SpdyFrame> req1(
2401 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
2402 MockWrite writes[] = {
2403 CreateMockWrite(*req1, 0),
2406 // Build buffer of size kMaxReadBytesWithoutYielding / 4
2407 // (-spdy_data_frame_size).
2408 ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding);
2409 const int kPayloadSize =
2410 kMaxReadBytesWithoutYielding / 4 - framer.GetControlFrameHeaderSize();
2411 TestDataStream test_stream;
2412 scoped_refptr<net::IOBuffer> payload(new net::IOBuffer(kPayloadSize));
2413 char* payload_data = payload->data();
2414 test_stream.GetBytes(payload_data, kPayloadSize);
2416 scoped_ptr<SpdyFrame> partial_data_frame(
2417 framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_NONE));
2418 scoped_ptr<SpdyFrame> finish_data_frame(
2419 framer.CreateDataFrame(1, "h", 1, DATA_FLAG_FIN));
2421 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2423 // Write 1 byte more than kMaxReadBytes to check that DoRead yields.
2424 MockRead reads[] = {
2425 CreateMockRead(*resp1, 1),
2426 CreateMockRead(*partial_data_frame, 2),
2427 CreateMockRead(*partial_data_frame, 3, SYNCHRONOUS),
2428 CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
2429 CreateMockRead(*partial_data_frame, 5, SYNCHRONOUS),
2430 CreateMockRead(*finish_data_frame, 6, SYNCHRONOUS),
2431 MockRead(ASYNC, 0, 7) // EOF
2434 // Create SpdySession and SpdyStream and send the request.
2435 DeterministicSocketData data(reads, arraysize(reads),
2436 writes, arraysize(writes));
2437 data.set_connect_data(connect_data);
2438 session_deps_.host_resolver->set_synchronous_mode(true);
2439 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2441 CreateDeterministicNetworkSession();
2443 base::WeakPtr<SpdySession> session =
2444 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2446 GURL url1(kDefaultURL);
2447 base::WeakPtr<SpdyStream> spdy_stream1 =
2448 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2449 session, url1, MEDIUM, BoundNetLog());
2450 ASSERT_TRUE(spdy_stream1.get() != NULL);
2451 EXPECT_EQ(0u, spdy_stream1->stream_id());
2452 test::StreamDelegateDoNothing delegate1(spdy_stream1);
2453 spdy_stream1->SetDelegate(&delegate1);
2455 scoped_ptr<SpdyHeaderBlock> headers1(
2456 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2457 spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND);
2458 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2460 // Set up the TaskObserver to verify SpdySession::DoReadLoop posts a
2461 // task.
2462 SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop");
2464 // Run until 1st read.
2465 EXPECT_EQ(0u, delegate1.stream_id());
2466 data.RunFor(2);
2467 EXPECT_EQ(1u, delegate1.stream_id());
2468 EXPECT_EQ(0u, observer.executed_count());
2470 // Read all the data and verify SpdySession::DoReadLoop has posted a
2471 // task.
2472 data.RunFor(6);
2473 EXPECT_EQ(NULL, spdy_stream1.get());
2475 // Verify task observer's executed_count is 1, which indicates DoRead has
2476 // posted only one task and thus yielded though there is data available for it
2477 // to read.
2478 EXPECT_EQ(1u, observer.executed_count());
2479 EXPECT_TRUE(data.at_write_eof());
2480 EXPECT_TRUE(data.at_read_eof());
2483 // Test that SpdySession::DoReadLoop() tests interactions of yielding
2484 // + async, by doing the following MockReads.
2486 // MockRead of SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K
2487 // ASYNC 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K.
2489 // The above reads 26K synchronously. Since that is less that 32K, we
2490 // will attempt to read again. However, that DoRead() will return
2491 // ERR_IO_PENDING (because of async read), so DoReadLoop() will
2492 // yield. When we come back, DoRead() will read the results from the
2493 // async read, and rest of the data synchronously.
2494 TEST_P(SpdySessionTest, TestYieldingDuringAsyncReadData) {
2495 MockConnect connect_data(SYNCHRONOUS, OK);
2496 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
2498 scoped_ptr<SpdyFrame> req1(
2499 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
2500 MockWrite writes[] = {
2501 CreateMockWrite(*req1, 0),
2504 // Build buffer of size kMaxReadBytesWithoutYielding / 4
2505 // (-spdy_data_frame_size).
2506 ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding);
2507 TestDataStream test_stream;
2508 const int kEightKPayloadSize =
2509 kMaxReadBytesWithoutYielding / 4 - framer.GetControlFrameHeaderSize();
2510 scoped_refptr<net::IOBuffer> eightk_payload(
2511 new net::IOBuffer(kEightKPayloadSize));
2512 char* eightk_payload_data = eightk_payload->data();
2513 test_stream.GetBytes(eightk_payload_data, kEightKPayloadSize);
2515 // Build buffer of 2k size.
2516 TestDataStream test_stream2;
2517 const int kTwoKPayloadSize = kEightKPayloadSize - 6 * 1024;
2518 scoped_refptr<net::IOBuffer> twok_payload(
2519 new net::IOBuffer(kTwoKPayloadSize));
2520 char* twok_payload_data = twok_payload->data();
2521 test_stream2.GetBytes(twok_payload_data, kTwoKPayloadSize);
2523 scoped_ptr<SpdyFrame> eightk_data_frame(framer.CreateDataFrame(
2524 1, eightk_payload_data, kEightKPayloadSize, DATA_FLAG_NONE));
2525 scoped_ptr<SpdyFrame> twok_data_frame(framer.CreateDataFrame(
2526 1, twok_payload_data, kTwoKPayloadSize, DATA_FLAG_NONE));
2527 scoped_ptr<SpdyFrame> finish_data_frame(framer.CreateDataFrame(
2528 1, "h", 1, DATA_FLAG_FIN));
2530 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2532 MockRead reads[] = {
2533 CreateMockRead(*resp1, 1),
2534 CreateMockRead(*eightk_data_frame, 2),
2535 CreateMockRead(*eightk_data_frame, 3, SYNCHRONOUS),
2536 CreateMockRead(*eightk_data_frame, 4, SYNCHRONOUS),
2537 CreateMockRead(*twok_data_frame, 5, SYNCHRONOUS),
2538 CreateMockRead(*eightk_data_frame, 6, ASYNC),
2539 CreateMockRead(*eightk_data_frame, 7, SYNCHRONOUS),
2540 CreateMockRead(*eightk_data_frame, 8, SYNCHRONOUS),
2541 CreateMockRead(*eightk_data_frame, 9, SYNCHRONOUS),
2542 CreateMockRead(*twok_data_frame, 10, SYNCHRONOUS),
2543 CreateMockRead(*finish_data_frame, 11, SYNCHRONOUS),
2544 MockRead(ASYNC, 0, 12) // EOF
2547 // Create SpdySession and SpdyStream and send the request.
2548 DeterministicSocketData data(reads, arraysize(reads),
2549 writes, arraysize(writes));
2550 data.set_connect_data(connect_data);
2551 session_deps_.host_resolver->set_synchronous_mode(true);
2552 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2554 CreateDeterministicNetworkSession();
2556 base::WeakPtr<SpdySession> session =
2557 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2559 GURL url1(kDefaultURL);
2560 base::WeakPtr<SpdyStream> spdy_stream1 =
2561 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2562 session, url1, MEDIUM, BoundNetLog());
2563 ASSERT_TRUE(spdy_stream1.get() != NULL);
2564 EXPECT_EQ(0u, spdy_stream1->stream_id());
2565 test::StreamDelegateDoNothing delegate1(spdy_stream1);
2566 spdy_stream1->SetDelegate(&delegate1);
2568 scoped_ptr<SpdyHeaderBlock> headers1(
2569 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2570 spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND);
2571 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2573 // Set up the TaskObserver to monitor SpdySession::DoReadLoop
2574 // posting of tasks.
2575 SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop");
2577 // Run until 1st read.
2578 EXPECT_EQ(0u, delegate1.stream_id());
2579 data.RunFor(2);
2580 EXPECT_EQ(1u, delegate1.stream_id());
2581 EXPECT_EQ(0u, observer.executed_count());
2583 // Read all the data and verify SpdySession::DoReadLoop has posted a
2584 // task.
2585 data.RunFor(12);
2586 EXPECT_EQ(NULL, spdy_stream1.get());
2588 // Verify task observer's executed_count is 1, which indicates DoRead has
2589 // posted only one task and thus yielded though there is data available for
2590 // it to read.
2591 EXPECT_EQ(1u, observer.executed_count());
2592 EXPECT_TRUE(data.at_write_eof());
2593 EXPECT_TRUE(data.at_read_eof());
2596 // Send a GoAway frame when SpdySession is in DoReadLoop. Make sure
2597 // nothing blows up.
2598 TEST_P(SpdySessionTest, GoAwayWhileInDoReadLoop) {
2599 MockConnect connect_data(SYNCHRONOUS, OK);
2600 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
2602 scoped_ptr<SpdyFrame> req1(
2603 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
2604 MockWrite writes[] = {
2605 CreateMockWrite(*req1, 0),
2608 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
2609 scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true));
2610 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway());
2612 MockRead reads[] = {
2613 CreateMockRead(*resp1, 1),
2614 CreateMockRead(*body1, 2),
2615 CreateMockRead(*goaway, 3),
2618 // Create SpdySession and SpdyStream and send the request.
2619 DeterministicSocketData data(reads, arraysize(reads),
2620 writes, arraysize(writes));
2621 data.set_connect_data(connect_data);
2622 session_deps_.host_resolver->set_synchronous_mode(true);
2623 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
2625 CreateDeterministicNetworkSession();
2627 base::WeakPtr<SpdySession> session =
2628 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
2630 GURL url1(kDefaultURL);
2631 base::WeakPtr<SpdyStream> spdy_stream1 =
2632 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2633 session, url1, MEDIUM, BoundNetLog());
2634 test::StreamDelegateDoNothing delegate1(spdy_stream1);
2635 spdy_stream1->SetDelegate(&delegate1);
2636 ASSERT_TRUE(spdy_stream1.get() != NULL);
2637 EXPECT_EQ(0u, spdy_stream1->stream_id());
2639 scoped_ptr<SpdyHeaderBlock> headers1(
2640 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2641 spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND);
2642 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2644 // Run until 1st read.
2645 EXPECT_EQ(0u, spdy_stream1->stream_id());
2646 data.RunFor(1);
2647 EXPECT_EQ(1u, spdy_stream1->stream_id());
2649 // Run until GoAway.
2650 data.RunFor(3);
2651 EXPECT_EQ(NULL, spdy_stream1.get());
2652 EXPECT_TRUE(data.at_write_eof());
2653 EXPECT_TRUE(data.at_read_eof());
2654 EXPECT_TRUE(session == NULL);
2657 // Within this framework, a SpdySession should be initialized with
2658 // flow control disabled for protocol version 2, with flow control
2659 // enabled only for streams for protocol version 3, and with flow
2660 // control enabled for streams and sessions for higher versions.
2661 TEST_P(SpdySessionTest, ProtocolNegotiation) {
2662 session_deps_.host_resolver->set_synchronous_mode(true);
2664 MockConnect connect_data(SYNCHRONOUS, OK);
2665 MockRead reads[] = {
2666 MockRead(SYNCHRONOUS, 0, 0) // EOF
2668 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
2669 data.set_connect_data(connect_data);
2670 session_deps_.socket_factory->AddSocketDataProvider(&data);
2672 CreateNetworkSession();
2673 base::WeakPtr<SpdySession> session =
2674 CreateFakeSpdySession(spdy_session_pool_, key_);
2676 EXPECT_EQ(spdy_util_.spdy_version(),
2677 session->buffered_spdy_framer_->protocol_version());
2678 if (GetParam() == kProtoDeprecatedSPDY2) {
2679 EXPECT_EQ(SpdySession::FLOW_CONTROL_NONE, session->flow_control_state());
2680 EXPECT_EQ(0, session->session_send_window_size_);
2681 EXPECT_EQ(0, session->session_recv_window_size_);
2682 } else if (GetParam() == kProtoSPDY3) {
2683 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM, session->flow_control_state());
2684 EXPECT_EQ(0, session->session_send_window_size_);
2685 EXPECT_EQ(0, session->session_recv_window_size_);
2686 } else {
2687 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
2688 session->flow_control_state());
2689 EXPECT_EQ(kSpdySessionInitialWindowSize,
2690 session->session_send_window_size_);
2691 EXPECT_EQ(kSpdySessionInitialWindowSize,
2692 session->session_recv_window_size_);
2694 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
2697 // Tests the case of a non-SPDY request closing an idle SPDY session when no
2698 // pointers to the idle session are currently held.
2699 TEST_P(SpdySessionTest, CloseOneIdleConnection) {
2700 ClientSocketPoolManager::set_max_sockets_per_group(
2701 HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
2702 ClientSocketPoolManager::set_max_sockets_per_pool(
2703 HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
2705 MockConnect connect_data(SYNCHRONOUS, OK);
2706 MockRead reads[] = {
2707 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
2709 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
2710 data.set_connect_data(connect_data);
2711 session_deps_.socket_factory->AddSocketDataProvider(&data);
2712 session_deps_.socket_factory->AddSocketDataProvider(&data);
2714 CreateNetworkSession();
2716 TransportClientSocketPool* pool =
2717 http_session_->GetTransportSocketPool(
2718 HttpNetworkSession::NORMAL_SOCKET_POOL);
2720 // Create an idle SPDY session.
2721 SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(),
2722 kPrivacyModeDisabled);
2723 base::WeakPtr<SpdySession> session1 =
2724 CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
2725 EXPECT_FALSE(pool->IsStalled());
2727 // Trying to create a new connection should cause the pool to be stalled, and
2728 // post a task asynchronously to try and close the session.
2729 TestCompletionCallback callback2;
2730 HostPortPair host_port2("2.com", 80);
2731 scoped_refptr<TransportSocketParams> params2(
2732 new TransportSocketParams(host_port2, false, false,
2733 OnHostResolutionCallback()));
2734 scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle);
2735 EXPECT_EQ(ERR_IO_PENDING,
2736 connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY,
2737 callback2.callback(), pool, BoundNetLog()));
2738 EXPECT_TRUE(pool->IsStalled());
2740 // The socket pool should close the connection asynchronously and establish a
2741 // new connection.
2742 EXPECT_EQ(OK, callback2.WaitForResult());
2743 EXPECT_FALSE(pool->IsStalled());
2744 EXPECT_TRUE(session1 == NULL);
2747 // Tests the case of a non-SPDY request closing an idle SPDY session when no
2748 // pointers to the idle session are currently held, in the case the SPDY session
2749 // has an alias.
2750 TEST_P(SpdySessionTest, CloseOneIdleConnectionWithAlias) {
2751 ClientSocketPoolManager::set_max_sockets_per_group(
2752 HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
2753 ClientSocketPoolManager::set_max_sockets_per_pool(
2754 HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
2756 MockConnect connect_data(SYNCHRONOUS, OK);
2757 MockRead reads[] = {
2758 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
2760 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
2761 data.set_connect_data(connect_data);
2762 session_deps_.socket_factory->AddSocketDataProvider(&data);
2763 session_deps_.socket_factory->AddSocketDataProvider(&data);
2765 session_deps_.host_resolver->set_synchronous_mode(true);
2766 session_deps_.host_resolver->rules()->AddIPLiteralRule(
2767 "1.com", "192.168.0.2", std::string());
2768 session_deps_.host_resolver->rules()->AddIPLiteralRule(
2769 "2.com", "192.168.0.2", std::string());
2770 // Not strictly needed.
2771 session_deps_.host_resolver->rules()->AddIPLiteralRule(
2772 "3.com", "192.168.0.3", std::string());
2774 CreateNetworkSession();
2776 TransportClientSocketPool* pool =
2777 http_session_->GetTransportSocketPool(
2778 HttpNetworkSession::NORMAL_SOCKET_POOL);
2780 // Create an idle SPDY session.
2781 SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(),
2782 kPrivacyModeDisabled);
2783 base::WeakPtr<SpdySession> session1 =
2784 CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
2785 EXPECT_FALSE(pool->IsStalled());
2787 // Set up an alias for the idle SPDY session, increasing its ref count to 2.
2788 SpdySessionKey key2(HostPortPair("2.com", 80), ProxyServer::Direct(),
2789 kPrivacyModeDisabled);
2790 HostResolver::RequestInfo info(key2.host_port_pair());
2791 AddressList addresses;
2792 // Pre-populate the DNS cache, since a synchronous resolution is required in
2793 // order to create the alias.
2794 session_deps_.host_resolver->Resolve(info,
2795 DEFAULT_PRIORITY,
2796 &addresses,
2797 CompletionCallback(),
2798 NULL,
2799 BoundNetLog());
2800 // Get a session for |key2|, which should return the session created earlier.
2801 base::WeakPtr<SpdySession> session2 =
2802 spdy_session_pool_->FindAvailableSession(key2, BoundNetLog());
2803 ASSERT_EQ(session1.get(), session2.get());
2804 EXPECT_FALSE(pool->IsStalled());
2806 // Trying to create a new connection should cause the pool to be stalled, and
2807 // post a task asynchronously to try and close the session.
2808 TestCompletionCallback callback3;
2809 HostPortPair host_port3("3.com", 80);
2810 scoped_refptr<TransportSocketParams> params3(
2811 new TransportSocketParams(host_port3, false, false,
2812 OnHostResolutionCallback()));
2813 scoped_ptr<ClientSocketHandle> connection3(new ClientSocketHandle);
2814 EXPECT_EQ(ERR_IO_PENDING,
2815 connection3->Init(host_port3.ToString(), params3, DEFAULT_PRIORITY,
2816 callback3.callback(), pool, BoundNetLog()));
2817 EXPECT_TRUE(pool->IsStalled());
2819 // The socket pool should close the connection asynchronously and establish a
2820 // new connection.
2821 EXPECT_EQ(OK, callback3.WaitForResult());
2822 EXPECT_FALSE(pool->IsStalled());
2823 EXPECT_TRUE(session1 == NULL);
2824 EXPECT_TRUE(session2 == NULL);
2827 // Tests that when a SPDY session becomes idle, it closes itself if there is
2828 // a lower layer pool stalled on the per-pool socket limit.
2829 TEST_P(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) {
2830 ClientSocketPoolManager::set_max_sockets_per_group(
2831 HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
2832 ClientSocketPoolManager::set_max_sockets_per_pool(
2833 HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
2835 MockConnect connect_data(SYNCHRONOUS, OK);
2836 MockRead reads[] = {
2837 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
2839 scoped_ptr<SpdyFrame> req1(
2840 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
2841 scoped_ptr<SpdyFrame> cancel1(
2842 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
2843 MockWrite writes[] = {
2844 CreateMockWrite(*req1, 1),
2845 CreateMockWrite(*cancel1, 1),
2847 StaticSocketDataProvider data(reads, arraysize(reads),
2848 writes, arraysize(writes));
2849 data.set_connect_data(connect_data);
2850 session_deps_.socket_factory->AddSocketDataProvider(&data);
2852 MockRead http_reads[] = {
2853 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
2855 StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
2856 NULL, 0);
2857 http_data.set_connect_data(connect_data);
2858 session_deps_.socket_factory->AddSocketDataProvider(&http_data);
2861 CreateNetworkSession();
2863 TransportClientSocketPool* pool =
2864 http_session_->GetTransportSocketPool(
2865 HttpNetworkSession::NORMAL_SOCKET_POOL);
2867 // Create a SPDY session.
2868 GURL url1(kDefaultURL);
2869 SpdySessionKey key1(HostPortPair(url1.host(), 80),
2870 ProxyServer::Direct(), kPrivacyModeDisabled);
2871 base::WeakPtr<SpdySession> session1 =
2872 CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
2873 EXPECT_FALSE(pool->IsStalled());
2875 // Create a stream using the session, and send a request.
2877 TestCompletionCallback callback1;
2878 base::WeakPtr<SpdyStream> spdy_stream1 =
2879 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2880 session1, url1, DEFAULT_PRIORITY,
2881 BoundNetLog());
2882 ASSERT_TRUE(spdy_stream1.get());
2883 test::StreamDelegateDoNothing delegate1(spdy_stream1);
2884 spdy_stream1->SetDelegate(&delegate1);
2886 scoped_ptr<SpdyHeaderBlock> headers1(
2887 spdy_util_.ConstructGetHeaderBlock(url1.spec()));
2888 EXPECT_EQ(ERR_IO_PENDING,
2889 spdy_stream1->SendRequestHeaders(
2890 headers1.Pass(), NO_MORE_DATA_TO_SEND));
2891 EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
2893 base::MessageLoop::current()->RunUntilIdle();
2895 // Trying to create a new connection should cause the pool to be stalled, and
2896 // post a task asynchronously to try and close the session.
2897 TestCompletionCallback callback2;
2898 HostPortPair host_port2("2.com", 80);
2899 scoped_refptr<TransportSocketParams> params2(
2900 new TransportSocketParams(host_port2, false, false,
2901 OnHostResolutionCallback()));
2902 scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle);
2903 EXPECT_EQ(ERR_IO_PENDING,
2904 connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY,
2905 callback2.callback(), pool, BoundNetLog()));
2906 EXPECT_TRUE(pool->IsStalled());
2908 // Running the message loop should cause the socket pool to ask the SPDY
2909 // session to close an idle socket, but since the socket is in use, nothing
2910 // happens.
2911 base::RunLoop().RunUntilIdle();
2912 EXPECT_TRUE(pool->IsStalled());
2913 EXPECT_FALSE(callback2.have_result());
2915 // Cancelling the request should result in the session's socket being
2916 // closed, since the pool is stalled.
2917 ASSERT_TRUE(spdy_stream1.get());
2918 spdy_stream1->Cancel();
2919 base::RunLoop().RunUntilIdle();
2920 ASSERT_FALSE(pool->IsStalled());
2921 EXPECT_EQ(OK, callback2.WaitForResult());
2924 // Verify that SpdySessionKey and therefore SpdySession is different when
2925 // privacy mode is enabled or disabled.
2926 TEST_P(SpdySessionTest, SpdySessionKeyPrivacyMode) {
2927 CreateDeterministicNetworkSession();
2929 HostPortPair host_port_pair("www.google.com", 443);
2930 SpdySessionKey key_privacy_enabled(host_port_pair, ProxyServer::Direct(),
2931 kPrivacyModeEnabled);
2932 SpdySessionKey key_privacy_disabled(host_port_pair, ProxyServer::Direct(),
2933 kPrivacyModeDisabled);
2935 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
2936 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
2938 // Add SpdySession with PrivacyMode Enabled to the pool.
2939 base::WeakPtr<SpdySession> session_privacy_enabled =
2940 CreateFakeSpdySession(spdy_session_pool_, key_privacy_enabled);
2942 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
2943 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
2945 // Add SpdySession with PrivacyMode Disabled to the pool.
2946 base::WeakPtr<SpdySession> session_privacy_disabled =
2947 CreateFakeSpdySession(spdy_session_pool_, key_privacy_disabled);
2949 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
2950 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
2952 session_privacy_enabled->CloseSessionOnError(ERR_ABORTED, std::string());
2953 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
2954 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
2956 session_privacy_disabled->CloseSessionOnError(ERR_ABORTED, std::string());
2957 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
2958 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
2961 // Delegate that creates another stream when its stream is closed.
2962 class StreamCreatingDelegate : public test::StreamDelegateDoNothing {
2963 public:
2964 StreamCreatingDelegate(const base::WeakPtr<SpdyStream>& stream,
2965 const base::WeakPtr<SpdySession>& session)
2966 : StreamDelegateDoNothing(stream),
2967 session_(session) {}
2969 virtual ~StreamCreatingDelegate() {}
2971 virtual void OnClose(int status) OVERRIDE {
2972 GURL url(kDefaultURL);
2973 ignore_result(
2974 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
2975 session_, url, MEDIUM, BoundNetLog()));
2978 private:
2979 const base::WeakPtr<SpdySession> session_;
2982 // Create another stream in response to a stream being reset. Nothing
2983 // should blow up. This is a regression test for
2984 // http://crbug.com/263690 .
2985 TEST_P(SpdySessionTest, CreateStreamOnStreamReset) {
2986 session_deps_.host_resolver->set_synchronous_mode(true);
2988 MockConnect connect_data(SYNCHRONOUS, OK);
2990 scoped_ptr<SpdyFrame> req(
2991 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
2992 MockWrite writes[] = {
2993 CreateMockWrite(*req, 0),
2996 scoped_ptr<SpdyFrame> rst(
2997 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM));
2998 MockRead reads[] = {
2999 CreateMockRead(*rst, 1),
3000 MockRead(ASYNC, 0, 2) // EOF
3002 DeterministicSocketData data(reads, arraysize(reads),
3003 writes, arraysize(writes));
3004 data.set_connect_data(connect_data);
3005 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3007 CreateDeterministicNetworkSession();
3009 base::WeakPtr<SpdySession> session =
3010 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3012 GURL url(kDefaultURL);
3013 base::WeakPtr<SpdyStream> spdy_stream =
3014 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
3015 session, url, MEDIUM, BoundNetLog());
3016 ASSERT_TRUE(spdy_stream.get() != NULL);
3017 EXPECT_EQ(0u, spdy_stream->stream_id());
3019 StreamCreatingDelegate delegate(spdy_stream, session);
3020 spdy_stream->SetDelegate(&delegate);
3022 scoped_ptr<SpdyHeaderBlock> headers(
3023 spdy_util_.ConstructGetHeaderBlock(url.spec()));
3024 spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
3025 EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
3027 EXPECT_EQ(0u, spdy_stream->stream_id());
3029 data.RunFor(1);
3031 EXPECT_EQ(1u, spdy_stream->stream_id());
3033 // Cause the stream to be reset, which should cause another stream
3034 // to be created.
3035 data.RunFor(1);
3037 EXPECT_EQ(NULL, spdy_stream.get());
3038 EXPECT_TRUE(delegate.StreamIsClosed());
3039 EXPECT_EQ(0u, session->num_active_streams());
3040 EXPECT_EQ(1u, session->num_created_streams());
3043 // The tests below are only for SPDY/3 and above.
3045 TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) {
3046 if (GetParam() < kProtoSPDY3)
3047 return;
3049 // Set SETTINGS_INITIAL_WINDOW_SIZE to a small number so that WINDOW_UPDATE
3050 // gets sent.
3051 SettingsMap new_settings;
3052 int32 window_size = 1;
3053 new_settings[SETTINGS_INITIAL_WINDOW_SIZE] =
3054 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, window_size);
3056 // Set up the socket so we read a SETTINGS frame that sets
3057 // INITIAL_WINDOW_SIZE.
3058 MockConnect connect_data(SYNCHRONOUS, OK);
3059 scoped_ptr<SpdyFrame> settings_frame(
3060 spdy_util_.ConstructSpdySettings(new_settings));
3061 MockRead reads[] = {
3062 CreateMockRead(*settings_frame, 0),
3063 MockRead(ASYNC, 0, 1) // EOF
3066 session_deps_.host_resolver->set_synchronous_mode(true);
3068 scoped_ptr<DeterministicSocketData> data(
3069 new DeterministicSocketData(reads, arraysize(reads), NULL, 0));
3070 data->set_connect_data(connect_data);
3071 session_deps_.deterministic_socket_factory->AddSocketDataProvider(data.get());
3073 CreateDeterministicNetworkSession();
3075 base::WeakPtr<SpdySession> session =
3076 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3077 base::WeakPtr<SpdyStream> spdy_stream1 =
3078 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
3079 session, test_url_, MEDIUM, BoundNetLog());
3080 ASSERT_TRUE(spdy_stream1.get() != NULL);
3081 TestCompletionCallback callback1;
3082 EXPECT_NE(spdy_stream1->send_window_size(), window_size);
3084 data->RunFor(1); // Process the SETTINGS frame, but not the EOF
3085 base::MessageLoop::current()->RunUntilIdle();
3086 EXPECT_EQ(session->stream_initial_send_window_size(), window_size);
3087 EXPECT_EQ(spdy_stream1->send_window_size(), window_size);
3089 // Release the first one, this will allow the second to be created.
3090 spdy_stream1->Cancel();
3091 EXPECT_EQ(NULL, spdy_stream1.get());
3093 base::WeakPtr<SpdyStream> spdy_stream2 =
3094 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
3095 session, test_url_, MEDIUM, BoundNetLog());
3096 ASSERT_TRUE(spdy_stream2.get() != NULL);
3097 EXPECT_EQ(spdy_stream2->send_window_size(), window_size);
3098 spdy_stream2->Cancel();
3099 EXPECT_EQ(NULL, spdy_stream2.get());
3102 // The tests below are only for SPDY/3.1 and above.
3104 // SpdySession::{Increase,Decrease}RecvWindowSize should properly
3105 // adjust the session receive window size for SPDY 3.1 and higher. In
3106 // addition, SpdySession::IncreaseRecvWindowSize should trigger
3107 // sending a WINDOW_UPDATE frame for a large enough delta.
3108 TEST_P(SpdySessionTest, AdjustRecvWindowSize) {
3109 if (GetParam() < kProtoSPDY31)
3110 return;
3112 session_deps_.host_resolver->set_synchronous_mode(true);
3114 const int32 delta_window_size = 100;
3116 MockConnect connect_data(SYNCHRONOUS, OK);
3117 MockRead reads[] = {
3118 MockRead(ASYNC, 0, 1) // EOF
3120 scoped_ptr<SpdyFrame> window_update(
3121 spdy_util_.ConstructSpdyWindowUpdate(
3122 kSessionFlowControlStreamId,
3123 kSpdySessionInitialWindowSize + delta_window_size));
3124 MockWrite writes[] = {
3125 CreateMockWrite(*window_update, 0),
3127 DeterministicSocketData data(reads, arraysize(reads),
3128 writes, arraysize(writes));
3129 data.set_connect_data(connect_data);
3130 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3132 CreateDeterministicNetworkSession();
3133 base::WeakPtr<SpdySession> session =
3134 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3135 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
3136 session->flow_control_state());
3138 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3139 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3141 session->IncreaseRecvWindowSize(delta_window_size);
3142 EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size,
3143 session->session_recv_window_size_);
3144 EXPECT_EQ(delta_window_size, session->session_unacked_recv_window_bytes_);
3146 // Should trigger sending a WINDOW_UPDATE frame.
3147 session->IncreaseRecvWindowSize(kSpdySessionInitialWindowSize);
3148 EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size +
3149 kSpdySessionInitialWindowSize,
3150 session->session_recv_window_size_);
3151 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3153 data.RunFor(1);
3155 // DecreaseRecvWindowSize() expects |in_io_loop_| to be true.
3156 session->in_io_loop_ = true;
3157 session->DecreaseRecvWindowSize(
3158 kSpdySessionInitialWindowSize + delta_window_size +
3159 kSpdySessionInitialWindowSize);
3160 session->in_io_loop_ = false;
3161 EXPECT_EQ(0, session->session_recv_window_size_);
3162 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3165 // SpdySession::{Increase,Decrease}SendWindowSize should properly
3166 // adjust the session send window size when the "enable_spdy_31" flag
3167 // is set.
3168 TEST_P(SpdySessionTest, AdjustSendWindowSize) {
3169 if (GetParam() < kProtoSPDY31)
3170 return;
3172 session_deps_.host_resolver->set_synchronous_mode(true);
3174 MockConnect connect_data(SYNCHRONOUS, OK);
3175 MockRead reads[] = {
3176 MockRead(SYNCHRONOUS, 0, 0) // EOF
3178 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
3179 data.set_connect_data(connect_data);
3180 session_deps_.socket_factory->AddSocketDataProvider(&data);
3182 CreateNetworkSession();
3183 base::WeakPtr<SpdySession> session =
3184 CreateFakeSpdySession(spdy_session_pool_, key_);
3185 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
3186 session->flow_control_state());
3188 const int32 delta_window_size = 100;
3190 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3192 session->IncreaseSendWindowSize(delta_window_size);
3193 EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size,
3194 session->session_send_window_size_);
3196 session->DecreaseSendWindowSize(delta_window_size);
3197 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3200 // Incoming data for an inactive stream should not cause the session
3201 // receive window size to decrease, but it should cause the unacked
3202 // bytes to increase.
3203 TEST_P(SpdySessionTest, SessionFlowControlInactiveStream) {
3204 if (GetParam() < kProtoSPDY31)
3205 return;
3207 session_deps_.host_resolver->set_synchronous_mode(true);
3209 MockConnect connect_data(SYNCHRONOUS, OK);
3210 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyBodyFrame(1, false));
3211 MockRead reads[] = {
3212 CreateMockRead(*resp, 0),
3213 MockRead(ASYNC, 0, 1) // EOF
3215 DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
3216 data.set_connect_data(connect_data);
3217 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3219 CreateDeterministicNetworkSession();
3220 base::WeakPtr<SpdySession> session =
3221 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3222 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
3223 session->flow_control_state());
3225 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3226 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3228 data.RunFor(1);
3230 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3231 EXPECT_EQ(kUploadDataSize, session->session_unacked_recv_window_bytes_);
3233 data.RunFor(1);
3236 // A delegate that drops any received data.
3237 class DropReceivedDataDelegate : public test::StreamDelegateSendImmediate {
3238 public:
3239 DropReceivedDataDelegate(const base::WeakPtr<SpdyStream>& stream,
3240 base::StringPiece data)
3241 : StreamDelegateSendImmediate(stream, data) {}
3243 virtual ~DropReceivedDataDelegate() {}
3245 // Drop any received data.
3246 virtual void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) OVERRIDE {}
3249 // Send data back and forth but use a delegate that drops its received
3250 // data. The receive window should still increase to its original
3251 // value, i.e. we shouldn't "leak" receive window bytes.
3252 TEST_P(SpdySessionTest, SessionFlowControlNoReceiveLeaks) {
3253 if (GetParam() < kProtoSPDY31)
3254 return;
3256 const char kStreamUrl[] = "http://www.google.com/";
3258 const int32 msg_data_size = 100;
3259 const std::string msg_data(msg_data_size, 'a');
3261 MockConnect connect_data(SYNCHRONOUS, OK);
3263 scoped_ptr<SpdyFrame> req(
3264 spdy_util_.ConstructSpdyPost(
3265 kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0));
3266 scoped_ptr<SpdyFrame> msg(
3267 spdy_util_.ConstructSpdyBodyFrame(
3268 1, msg_data.data(), msg_data_size, false));
3269 MockWrite writes[] = {
3270 CreateMockWrite(*req, 0),
3271 CreateMockWrite(*msg, 2),
3274 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3275 scoped_ptr<SpdyFrame> echo(
3276 spdy_util_.ConstructSpdyBodyFrame(
3277 1, msg_data.data(), msg_data_size, false));
3278 scoped_ptr<SpdyFrame> window_update(
3279 spdy_util_.ConstructSpdyWindowUpdate(
3280 kSessionFlowControlStreamId, msg_data_size));
3281 MockRead reads[] = {
3282 CreateMockRead(*resp, 1),
3283 CreateMockRead(*echo, 3),
3284 MockRead(ASYNC, 0, 4) // EOF
3287 // Create SpdySession and SpdyStream and send the request.
3288 DeterministicSocketData data(reads, arraysize(reads),
3289 writes, arraysize(writes));
3290 data.set_connect_data(connect_data);
3291 session_deps_.host_resolver->set_synchronous_mode(true);
3292 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3294 CreateDeterministicNetworkSession();
3296 base::WeakPtr<SpdySession> session =
3297 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3299 GURL url(kStreamUrl);
3300 base::WeakPtr<SpdyStream> stream =
3301 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
3302 session, url, MEDIUM, BoundNetLog());
3303 ASSERT_TRUE(stream.get() != NULL);
3304 EXPECT_EQ(0u, stream->stream_id());
3306 DropReceivedDataDelegate delegate(stream, msg_data);
3307 stream->SetDelegate(&delegate);
3309 scoped_ptr<SpdyHeaderBlock> headers(
3310 spdy_util_.ConstructPostHeaderBlock(url.spec(), msg_data_size));
3311 EXPECT_EQ(ERR_IO_PENDING,
3312 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
3313 EXPECT_TRUE(stream->HasUrlFromHeaders());
3315 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3316 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3318 data.RunFor(4);
3320 EXPECT_TRUE(data.at_write_eof());
3321 EXPECT_TRUE(data.at_read_eof());
3323 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3324 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
3326 stream->Close();
3327 EXPECT_EQ(NULL, stream.get());
3329 EXPECT_EQ(OK, delegate.WaitForClose());
3331 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3332 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
3335 // Send data back and forth but close the stream before its data frame
3336 // can be written to the socket. The send window should then increase
3337 // to its original value, i.e. we shouldn't "leak" send window bytes.
3338 TEST_P(SpdySessionTest, SessionFlowControlNoSendLeaks) {
3339 if (GetParam() < kProtoSPDY31)
3340 return;
3342 const char kStreamUrl[] = "http://www.google.com/";
3344 const int32 msg_data_size = 100;
3345 const std::string msg_data(msg_data_size, 'a');
3347 MockConnect connect_data(SYNCHRONOUS, OK);
3349 scoped_ptr<SpdyFrame> req(
3350 spdy_util_.ConstructSpdyPost(
3351 kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0));
3352 MockWrite writes[] = {
3353 CreateMockWrite(*req, 0),
3356 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3357 MockRead reads[] = {
3358 CreateMockRead(*resp, 1),
3359 MockRead(ASYNC, 0, 2) // EOF
3362 // Create SpdySession and SpdyStream and send the request.
3363 DeterministicSocketData data(reads, arraysize(reads),
3364 writes, arraysize(writes));
3365 data.set_connect_data(connect_data);
3366 session_deps_.host_resolver->set_synchronous_mode(true);
3367 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3369 CreateDeterministicNetworkSession();
3371 base::WeakPtr<SpdySession> session =
3372 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3374 GURL url(kStreamUrl);
3375 base::WeakPtr<SpdyStream> stream =
3376 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
3377 session, url, MEDIUM, BoundNetLog());
3378 ASSERT_TRUE(stream.get() != NULL);
3379 EXPECT_EQ(0u, stream->stream_id());
3381 test::StreamDelegateSendImmediate delegate(stream, msg_data);
3382 stream->SetDelegate(&delegate);
3384 scoped_ptr<SpdyHeaderBlock> headers(
3385 spdy_util_.ConstructPostHeaderBlock(url.spec(), msg_data_size));
3386 EXPECT_EQ(ERR_IO_PENDING,
3387 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
3388 EXPECT_TRUE(stream->HasUrlFromHeaders());
3390 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3392 data.RunFor(1);
3394 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3396 data.RunFor(1);
3398 EXPECT_TRUE(data.at_write_eof());
3399 EXPECT_TRUE(data.at_read_eof());
3401 EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
3402 session->session_send_window_size_);
3404 // Closing the stream should increase the session's send window.
3405 stream->Close();
3406 EXPECT_EQ(NULL, stream.get());
3408 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3410 EXPECT_EQ(OK, delegate.WaitForClose());
3413 // Send data back and forth; the send and receive windows should
3414 // change appropriately.
3415 TEST_P(SpdySessionTest, SessionFlowControlEndToEnd) {
3416 if (GetParam() < kProtoSPDY31)
3417 return;
3419 const char kStreamUrl[] = "http://www.google.com/";
3421 const int32 msg_data_size = 100;
3422 const std::string msg_data(msg_data_size, 'a');
3424 MockConnect connect_data(SYNCHRONOUS, OK);
3426 scoped_ptr<SpdyFrame> req(
3427 spdy_util_.ConstructSpdyPost(
3428 kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0));
3429 scoped_ptr<SpdyFrame> msg(
3430 spdy_util_.ConstructSpdyBodyFrame(
3431 1, msg_data.data(), msg_data_size, false));
3432 MockWrite writes[] = {
3433 CreateMockWrite(*req, 0),
3434 CreateMockWrite(*msg, 2),
3437 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3438 scoped_ptr<SpdyFrame> echo(
3439 spdy_util_.ConstructSpdyBodyFrame(
3440 1, msg_data.data(), msg_data_size, false));
3441 scoped_ptr<SpdyFrame> window_update(
3442 spdy_util_.ConstructSpdyWindowUpdate(
3443 kSessionFlowControlStreamId, msg_data_size));
3444 MockRead reads[] = {
3445 CreateMockRead(*resp, 1),
3446 CreateMockRead(*echo, 3),
3447 CreateMockRead(*window_update, 4),
3448 MockRead(ASYNC, 0, 5) // EOF
3451 // Create SpdySession and SpdyStream and send the request.
3452 DeterministicSocketData data(reads, arraysize(reads),
3453 writes, arraysize(writes));
3454 data.set_connect_data(connect_data);
3455 session_deps_.host_resolver->set_synchronous_mode(true);
3456 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3458 CreateDeterministicNetworkSession();
3460 base::WeakPtr<SpdySession> session =
3461 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3463 GURL url(kStreamUrl);
3464 base::WeakPtr<SpdyStream> stream =
3465 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
3466 session, url, MEDIUM, BoundNetLog());
3467 ASSERT_TRUE(stream.get() != NULL);
3468 EXPECT_EQ(0u, stream->stream_id());
3470 test::StreamDelegateSendImmediate delegate(stream, msg_data);
3471 stream->SetDelegate(&delegate);
3473 scoped_ptr<SpdyHeaderBlock> headers(
3474 spdy_util_.ConstructPostHeaderBlock(url.spec(), msg_data_size));
3475 EXPECT_EQ(ERR_IO_PENDING,
3476 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
3477 EXPECT_TRUE(stream->HasUrlFromHeaders());
3479 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3480 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3481 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3483 data.RunFor(1);
3485 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3486 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3487 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3489 data.RunFor(1);
3491 EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
3492 session->session_send_window_size_);
3493 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3494 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3496 data.RunFor(1);
3498 EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
3499 session->session_send_window_size_);
3500 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3501 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3503 data.RunFor(1);
3505 EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
3506 session->session_send_window_size_);
3507 EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
3508 session->session_recv_window_size_);
3509 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3511 data.RunFor(1);
3513 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3514 EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
3515 session->session_recv_window_size_);
3516 EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
3518 EXPECT_TRUE(data.at_write_eof());
3519 EXPECT_TRUE(data.at_read_eof());
3521 EXPECT_EQ(msg_data, delegate.TakeReceivedData());
3523 // Draining the delegate's read queue should increase the session's
3524 // receive window.
3525 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3526 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3527 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
3529 stream->Close();
3530 EXPECT_EQ(NULL, stream.get());
3532 EXPECT_EQ(OK, delegate.WaitForClose());
3534 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
3535 EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
3536 EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
3539 // Given a stall function and an unstall function, runs a test to make
3540 // sure that a stream resumes after unstall.
3541 void SpdySessionTest::RunResumeAfterUnstallTest(
3542 const base::Callback<void(SpdySession*, SpdyStream*)>& stall_function,
3543 const base::Callback<void(SpdySession*, SpdyStream*, int32)>&
3544 unstall_function) {
3545 const char kStreamUrl[] = "http://www.google.com/";
3546 GURL url(kStreamUrl);
3548 session_deps_.host_resolver->set_synchronous_mode(true);
3550 scoped_ptr<SpdyFrame> req(
3551 spdy_util_.ConstructSpdyPost(
3552 kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
3553 scoped_ptr<SpdyFrame> body(
3554 spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, true));
3555 MockWrite writes[] = {
3556 CreateMockWrite(*req, 0),
3557 CreateMockWrite(*body, 1),
3560 scoped_ptr<SpdyFrame> resp(
3561 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3562 scoped_ptr<SpdyFrame> echo(
3563 spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false));
3564 MockRead reads[] = {
3565 CreateMockRead(*resp, 2),
3566 MockRead(ASYNC, 0, 0, 3), // EOF
3569 DeterministicSocketData data(reads, arraysize(reads),
3570 writes, arraysize(writes));
3571 MockConnect connect_data(SYNCHRONOUS, OK);
3572 data.set_connect_data(connect_data);
3574 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3576 CreateDeterministicNetworkSession();
3577 base::WeakPtr<SpdySession> session =
3578 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3579 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
3580 session->flow_control_state());
3582 base::WeakPtr<SpdyStream> stream =
3583 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
3584 session, url, LOWEST, BoundNetLog());
3585 ASSERT_TRUE(stream.get() != NULL);
3587 test::StreamDelegateWithBody delegate(stream, kBodyDataStringPiece);
3588 stream->SetDelegate(&delegate);
3590 EXPECT_FALSE(stream->HasUrlFromHeaders());
3591 EXPECT_FALSE(stream->send_stalled_by_flow_control());
3593 scoped_ptr<SpdyHeaderBlock> headers(
3594 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
3595 EXPECT_EQ(ERR_IO_PENDING,
3596 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
3597 EXPECT_TRUE(stream->HasUrlFromHeaders());
3598 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
3600 stall_function.Run(session.get(), stream.get());
3602 data.RunFor(1);
3604 EXPECT_TRUE(stream->send_stalled_by_flow_control());
3606 unstall_function.Run(session.get(), stream.get(), kBodyDataSize);
3608 EXPECT_FALSE(stream->send_stalled_by_flow_control());
3610 data.RunFor(3);
3612 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
3614 EXPECT_TRUE(delegate.send_headers_completed());
3615 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
3616 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
3617 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
3618 EXPECT_TRUE(data.at_write_eof());
3621 // Run the resume-after-unstall test with all possible stall and
3622 // unstall sequences.
3624 TEST_P(SpdySessionTest, ResumeAfterUnstallSession) {
3625 if (GetParam() < kProtoSPDY31)
3626 return;
3628 RunResumeAfterUnstallTest(
3629 base::Bind(&SpdySessionTest::StallSessionOnly,
3630 base::Unretained(this)),
3631 base::Bind(&SpdySessionTest::UnstallSessionOnly,
3632 base::Unretained(this)));
3635 // Equivalent to
3636 // SpdyStreamTest.ResumeAfterSendWindowSizeIncrease.
3637 TEST_P(SpdySessionTest, ResumeAfterUnstallStream) {
3638 if (GetParam() < kProtoSPDY31)
3639 return;
3641 RunResumeAfterUnstallTest(
3642 base::Bind(&SpdySessionTest::StallStreamOnly,
3643 base::Unretained(this)),
3644 base::Bind(&SpdySessionTest::UnstallStreamOnly,
3645 base::Unretained(this)));
3648 TEST_P(SpdySessionTest, StallSessionStreamResumeAfterUnstallSessionStream) {
3649 if (GetParam() < kProtoSPDY31)
3650 return;
3652 RunResumeAfterUnstallTest(
3653 base::Bind(&SpdySessionTest::StallSessionStream,
3654 base::Unretained(this)),
3655 base::Bind(&SpdySessionTest::UnstallSessionStream,
3656 base::Unretained(this)));
3659 TEST_P(SpdySessionTest, StallStreamSessionResumeAfterUnstallSessionStream) {
3660 if (GetParam() < kProtoSPDY31)
3661 return;
3663 RunResumeAfterUnstallTest(
3664 base::Bind(&SpdySessionTest::StallStreamSession,
3665 base::Unretained(this)),
3666 base::Bind(&SpdySessionTest::UnstallSessionStream,
3667 base::Unretained(this)));
3670 TEST_P(SpdySessionTest, StallStreamSessionResumeAfterUnstallStreamSession) {
3671 if (GetParam() < kProtoSPDY31)
3672 return;
3674 RunResumeAfterUnstallTest(
3675 base::Bind(&SpdySessionTest::StallStreamSession,
3676 base::Unretained(this)),
3677 base::Bind(&SpdySessionTest::UnstallStreamSession,
3678 base::Unretained(this)));
3681 TEST_P(SpdySessionTest, StallSessionStreamResumeAfterUnstallStreamSession) {
3682 if (GetParam() < kProtoSPDY31)
3683 return;
3685 RunResumeAfterUnstallTest(
3686 base::Bind(&SpdySessionTest::StallSessionStream,
3687 base::Unretained(this)),
3688 base::Bind(&SpdySessionTest::UnstallStreamSession,
3689 base::Unretained(this)));
3692 // Cause a stall by reducing the flow control send window to 0. The
3693 // streams should resume in priority order when that window is then
3694 // increased.
3695 TEST_P(SpdySessionTest, ResumeByPriorityAfterSendWindowSizeIncrease) {
3696 if (GetParam() < kProtoSPDY31)
3697 return;
3699 const char kStreamUrl[] = "http://www.google.com/";
3700 GURL url(kStreamUrl);
3702 session_deps_.host_resolver->set_synchronous_mode(true);
3704 scoped_ptr<SpdyFrame> req1(
3705 spdy_util_.ConstructSpdyPost(
3706 kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
3707 scoped_ptr<SpdyFrame> req2(
3708 spdy_util_.ConstructSpdyPost(
3709 kStreamUrl, 3, kBodyDataSize, MEDIUM, NULL, 0));
3710 scoped_ptr<SpdyFrame> body1(
3711 spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, true));
3712 scoped_ptr<SpdyFrame> body2(
3713 spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true));
3714 MockWrite writes[] = {
3715 CreateMockWrite(*req1, 0),
3716 CreateMockWrite(*req2, 1),
3717 CreateMockWrite(*body2, 2),
3718 CreateMockWrite(*body1, 3),
3721 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
3722 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
3723 MockRead reads[] = {
3724 CreateMockRead(*resp1, 4),
3725 CreateMockRead(*resp2, 5),
3726 MockRead(ASYNC, 0, 0, 6), // EOF
3729 DeterministicSocketData data(reads, arraysize(reads),
3730 writes, arraysize(writes));
3731 MockConnect connect_data(SYNCHRONOUS, OK);
3732 data.set_connect_data(connect_data);
3734 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3736 CreateDeterministicNetworkSession();
3737 base::WeakPtr<SpdySession> session =
3738 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3739 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
3740 session->flow_control_state());
3742 base::WeakPtr<SpdyStream> stream1 =
3743 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
3744 session, url, LOWEST, BoundNetLog());
3745 ASSERT_TRUE(stream1.get() != NULL);
3747 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
3748 stream1->SetDelegate(&delegate1);
3750 EXPECT_FALSE(stream1->HasUrlFromHeaders());
3752 base::WeakPtr<SpdyStream> stream2 =
3753 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
3754 session, url, MEDIUM, BoundNetLog());
3755 ASSERT_TRUE(stream2.get() != NULL);
3757 test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece);
3758 stream2->SetDelegate(&delegate2);
3760 EXPECT_FALSE(stream2->HasUrlFromHeaders());
3762 EXPECT_FALSE(stream1->send_stalled_by_flow_control());
3763 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
3765 StallSessionSend(session.get());
3767 scoped_ptr<SpdyHeaderBlock> headers1(
3768 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
3769 EXPECT_EQ(ERR_IO_PENDING,
3770 stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND));
3771 EXPECT_TRUE(stream1->HasUrlFromHeaders());
3772 EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec());
3774 data.RunFor(1);
3775 EXPECT_EQ(1u, stream1->stream_id());
3776 EXPECT_TRUE(stream1->send_stalled_by_flow_control());
3778 scoped_ptr<SpdyHeaderBlock> headers2(
3779 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
3780 EXPECT_EQ(ERR_IO_PENDING,
3781 stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND));
3782 EXPECT_TRUE(stream2->HasUrlFromHeaders());
3783 EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec());
3785 data.RunFor(1);
3786 EXPECT_EQ(3u, stream2->stream_id());
3787 EXPECT_TRUE(stream2->send_stalled_by_flow_control());
3789 // This should unstall only stream2.
3790 UnstallSessionSend(session.get(), kBodyDataSize);
3792 EXPECT_TRUE(stream1->send_stalled_by_flow_control());
3793 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
3795 data.RunFor(1);
3797 EXPECT_TRUE(stream1->send_stalled_by_flow_control());
3798 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
3800 // This should then unstall stream1.
3801 UnstallSessionSend(session.get(), kBodyDataSize);
3803 EXPECT_FALSE(stream1->send_stalled_by_flow_control());
3804 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
3806 data.RunFor(4);
3808 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
3809 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
3811 EXPECT_TRUE(delegate1.send_headers_completed());
3812 EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status"));
3813 EXPECT_EQ("HTTP/1.1", delegate1.GetResponseHeaderValue(":version"));
3814 EXPECT_EQ(std::string(), delegate1.TakeReceivedData());
3816 EXPECT_TRUE(delegate2.send_headers_completed());
3817 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status"));
3818 EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version"));
3819 EXPECT_EQ(std::string(), delegate2.TakeReceivedData());
3821 EXPECT_TRUE(data.at_write_eof());
3824 // Delegate that closes a given stream after sending its body.
3825 class StreamClosingDelegate : public test::StreamDelegateWithBody {
3826 public:
3827 StreamClosingDelegate(const base::WeakPtr<SpdyStream>& stream,
3828 base::StringPiece data)
3829 : StreamDelegateWithBody(stream, data) {}
3831 virtual ~StreamClosingDelegate() {}
3833 void set_stream_to_close(const base::WeakPtr<SpdyStream>& stream_to_close) {
3834 stream_to_close_ = stream_to_close;
3837 virtual void OnDataSent() OVERRIDE {
3838 test::StreamDelegateWithBody::OnDataSent();
3839 if (stream_to_close_.get()) {
3840 stream_to_close_->Close();
3841 EXPECT_EQ(NULL, stream_to_close_.get());
3845 private:
3846 base::WeakPtr<SpdyStream> stream_to_close_;
3849 // Cause a stall by reducing the flow control send window to
3850 // 0. Unstalling the session should properly handle deleted streams.
3851 TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) {
3852 if (GetParam() < kProtoSPDY31)
3853 return;
3855 const char kStreamUrl[] = "http://www.google.com/";
3856 GURL url(kStreamUrl);
3858 session_deps_.host_resolver->set_synchronous_mode(true);
3860 scoped_ptr<SpdyFrame> req1(
3861 spdy_util_.ConstructSpdyPost(
3862 kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
3863 scoped_ptr<SpdyFrame> req2(
3864 spdy_util_.ConstructSpdyPost(
3865 kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0));
3866 scoped_ptr<SpdyFrame> req3(
3867 spdy_util_.ConstructSpdyPost(
3868 kStreamUrl, 5, kBodyDataSize, LOWEST, NULL, 0));
3869 scoped_ptr<SpdyFrame> body2(
3870 spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true));
3871 MockWrite writes[] = {
3872 CreateMockWrite(*req1, 0),
3873 CreateMockWrite(*req2, 1),
3874 CreateMockWrite(*req3, 2),
3875 CreateMockWrite(*body2, 3),
3878 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
3879 MockRead reads[] = {
3880 CreateMockRead(*resp2, 4),
3881 MockRead(ASYNC, 0, 0, 5), // EOF
3884 DeterministicSocketData data(reads, arraysize(reads),
3885 writes, arraysize(writes));
3886 MockConnect connect_data(SYNCHRONOUS, OK);
3887 data.set_connect_data(connect_data);
3889 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
3891 CreateDeterministicNetworkSession();
3892 base::WeakPtr<SpdySession> session =
3893 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
3894 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
3895 session->flow_control_state());
3897 base::WeakPtr<SpdyStream> stream1 =
3898 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
3899 session, url, LOWEST, BoundNetLog());
3900 ASSERT_TRUE(stream1.get() != NULL);
3902 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
3903 stream1->SetDelegate(&delegate1);
3905 EXPECT_FALSE(stream1->HasUrlFromHeaders());
3907 base::WeakPtr<SpdyStream> stream2 =
3908 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
3909 session, url, LOWEST, BoundNetLog());
3910 ASSERT_TRUE(stream2.get() != NULL);
3912 StreamClosingDelegate delegate2(stream2, kBodyDataStringPiece);
3913 stream2->SetDelegate(&delegate2);
3915 EXPECT_FALSE(stream2->HasUrlFromHeaders());
3917 base::WeakPtr<SpdyStream> stream3 =
3918 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
3919 session, url, LOWEST, BoundNetLog());
3920 ASSERT_TRUE(stream3.get() != NULL);
3922 test::StreamDelegateWithBody delegate3(stream3, kBodyDataStringPiece);
3923 stream3->SetDelegate(&delegate3);
3925 EXPECT_FALSE(stream3->HasUrlFromHeaders());
3927 EXPECT_FALSE(stream1->send_stalled_by_flow_control());
3928 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
3929 EXPECT_FALSE(stream3->send_stalled_by_flow_control());
3931 StallSessionSend(session.get());
3933 scoped_ptr<SpdyHeaderBlock> headers1(
3934 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
3935 EXPECT_EQ(ERR_IO_PENDING,
3936 stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND));
3937 EXPECT_TRUE(stream1->HasUrlFromHeaders());
3938 EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec());
3940 data.RunFor(1);
3941 EXPECT_EQ(1u, stream1->stream_id());
3942 EXPECT_TRUE(stream1->send_stalled_by_flow_control());
3944 scoped_ptr<SpdyHeaderBlock> headers2(
3945 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
3946 EXPECT_EQ(ERR_IO_PENDING,
3947 stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND));
3948 EXPECT_TRUE(stream2->HasUrlFromHeaders());
3949 EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec());
3951 data.RunFor(1);
3952 EXPECT_EQ(3u, stream2->stream_id());
3953 EXPECT_TRUE(stream2->send_stalled_by_flow_control());
3955 scoped_ptr<SpdyHeaderBlock> headers3(
3956 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
3957 EXPECT_EQ(ERR_IO_PENDING,
3958 stream3->SendRequestHeaders(headers3.Pass(), MORE_DATA_TO_SEND));
3959 EXPECT_TRUE(stream3->HasUrlFromHeaders());
3960 EXPECT_EQ(kStreamUrl, stream3->GetUrlFromHeaders().spec());
3962 data.RunFor(1);
3963 EXPECT_EQ(5u, stream3->stream_id());
3964 EXPECT_TRUE(stream3->send_stalled_by_flow_control());
3966 SpdyStreamId stream_id1 = stream1->stream_id();
3967 SpdyStreamId stream_id2 = stream2->stream_id();
3968 SpdyStreamId stream_id3 = stream3->stream_id();
3970 // Close stream1 preemptively.
3971 session->CloseActiveStream(stream_id1, ERR_CONNECTION_CLOSED);
3972 EXPECT_EQ(NULL, stream1.get());
3974 EXPECT_FALSE(session->IsStreamActive(stream_id1));
3975 EXPECT_TRUE(session->IsStreamActive(stream_id2));
3976 EXPECT_TRUE(session->IsStreamActive(stream_id3));
3978 // Unstall stream2, which should then close stream3.
3979 delegate2.set_stream_to_close(stream3);
3980 UnstallSessionSend(session.get(), kBodyDataSize);
3982 data.RunFor(1);
3983 EXPECT_EQ(NULL, stream3.get());
3985 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
3986 EXPECT_FALSE(session->IsStreamActive(stream_id1));
3987 EXPECT_TRUE(session->IsStreamActive(stream_id2));
3988 EXPECT_FALSE(session->IsStreamActive(stream_id3));
3990 data.RunFor(2);
3991 EXPECT_EQ(NULL, stream2.get());
3993 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
3994 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
3995 EXPECT_EQ(OK, delegate3.WaitForClose());
3997 EXPECT_TRUE(delegate1.send_headers_completed());
3998 EXPECT_EQ(std::string(), delegate1.TakeReceivedData());
4000 EXPECT_TRUE(delegate2.send_headers_completed());
4001 EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status"));
4002 EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version"));
4003 EXPECT_EQ(std::string(), delegate2.TakeReceivedData());
4005 EXPECT_TRUE(delegate3.send_headers_completed());
4006 EXPECT_EQ(std::string(), delegate3.TakeReceivedData());
4008 EXPECT_TRUE(data.at_write_eof());
4011 // Cause a stall by reducing the flow control send window to
4012 // 0. Unstalling the session should properly handle the session itself
4013 // being closed.
4014 TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) {
4015 if (GetParam() < kProtoSPDY31)
4016 return;
4018 const char kStreamUrl[] = "http://www.google.com/";
4019 GURL url(kStreamUrl);
4021 session_deps_.host_resolver->set_synchronous_mode(true);
4023 scoped_ptr<SpdyFrame> req1(
4024 spdy_util_.ConstructSpdyPost(
4025 kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
4026 scoped_ptr<SpdyFrame> req2(
4027 spdy_util_.ConstructSpdyPost(
4028 kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0));
4029 scoped_ptr<SpdyFrame> body1(
4030 spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false));
4031 MockWrite writes[] = {
4032 CreateMockWrite(*req1, 0),
4033 CreateMockWrite(*req2, 1),
4036 MockRead reads[] = {
4037 MockRead(ASYNC, 0, 0, 2), // EOF
4040 DeterministicSocketData data(reads, arraysize(reads),
4041 writes, arraysize(writes));
4042 MockConnect connect_data(SYNCHRONOUS, OK);
4043 data.set_connect_data(connect_data);
4045 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
4047 CreateDeterministicNetworkSession();
4048 base::WeakPtr<SpdySession> session =
4049 CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
4050 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
4051 session->flow_control_state());
4053 base::WeakPtr<SpdyStream> stream1 =
4054 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
4055 session, url, LOWEST, BoundNetLog());
4056 ASSERT_TRUE(stream1.get() != NULL);
4058 test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
4059 stream1->SetDelegate(&delegate1);
4061 EXPECT_FALSE(stream1->HasUrlFromHeaders());
4063 base::WeakPtr<SpdyStream> stream2 =
4064 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
4065 session, url, LOWEST, BoundNetLog());
4066 ASSERT_TRUE(stream2.get() != NULL);
4068 test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece);
4069 stream2->SetDelegate(&delegate2);
4071 EXPECT_FALSE(stream2->HasUrlFromHeaders());
4073 EXPECT_FALSE(stream1->send_stalled_by_flow_control());
4074 EXPECT_FALSE(stream2->send_stalled_by_flow_control());
4076 StallSessionSend(session.get());
4078 scoped_ptr<SpdyHeaderBlock> headers1(
4079 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
4080 EXPECT_EQ(ERR_IO_PENDING,
4081 stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND));
4082 EXPECT_TRUE(stream1->HasUrlFromHeaders());
4083 EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec());
4085 data.RunFor(1);
4086 EXPECT_EQ(1u, stream1->stream_id());
4087 EXPECT_TRUE(stream1->send_stalled_by_flow_control());
4089 scoped_ptr<SpdyHeaderBlock> headers2(
4090 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
4091 EXPECT_EQ(ERR_IO_PENDING,
4092 stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND));
4093 EXPECT_TRUE(stream2->HasUrlFromHeaders());
4094 EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec());
4096 data.RunFor(1);
4097 EXPECT_EQ(3u, stream2->stream_id());
4098 EXPECT_TRUE(stream2->send_stalled_by_flow_control());
4100 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
4102 // Unstall stream1.
4103 UnstallSessionSend(session.get(), kBodyDataSize);
4105 // Close the session (since we can't do it from within the delegate
4106 // method, since it's in the stream's loop).
4107 session->CloseSessionOnError(ERR_CONNECTION_CLOSED, "Closing session");
4108 EXPECT_TRUE(session == NULL);
4110 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
4112 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
4113 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
4115 EXPECT_TRUE(delegate1.send_headers_completed());
4116 EXPECT_EQ(std::string(), delegate1.TakeReceivedData());
4118 EXPECT_TRUE(delegate2.send_headers_completed());
4119 EXPECT_EQ(std::string(), delegate2.TakeReceivedData());
4121 EXPECT_TRUE(data.at_write_eof());
4124 TEST(MapFramerErrorToProtocolError, MapsValues) {
4125 CHECK_EQ(SPDY_ERROR_INVALID_CONTROL_FRAME,
4126 MapFramerErrorToProtocolError(
4127 SpdyFramer::SPDY_INVALID_CONTROL_FRAME));
4128 CHECK_EQ(SPDY_ERROR_INVALID_DATA_FRAME_FLAGS,
4129 MapFramerErrorToProtocolError(
4130 SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS));
4131 CHECK_EQ(SPDY_ERROR_GOAWAY_FRAME_CORRUPT,
4132 MapFramerErrorToProtocolError(
4133 SpdyFramer::SPDY_GOAWAY_FRAME_CORRUPT));
4134 CHECK_EQ(SPDY_ERROR_UNEXPECTED_FRAME,
4135 MapFramerErrorToProtocolError(
4136 SpdyFramer::SPDY_UNEXPECTED_FRAME));
4139 TEST(MapRstStreamStatusToProtocolError, MapsValues) {
4140 CHECK_EQ(STATUS_CODE_PROTOCOL_ERROR,
4141 MapRstStreamStatusToProtocolError(
4142 RST_STREAM_PROTOCOL_ERROR));
4143 CHECK_EQ(STATUS_CODE_FRAME_TOO_LARGE,
4144 MapRstStreamStatusToProtocolError(
4145 RST_STREAM_FRAME_TOO_LARGE));
4148 } // namespace net