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"
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"
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
;
49 class SpdySessionTest
: public PlatformTest
,
50 public ::testing::WithParamInterface
<NextProto
> {
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
,
74 int32 delta_window_size
) {
75 UnstallSessionSend(session
, delta_window_size
);
78 void UnstallStreamOnly(SpdySession
* session
,
80 int32 delta_window_size
) {
81 UnstallStreamSend(stream
, delta_window_size
);
84 void UnstallSessionStream(SpdySession
* session
,
86 int32 delta_window_size
) {
87 UnstallSessionSend(session
, delta_window_size
);
88 UnstallStreamSend(stream
, delta_window_size
);
91 void UnstallStreamSession(SpdySession
* session
,
93 int32 delta_window_size
) {
94 UnstallStreamSend(stream
, delta_window_size
);
95 UnstallSessionSend(session
, delta_window_size
);
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
),
108 test_host_port_pair_(kTestHost
, kTestPort
),
109 key_(test_host_port_pair_
, ProxyServer::Direct(),
110 PRIVACY_MODE_DISABLED
) {
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() {
128 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
129 spdy_session_pool_
= http_session_
->spdy_session_pool();
132 void CreateNetworkSession() {
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
)>&
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_
;
177 HostPortPair test_host_port_pair_
;
181 INSTANTIATE_TEST_CASE_P(
184 testing::Values(kProtoDeprecatedSPDY2
,
185 kProtoSPDY3
, kProtoSPDY31
, kProtoSPDY4
));
187 // Try to create a SPDY session that will fail during
188 // initialization. Nothing should blow up.
189 TEST_P(SpdySessionTest
, InitialReadError
) {
190 CreateDeterministicNetworkSession();
192 base::WeakPtr
<SpdySession
> session
= TryCreateFakeSpdySessionExpectingFailure(
193 spdy_session_pool_
, key_
, ERR_FAILED
);
194 EXPECT_TRUE(session
);
196 base::RunLoop().RunUntilIdle();
197 EXPECT_FALSE(session
);
202 // A helper class that vends a callback that, when fired, destroys a
203 // given SpdyStreamRequest.
204 class StreamRequestDestroyingCallback
: public TestCompletionCallbackBase
{
206 StreamRequestDestroyingCallback() {}
208 virtual ~StreamRequestDestroyingCallback() {}
210 void SetRequestToDestroy(scoped_ptr
<SpdyStreamRequest
> request
) {
211 request_
= request
.Pass();
214 CompletionCallback
MakeCallback() {
215 return base::Bind(&StreamRequestDestroyingCallback::OnComplete
,
216 base::Unretained(this));
220 void OnComplete(int result
) {
225 scoped_ptr
<SpdyStreamRequest
> request_
;
230 // Request kInitialMaxConcurrentStreams streams. Request two more
231 // streams, but have the callback for one destroy the second stream
232 // request. Close the session. Nothing should blow up. This is a
233 // regression test for http://crbug.com/250841 .
234 TEST_P(SpdySessionTest
, PendingStreamCancellingAnother
) {
235 session_deps_
.host_resolver
->set_synchronous_mode(true);
237 MockRead reads
[] = {MockRead(ASYNC
, 0, 0), };
239 DeterministicSocketData
data(reads
, arraysize(reads
), NULL
, 0);
240 MockConnect
connect_data(SYNCHRONOUS
, OK
);
241 data
.set_connect_data(connect_data
);
242 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
244 CreateDeterministicNetworkSession();
246 base::WeakPtr
<SpdySession
> session
=
247 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
249 // Create the maximum number of concurrent streams.
250 for (size_t i
= 0; i
< kInitialMaxConcurrentStreams
; ++i
) {
251 base::WeakPtr
<SpdyStream
> spdy_stream
= CreateStreamSynchronously(
252 SPDY_BIDIRECTIONAL_STREAM
, session
, test_url_
, MEDIUM
, BoundNetLog());
253 ASSERT_TRUE(spdy_stream
!= NULL
);
256 SpdyStreamRequest request1
;
257 scoped_ptr
<SpdyStreamRequest
> request2(new SpdyStreamRequest
);
259 StreamRequestDestroyingCallback callback1
;
260 ASSERT_EQ(ERR_IO_PENDING
,
261 request1
.StartRequest(SPDY_BIDIRECTIONAL_STREAM
,
266 callback1
.MakeCallback()));
268 // |callback2| is never called.
269 TestCompletionCallback callback2
;
270 ASSERT_EQ(ERR_IO_PENDING
,
271 request2
->StartRequest(SPDY_BIDIRECTIONAL_STREAM
,
276 callback2
.callback()));
278 callback1
.SetRequestToDestroy(request2
.Pass());
280 session
->CloseSessionOnError(ERR_ABORTED
, "Aborting session");
282 EXPECT_EQ(ERR_ABORTED
, callback1
.WaitForResult());
285 // A session receiving a GOAWAY frame with no active streams should
286 // immediately close.
287 TEST_P(SpdySessionTest
, GoAwayWithNoActiveStreams
) {
288 session_deps_
.host_resolver
->set_synchronous_mode(true);
290 MockConnect
connect_data(SYNCHRONOUS
, OK
);
291 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
293 CreateMockRead(*goaway
, 0),
295 DeterministicSocketData
data(reads
, arraysize(reads
), NULL
, 0);
296 data
.set_connect_data(connect_data
);
297 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
299 CreateDeterministicNetworkSession();
301 base::WeakPtr
<SpdySession
> session
=
302 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
304 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
306 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
308 // Read and process the GOAWAY frame.
311 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
313 EXPECT_TRUE(session
== NULL
);
316 // A session receiving a GOAWAY frame immediately with no active
317 // streams should then close.
318 TEST_P(SpdySessionTest
, GoAwayImmediatelyWithNoActiveStreams
) {
319 session_deps_
.host_resolver
->set_synchronous_mode(true);
321 MockConnect
connect_data(SYNCHRONOUS
, OK
);
322 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
324 CreateMockRead(*goaway
, 0, SYNCHRONOUS
),
326 DeterministicSocketData
data(reads
, arraysize(reads
), NULL
, 0);
327 data
.set_connect_data(connect_data
);
328 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
330 CreateDeterministicNetworkSession();
334 base::WeakPtr
<SpdySession
> session
=
335 TryCreateInsecureSpdySessionExpectingFailure(
336 http_session_
, key_
, ERR_CONNECTION_CLOSED
, BoundNetLog());
337 base::RunLoop().RunUntilIdle();
339 EXPECT_FALSE(session
);
340 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
343 // A session receiving a GOAWAY frame with active streams should close
344 // when the last active stream is closed.
345 TEST_P(SpdySessionTest
, GoAwayWithActiveStreams
) {
346 session_deps_
.host_resolver
->set_synchronous_mode(true);
348 MockConnect
connect_data(SYNCHRONOUS
, OK
);
349 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
351 CreateMockRead(*goaway
, 2),
352 MockRead(ASYNC
, 0, 3) // EOF
354 scoped_ptr
<SpdyFrame
> req1(
355 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
356 scoped_ptr
<SpdyFrame
> req2(
357 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, MEDIUM
, true));
358 MockWrite writes
[] = {
359 CreateMockWrite(*req1
, 0),
360 CreateMockWrite(*req2
, 1),
362 DeterministicSocketData
data(reads
, arraysize(reads
),
363 writes
, arraysize(writes
));
364 data
.set_connect_data(connect_data
);
365 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
367 CreateDeterministicNetworkSession();
369 base::WeakPtr
<SpdySession
> session
=
370 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
372 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
374 GURL
url(kDefaultURL
);
375 base::WeakPtr
<SpdyStream
> spdy_stream1
=
376 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
377 session
, url
, MEDIUM
, BoundNetLog());
378 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
379 spdy_stream1
->SetDelegate(&delegate1
);
381 base::WeakPtr
<SpdyStream
> spdy_stream2
=
382 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
383 session
, url
, MEDIUM
, BoundNetLog());
384 test::StreamDelegateDoNothing
delegate2(spdy_stream2
);
385 spdy_stream2
->SetDelegate(&delegate2
);
387 scoped_ptr
<SpdyHeaderBlock
> headers(
388 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
389 scoped_ptr
<SpdyHeaderBlock
> headers2(new SpdyHeaderBlock(*headers
));
391 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
392 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
393 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
394 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
398 EXPECT_EQ(1u, spdy_stream1
->stream_id());
399 EXPECT_EQ(3u, spdy_stream2
->stream_id());
401 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
403 // Read and process the GOAWAY frame.
406 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
408 EXPECT_FALSE(session
->IsStreamActive(3));
409 EXPECT_EQ(NULL
, spdy_stream2
.get());
410 EXPECT_TRUE(session
->IsStreamActive(1));
412 EXPECT_FALSE(session
->IsClosed());
414 // Should close the session.
415 spdy_stream1
->Close();
416 EXPECT_EQ(NULL
, spdy_stream1
.get());
418 EXPECT_TRUE(session
== NULL
);
421 // Have a session receive two GOAWAY frames, with the last one causing
422 // the last active stream to be closed. The session should then be
423 // closed after the second GOAWAY frame.
424 TEST_P(SpdySessionTest
, GoAwayTwice
) {
425 session_deps_
.host_resolver
->set_synchronous_mode(true);
427 MockConnect
connect_data(SYNCHRONOUS
, OK
);
428 scoped_ptr
<SpdyFrame
> goaway1(spdy_util_
.ConstructSpdyGoAway(1));
429 scoped_ptr
<SpdyFrame
> goaway2(spdy_util_
.ConstructSpdyGoAway(0));
431 CreateMockRead(*goaway1
, 2),
432 CreateMockRead(*goaway2
, 3),
433 MockRead(ASYNC
, 0, 4) // EOF
435 scoped_ptr
<SpdyFrame
> req1(
436 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
437 scoped_ptr
<SpdyFrame
> req2(
438 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, MEDIUM
, true));
439 MockWrite writes
[] = {
440 CreateMockWrite(*req1
, 0),
441 CreateMockWrite(*req2
, 1),
443 DeterministicSocketData
data(reads
, arraysize(reads
),
444 writes
, arraysize(writes
));
445 data
.set_connect_data(connect_data
);
446 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
448 CreateDeterministicNetworkSession();
450 base::WeakPtr
<SpdySession
> session
=
451 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
453 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
455 GURL
url(kDefaultURL
);
456 base::WeakPtr
<SpdyStream
> spdy_stream1
=
457 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
458 session
, url
, MEDIUM
, BoundNetLog());
459 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
460 spdy_stream1
->SetDelegate(&delegate1
);
462 base::WeakPtr
<SpdyStream
> spdy_stream2
=
463 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
464 session
, url
, MEDIUM
, BoundNetLog());
465 test::StreamDelegateDoNothing
delegate2(spdy_stream2
);
466 spdy_stream2
->SetDelegate(&delegate2
);
468 scoped_ptr
<SpdyHeaderBlock
> headers(
469 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
470 scoped_ptr
<SpdyHeaderBlock
> headers2(new SpdyHeaderBlock(*headers
));
472 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
473 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
474 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
475 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
479 EXPECT_EQ(1u, spdy_stream1
->stream_id());
480 EXPECT_EQ(3u, spdy_stream2
->stream_id());
482 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
484 // Read and process the first GOAWAY frame.
487 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
489 EXPECT_FALSE(session
->IsStreamActive(3));
490 EXPECT_EQ(NULL
, spdy_stream2
.get());
491 EXPECT_TRUE(session
->IsStreamActive(1));
493 EXPECT_FALSE(session
->IsClosed());
495 // Read and process the second GOAWAY frame, which should close the
499 EXPECT_TRUE(session
== NULL
);
502 // Have a session with active streams receive a GOAWAY frame and then
503 // close it. It should handle the close properly (i.e., not try to
504 // make itself unavailable in its pool twice).
505 TEST_P(SpdySessionTest
, GoAwayWithActiveStreamsThenClose
) {
506 session_deps_
.host_resolver
->set_synchronous_mode(true);
508 MockConnect
connect_data(SYNCHRONOUS
, OK
);
509 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
511 CreateMockRead(*goaway
, 2),
512 MockRead(ASYNC
, 0, 3) // EOF
514 scoped_ptr
<SpdyFrame
> req1(
515 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
516 scoped_ptr
<SpdyFrame
> req2(
517 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, MEDIUM
, true));
518 MockWrite writes
[] = {
519 CreateMockWrite(*req1
, 0),
520 CreateMockWrite(*req2
, 1),
522 DeterministicSocketData
data(reads
, arraysize(reads
),
523 writes
, arraysize(writes
));
524 data
.set_connect_data(connect_data
);
525 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
527 CreateDeterministicNetworkSession();
529 base::WeakPtr
<SpdySession
> session
=
530 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
532 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
534 GURL
url(kDefaultURL
);
535 base::WeakPtr
<SpdyStream
> spdy_stream1
=
536 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
537 session
, url
, MEDIUM
, BoundNetLog());
538 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
539 spdy_stream1
->SetDelegate(&delegate1
);
541 base::WeakPtr
<SpdyStream
> spdy_stream2
=
542 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
543 session
, url
, MEDIUM
, BoundNetLog());
544 test::StreamDelegateDoNothing
delegate2(spdy_stream2
);
545 spdy_stream2
->SetDelegate(&delegate2
);
547 scoped_ptr
<SpdyHeaderBlock
> headers(
548 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
549 scoped_ptr
<SpdyHeaderBlock
> headers2(new SpdyHeaderBlock(*headers
));
551 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
552 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
553 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
554 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
558 EXPECT_EQ(1u, spdy_stream1
->stream_id());
559 EXPECT_EQ(3u, spdy_stream2
->stream_id());
561 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
563 // Read and process the GOAWAY frame.
566 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
568 EXPECT_FALSE(session
->IsStreamActive(3));
569 EXPECT_EQ(NULL
, spdy_stream2
.get());
570 EXPECT_TRUE(session
->IsStreamActive(1));
572 EXPECT_FALSE(session
->IsClosed());
574 session
->CloseSessionOnError(ERR_ABORTED
, "Aborting session");
576 EXPECT_EQ(NULL
, spdy_stream1
.get());
577 EXPECT_TRUE(session
== NULL
);
580 // Try to create a stream after receiving a GOAWAY frame. It should
582 TEST_P(SpdySessionTest
, CreateStreamAfterGoAway
) {
583 session_deps_
.host_resolver
->set_synchronous_mode(true);
585 MockConnect
connect_data(SYNCHRONOUS
, OK
);
586 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
588 CreateMockRead(*goaway
, 1),
589 MockRead(ASYNC
, 0, 2) // EOF
591 scoped_ptr
<SpdyFrame
> req(
592 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
593 MockWrite writes
[] = {
594 CreateMockWrite(*req
, 0),
596 DeterministicSocketData
data(reads
, arraysize(reads
),
597 writes
, arraysize(writes
));
598 data
.set_connect_data(connect_data
);
599 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
601 CreateDeterministicNetworkSession();
603 base::WeakPtr
<SpdySession
> session
=
604 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
606 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
608 GURL
url(kDefaultURL
);
609 base::WeakPtr
<SpdyStream
> spdy_stream
=
610 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
611 session
, url
, MEDIUM
, BoundNetLog());
612 test::StreamDelegateDoNothing
delegate(spdy_stream
);
613 spdy_stream
->SetDelegate(&delegate
);
615 scoped_ptr
<SpdyHeaderBlock
> headers(
616 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
617 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
618 EXPECT_TRUE(spdy_stream
->HasUrlFromHeaders());
622 EXPECT_EQ(1u, spdy_stream
->stream_id());
624 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
626 // Read and process the GOAWAY frame.
629 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
630 EXPECT_TRUE(session
->IsStreamActive(1));
632 SpdyStreamRequest stream_request
;
633 int rv
= stream_request
.StartRequest(
634 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog(),
635 CompletionCallback());
636 EXPECT_EQ(ERR_FAILED
, rv
);
638 // Read and process EOF.
641 EXPECT_TRUE(session
== NULL
);
644 // Receiving a SYN_STREAM frame after a GOAWAY frame should result in
645 // the stream being refused.
646 TEST_P(SpdySessionTest
, SynStreamAfterGoAway
) {
647 session_deps_
.host_resolver
->set_synchronous_mode(true);
649 MockConnect
connect_data(SYNCHRONOUS
, OK
);
650 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
651 scoped_ptr
<SpdyFrame
>
652 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kDefaultURL
));
654 CreateMockRead(*goaway
, 1),
655 CreateMockRead(*push
, 2),
656 MockRead(ASYNC
, 0, 4) // EOF
658 scoped_ptr
<SpdyFrame
> req(
659 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
660 scoped_ptr
<SpdyFrame
> rst(
661 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
662 MockWrite writes
[] = {
663 CreateMockWrite(*req
, 0),
664 CreateMockWrite(*rst
, 3)
666 DeterministicSocketData
data(reads
, arraysize(reads
),
667 writes
, arraysize(writes
));
668 data
.set_connect_data(connect_data
);
669 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
671 CreateDeterministicNetworkSession();
673 base::WeakPtr
<SpdySession
> session
=
674 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
676 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
678 GURL
url(kDefaultURL
);
679 base::WeakPtr
<SpdyStream
> spdy_stream
=
680 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
681 session
, url
, MEDIUM
, BoundNetLog());
682 test::StreamDelegateDoNothing
delegate(spdy_stream
);
683 spdy_stream
->SetDelegate(&delegate
);
685 scoped_ptr
<SpdyHeaderBlock
> headers(
686 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
687 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
688 EXPECT_TRUE(spdy_stream
->HasUrlFromHeaders());
692 EXPECT_EQ(1u, spdy_stream
->stream_id());
694 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
696 // Read and process the GOAWAY frame.
699 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
700 EXPECT_TRUE(session
->IsStreamActive(1));
702 // Read and process the SYN_STREAM frame, the subsequent RST_STREAM,
706 EXPECT_TRUE(session
== NULL
);
709 // A session observing a network change with active streams should close
710 // when the last active stream is closed.
711 TEST_P(SpdySessionTest
, NetworkChangeWithActiveStreams
) {
712 session_deps_
.host_resolver
->set_synchronous_mode(true);
714 MockConnect
connect_data(SYNCHRONOUS
, OK
);
716 MockRead(ASYNC
, 0, 1) // EOF
718 scoped_ptr
<SpdyFrame
> req1(
719 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
720 MockWrite writes
[] = {
721 CreateMockWrite(*req1
, 0),
723 DeterministicSocketData
data(reads
, arraysize(reads
),
724 writes
, arraysize(writes
));
725 data
.set_connect_data(connect_data
);
726 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
728 CreateDeterministicNetworkSession();
730 base::WeakPtr
<SpdySession
> session
=
731 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
733 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
735 base::WeakPtr
<SpdyStream
> spdy_stream
=
736 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
, session
,
737 GURL(kDefaultURL
), MEDIUM
, BoundNetLog());
738 test::StreamDelegateDoNothing
delegate(spdy_stream
);
739 spdy_stream
->SetDelegate(&delegate
);
741 scoped_ptr
<SpdyHeaderBlock
> headers(
742 spdy_util_
.ConstructGetHeaderBlock(kDefaultURL
));
744 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
745 EXPECT_TRUE(spdy_stream
->HasUrlFromHeaders());
749 EXPECT_EQ(1u, spdy_stream
->stream_id());
751 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
753 spdy_session_pool_
->OnIPAddressChanged();
755 // The SpdySessionPool behavior differs based on how the OSs reacts to
756 // network changes; see comment in SpdySessionPool::OnIPAddressChanged().
757 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
758 // For OSs where the TCP connections will close upon relevant network
759 // changes, SpdySessionPool doesn't need to force them to close, so in these
760 // cases verify the session has become unavailable but remains open and the
761 // pre-existing stream is still active.
762 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
764 EXPECT_FALSE(session
->IsClosed());
766 EXPECT_TRUE(session
->IsStreamActive(1));
768 // Should close the session.
769 spdy_stream
->Close();
771 EXPECT_EQ(NULL
, spdy_stream
.get());
773 EXPECT_TRUE(session
== NULL
);
776 TEST_P(SpdySessionTest
, ClientPing
) {
777 session_deps_
.enable_ping
= true;
778 session_deps_
.host_resolver
->set_synchronous_mode(true);
780 MockConnect
connect_data(SYNCHRONOUS
, OK
);
781 scoped_ptr
<SpdyFrame
> read_ping(spdy_util_
.ConstructSpdyPing(1, true));
783 CreateMockRead(*read_ping
, 1),
784 MockRead(ASYNC
, 0, 0, 2) // EOF
786 scoped_ptr
<SpdyFrame
> write_ping(spdy_util_
.ConstructSpdyPing(1, false));
787 MockWrite writes
[] = {
788 CreateMockWrite(*write_ping
, 0),
790 DeterministicSocketData
data(
791 reads
, arraysize(reads
), writes
, arraysize(writes
));
792 data
.set_connect_data(connect_data
);
793 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
795 CreateDeterministicNetworkSession();
797 base::WeakPtr
<SpdySession
> session
=
798 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
800 base::WeakPtr
<SpdyStream
> spdy_stream1
=
801 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
802 session
, test_url_
, MEDIUM
, BoundNetLog());
803 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
804 test::StreamDelegateSendImmediate
delegate(spdy_stream1
, NULL
);
805 spdy_stream1
->SetDelegate(&delegate
);
807 base::TimeTicks before_ping_time
= base::TimeTicks::Now();
809 session
->set_connection_at_risk_of_loss_time(
810 base::TimeDelta::FromSeconds(-1));
811 session
->set_hung_interval(base::TimeDelta::FromMilliseconds(50));
813 session
->SendPrefacePingIfNoneInFlight();
817 session
->CheckPingStatus(before_ping_time
);
819 EXPECT_EQ(0, session
->pings_in_flight());
820 EXPECT_GE(session
->next_ping_id(), static_cast<uint32
>(1));
821 EXPECT_FALSE(session
->check_ping_status_pending());
822 EXPECT_GE(session
->last_activity_time(), before_ping_time
);
826 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
828 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
829 EXPECT_TRUE(session
== NULL
);
832 TEST_P(SpdySessionTest
, ServerPing
) {
833 session_deps_
.host_resolver
->set_synchronous_mode(true);
835 MockConnect
connect_data(SYNCHRONOUS
, OK
);
836 scoped_ptr
<SpdyFrame
> read_ping(spdy_util_
.ConstructSpdyPing(2, false));
838 CreateMockRead(*read_ping
),
839 MockRead(SYNCHRONOUS
, 0, 0) // EOF
841 scoped_ptr
<SpdyFrame
> write_ping(spdy_util_
.ConstructSpdyPing(2, true));
842 MockWrite writes
[] = {
843 CreateMockWrite(*write_ping
),
845 StaticSocketDataProvider
data(
846 reads
, arraysize(reads
), writes
, arraysize(writes
));
847 data
.set_connect_data(connect_data
);
848 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
850 CreateNetworkSession();
852 base::WeakPtr
<SpdySession
> session
=
853 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
855 base::WeakPtr
<SpdyStream
> spdy_stream1
=
856 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
857 session
, test_url_
, MEDIUM
, BoundNetLog());
858 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
859 test::StreamDelegateSendImmediate
delegate(spdy_stream1
, NULL
);
860 spdy_stream1
->SetDelegate(&delegate
);
862 // Flush the read completion task.
863 base::MessageLoop::current()->RunUntilIdle();
865 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
867 EXPECT_TRUE(session
== NULL
);
868 EXPECT_EQ(NULL
, spdy_stream1
.get());
871 // Cause a ping to be sent out while producing a write. The write loop
872 // should handle this properly, i.e. another DoWriteLoop task should
873 // not be posted. This is a regression test for
874 // http://crbug.com/261043 .
875 TEST_P(SpdySessionTest
, PingAndWriteLoop
) {
876 session_deps_
.enable_ping
= true;
877 session_deps_
.time_func
= TheNearFuture
;
879 MockConnect
connect_data(SYNCHRONOUS
, OK
);
880 scoped_ptr
<SpdyFrame
> write_ping(spdy_util_
.ConstructSpdyPing(1, false));
881 scoped_ptr
<SpdyFrame
> req(
882 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
883 MockWrite writes
[] = {
884 CreateMockWrite(*req
, 0),
885 CreateMockWrite(*write_ping
, 1),
889 MockRead(ASYNC
, 0, 2) // EOF
892 session_deps_
.host_resolver
->set_synchronous_mode(true);
894 DeterministicSocketData
data(reads
, arraysize(reads
),
895 writes
, arraysize(writes
));
896 data
.set_connect_data(connect_data
);
897 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
899 CreateDeterministicNetworkSession();
901 base::WeakPtr
<SpdySession
> session
=
902 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
904 GURL
url(kDefaultURL
);
905 base::WeakPtr
<SpdyStream
> spdy_stream
=
906 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
907 session
, url
, LOWEST
, BoundNetLog());
908 test::StreamDelegateDoNothing
delegate(spdy_stream
);
909 spdy_stream
->SetDelegate(&delegate
);
911 scoped_ptr
<SpdyHeaderBlock
> headers(
912 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
913 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
915 // Shift time so that a ping will be sent out.
916 g_time_delta
= base::TimeDelta::FromSeconds(11);
920 session
->CloseSessionOnError(ERR_ABORTED
, "Aborting");
923 TEST_P(SpdySessionTest
, StreamIdSpaceExhausted
) {
924 const SpdyStreamId kLastStreamId
= 0x7fffffff;
925 session_deps_
.host_resolver
->set_synchronous_mode(true);
927 // Test setup: |stream_hi_water_mark_| and |max_concurrent_streams_| are
928 // fixed to allow for two stream ID assignments, and three concurrent
929 // streams. Four streams are started, and two are activated. Verify the
930 // session goes away, and that the created (but not activated) and
931 // stalled streams are aborted. Also verify the activated streams complete,
932 // at which point the session closes.
934 scoped_ptr
<SpdyFrame
> req1(spdy_util_
.ConstructSpdyGet(
935 NULL
, 0, false, kLastStreamId
- 2, MEDIUM
, true));
936 scoped_ptr
<SpdyFrame
> req2(
937 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, kLastStreamId
, MEDIUM
, true));
939 MockWrite writes
[] = {
940 CreateMockWrite(*req1
, 0), CreateMockWrite(*req2
, 1),
943 scoped_ptr
<SpdyFrame
> resp1(
944 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, kLastStreamId
- 2));
945 scoped_ptr
<SpdyFrame
> resp2(
946 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, kLastStreamId
));
948 scoped_ptr
<SpdyFrame
> body1(
949 spdy_util_
.ConstructSpdyBodyFrame(kLastStreamId
- 2, true));
950 scoped_ptr
<SpdyFrame
> body2(
951 spdy_util_
.ConstructSpdyBodyFrame(kLastStreamId
, true));
954 CreateMockRead(*resp1
, 2), CreateMockRead(*resp2
, 3),
955 CreateMockRead(*body1
, 4), CreateMockRead(*body2
, 5),
956 MockRead(ASYNC
, 0, 6) // EOF
959 DeterministicSocketData
data(
960 reads
, arraysize(reads
), writes
, arraysize(writes
));
962 MockConnect
connect_data(SYNCHRONOUS
, OK
);
963 data
.set_connect_data(connect_data
);
964 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
966 CreateDeterministicNetworkSession();
967 base::WeakPtr
<SpdySession
> session
=
968 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
970 // Fix stream_hi_water_mark_ to allow for two stream activations.
971 session
->stream_hi_water_mark_
= kLastStreamId
- 2;
972 // Fix max_concurrent_streams to allow for three stream creations.
973 session
->max_concurrent_streams_
= 3;
975 // Create three streams synchronously, and begin a fourth (which is stalled).
976 GURL
url(kDefaultURL
);
977 base::WeakPtr
<SpdyStream
> stream1
= CreateStreamSynchronously(
978 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
979 test::StreamDelegateDoNothing
delegate1(stream1
);
980 stream1
->SetDelegate(&delegate1
);
982 base::WeakPtr
<SpdyStream
> stream2
= CreateStreamSynchronously(
983 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
984 test::StreamDelegateDoNothing
delegate2(stream2
);
985 stream2
->SetDelegate(&delegate2
);
987 base::WeakPtr
<SpdyStream
> stream3
= CreateStreamSynchronously(
988 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
989 test::StreamDelegateDoNothing
delegate3(stream3
);
990 stream3
->SetDelegate(&delegate3
);
992 SpdyStreamRequest request4
;
993 TestCompletionCallback callback4
;
994 EXPECT_EQ(ERR_IO_PENDING
,
995 request4
.StartRequest(SPDY_REQUEST_RESPONSE_STREAM
,
1000 callback4
.callback()));
1002 // Streams 1-3 were created. 4th is stalled. No streams are active yet.
1003 EXPECT_EQ(0u, session
->num_active_streams());
1004 EXPECT_EQ(3u, session
->num_created_streams());
1005 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(MEDIUM
));
1007 // Activate stream 1. One ID remains available.
1008 stream1
->SendRequestHeaders(
1009 scoped_ptr
<SpdyHeaderBlock
>(
1010 spdy_util_
.ConstructGetHeaderBlock(url
.spec())),
1011 NO_MORE_DATA_TO_SEND
);
1014 EXPECT_EQ(kLastStreamId
- 2u, stream1
->stream_id());
1015 EXPECT_EQ(1u, session
->num_active_streams());
1016 EXPECT_EQ(2u, session
->num_created_streams());
1017 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(MEDIUM
));
1019 // Activate stream 2. ID space is exhausted.
1020 stream2
->SendRequestHeaders(
1021 scoped_ptr
<SpdyHeaderBlock
>(
1022 spdy_util_
.ConstructGetHeaderBlock(url
.spec())),
1023 NO_MORE_DATA_TO_SEND
);
1026 // Active streams remain active.
1027 EXPECT_EQ(kLastStreamId
, stream2
->stream_id());
1028 EXPECT_EQ(2u, session
->num_active_streams());
1030 // Session is going away. Created and stalled streams were aborted.
1031 EXPECT_EQ(SpdySession::STATE_GOING_AWAY
, session
->availability_state_
);
1032 EXPECT_EQ(ERR_ABORTED
, delegate3
.WaitForClose());
1033 EXPECT_EQ(ERR_ABORTED
, callback4
.WaitForResult());
1034 EXPECT_EQ(0u, session
->num_created_streams());
1035 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(MEDIUM
));
1037 // Read responses on remaining active streams.
1039 EXPECT_EQ(OK
, delegate1
.WaitForClose());
1040 EXPECT_EQ(kUploadData
, delegate1
.TakeReceivedData());
1041 EXPECT_EQ(OK
, delegate2
.WaitForClose());
1042 EXPECT_EQ(kUploadData
, delegate2
.TakeReceivedData());
1044 // Session was destroyed.
1045 EXPECT_FALSE(session
.get());
1048 // Verifies that an unstalled pending stream creation racing with a new stream
1049 // creation doesn't violate the maximum stream concurrency. Regression test for
1050 // crbug.com/373858.
1051 TEST_P(SpdySessionTest
, UnstallRacesWithStreamCreation
) {
1052 session_deps_
.host_resolver
->set_synchronous_mode(true);
1054 MockRead reads
[] = {
1055 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
1058 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
1060 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1061 data
.set_connect_data(connect_data
);
1062 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
1064 CreateNetworkSession();
1065 base::WeakPtr
<SpdySession
> session
=
1066 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1068 // Fix max_concurrent_streams to allow for one open stream.
1069 session
->max_concurrent_streams_
= 1;
1071 // Create two streams: one synchronously, and one which stalls.
1072 GURL
url(kDefaultURL
);
1073 base::WeakPtr
<SpdyStream
> stream1
= CreateStreamSynchronously(
1074 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
1076 SpdyStreamRequest request2
;
1077 TestCompletionCallback callback2
;
1078 EXPECT_EQ(ERR_IO_PENDING
,
1079 request2
.StartRequest(SPDY_REQUEST_RESPONSE_STREAM
,
1084 callback2
.callback()));
1086 EXPECT_EQ(1u, session
->num_created_streams());
1087 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(MEDIUM
));
1089 // Cancel the first stream. A callback to unstall the second stream was
1090 // posted. Don't run it yet.
1093 EXPECT_EQ(0u, session
->num_created_streams());
1094 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(MEDIUM
));
1096 // Create a third stream prior to the second stream's callback.
1097 base::WeakPtr
<SpdyStream
> stream3
= CreateStreamSynchronously(
1098 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
1100 EXPECT_EQ(1u, session
->num_created_streams());
1101 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(MEDIUM
));
1103 // NOW run the message loop. The unstalled stream will re-stall itself.
1104 base::MessageLoop::current()->RunUntilIdle();
1105 EXPECT_EQ(1u, session
->num_created_streams());
1106 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(MEDIUM
));
1108 // Cancel the third stream and run the message loop. Verify that the second
1109 // stream creation now completes.
1111 base::MessageLoop::current()->RunUntilIdle();
1113 EXPECT_EQ(1u, session
->num_created_streams());
1114 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(MEDIUM
));
1115 EXPECT_EQ(OK
, callback2
.WaitForResult());
1118 TEST_P(SpdySessionTest
, DeleteExpiredPushStreams
) {
1119 session_deps_
.host_resolver
->set_synchronous_mode(true);
1120 session_deps_
.time_func
= TheNearFuture
;
1122 scoped_ptr
<SpdyFrame
> req(
1123 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
1124 scoped_ptr
<SpdyFrame
> rst(
1125 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
1127 scoped_ptr
<SpdyFrame
> push_a(spdy_util_
.ConstructSpdyPush(
1128 NULL
, 0, 2, 1, "http://www.google.com/a.dat"));
1129 scoped_ptr
<SpdyFrame
> push_a_body(
1130 spdy_util_
.ConstructSpdyBodyFrame(2, false));
1131 scoped_ptr
<SpdyFrame
> push_b(spdy_util_
.ConstructSpdyPush(
1132 NULL
, 0, 4, 1, "http://www.google.com/b.dat"));
1133 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4)};
1134 MockRead reads
[] = {
1135 CreateMockRead(*push_a
, 1), CreateMockRead(*push_a_body
, 2),
1136 CreateMockRead(*push_b
, 3), MockRead(ASYNC
, 0, 5), // EOF
1138 DeterministicSocketData
data(
1139 reads
, arraysize(reads
), writes
, arraysize(writes
));
1141 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1142 data
.set_connect_data(connect_data
);
1143 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1145 CreateDeterministicNetworkSession();
1146 base::WeakPtr
<SpdySession
> session
=
1147 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1149 // Process the principal request, and the first push stream request & body.
1150 GURL
url(kDefaultURL
);
1151 base::WeakPtr
<SpdyStream
> spdy_stream
= CreateStreamSynchronously(
1152 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
1153 test::StreamDelegateDoNothing
delegate(spdy_stream
);
1154 spdy_stream
->SetDelegate(&delegate
);
1156 scoped_ptr
<SpdyHeaderBlock
> headers(
1157 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
1158 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
1162 // Verify that there is one unclaimed push stream.
1163 EXPECT_EQ(1u, session
->num_unclaimed_pushed_streams());
1164 SpdySession::PushedStreamMap::iterator iter
=
1165 session
->unclaimed_pushed_streams_
.find(
1166 GURL("http://www.google.com/a.dat"));
1167 EXPECT_TRUE(session
->unclaimed_pushed_streams_
.end() != iter
);
1169 if (session
->flow_control_state_
==
1170 SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
) {
1171 // Unclaimed push body consumed bytes from the session window.
1172 EXPECT_EQ(kSpdySessionInitialWindowSize
- kUploadDataSize
,
1173 session
->session_recv_window_size_
);
1174 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
1177 // Shift time to expire the push stream. Read the second SYN_STREAM,
1178 // and verify a RST_STREAM was written.
1179 g_time_delta
= base::TimeDelta::FromSeconds(301);
1182 // Verify that the second pushed stream evicted the first pushed stream.
1183 EXPECT_EQ(1u, session
->num_unclaimed_pushed_streams());
1184 iter
= session
->unclaimed_pushed_streams_
.find(
1185 GURL("http://www.google.com/b.dat"));
1186 EXPECT_TRUE(session
->unclaimed_pushed_streams_
.end() != iter
);
1188 if (session
->flow_control_state_
==
1189 SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
) {
1190 // Verify that the session window reclaimed the evicted stream body.
1191 EXPECT_EQ(kSpdySessionInitialWindowSize
,
1192 session
->session_recv_window_size_
);
1193 EXPECT_EQ(kUploadDataSize
, session
->session_unacked_recv_window_bytes_
);
1196 // Read and process EOF.
1198 EXPECT_TRUE(session
== NULL
);
1201 TEST_P(SpdySessionTest
, FailedPing
) {
1202 session_deps_
.host_resolver
->set_synchronous_mode(true);
1204 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1205 MockRead reads
[] = {
1206 MockRead(ASYNC
, 0, 0, 0) // EOF
1208 scoped_ptr
<SpdyFrame
> write_ping(spdy_util_
.ConstructSpdyPing(1, false));
1209 DeterministicSocketData
data(reads
, arraysize(reads
), NULL
, 0);
1210 data
.set_connect_data(connect_data
);
1211 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1213 CreateDeterministicNetworkSession();
1215 base::WeakPtr
<SpdySession
> session
=
1216 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1218 base::WeakPtr
<SpdyStream
> spdy_stream1
=
1219 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1220 session
, test_url_
, MEDIUM
, BoundNetLog());
1221 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
1222 test::StreamDelegateSendImmediate
delegate(spdy_stream1
, NULL
);
1223 spdy_stream1
->SetDelegate(&delegate
);
1225 session
->set_connection_at_risk_of_loss_time(base::TimeDelta::FromSeconds(0));
1226 session
->set_hung_interval(base::TimeDelta::FromSeconds(0));
1228 // Send a PING frame.
1229 session
->WritePingFrame(1, false);
1230 EXPECT_LT(0, session
->pings_in_flight());
1231 EXPECT_GE(session
->next_ping_id(), static_cast<uint32
>(1));
1232 EXPECT_TRUE(session
->check_ping_status_pending());
1234 // Assert session is not closed.
1235 EXPECT_FALSE(session
->IsClosed());
1236 EXPECT_LT(0u, session
->num_active_streams() + session
->num_created_streams());
1237 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
1239 // We set last time we have received any data in 1 sec less than now.
1240 // CheckPingStatus will trigger timeout because hung interval is zero.
1241 base::TimeTicks now
= base::TimeTicks::Now();
1242 session
->last_activity_time_
= now
- base::TimeDelta::FromSeconds(1);
1243 session
->CheckPingStatus(now
);
1245 EXPECT_TRUE(session
== NULL
);
1246 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
1247 EXPECT_EQ(NULL
, spdy_stream1
.get());
1250 // Request kInitialMaxConcurrentStreams + 1 streams. Receive a
1251 // settings frame increasing the max concurrent streams by 1. Make
1252 // sure nothing blows up. This is a regression test for
1253 // http://crbug.com/57331 .
1254 TEST_P(SpdySessionTest
, OnSettings
) {
1255 session_deps_
.host_resolver
->set_synchronous_mode(true);
1257 const SpdySettingsIds kSpdySettingsIds
= SETTINGS_MAX_CONCURRENT_STREAMS
;
1259 SettingsMap new_settings
;
1260 const uint32 max_concurrent_streams
= kInitialMaxConcurrentStreams
+ 1;
1261 new_settings
[kSpdySettingsIds
] =
1262 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1263 scoped_ptr
<SpdyFrame
> settings_frame(
1264 spdy_util_
.ConstructSpdySettings(new_settings
));
1265 MockRead reads
[] = {
1266 CreateMockRead(*settings_frame
, 0),
1267 MockRead(ASYNC
, 0, 1),
1270 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1271 MockWrite writes
[] = {
1272 CreateMockWrite(*settings_ack
, 2),
1275 DeterministicSocketData
data(reads
, arraysize(reads
),
1276 writes
, arraysize(writes
));
1277 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1278 data
.set_connect_data(connect_data
);
1279 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1281 CreateDeterministicNetworkSession();
1283 base::WeakPtr
<SpdySession
> session
=
1284 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1286 // Create the maximum number of concurrent streams.
1287 for (size_t i
= 0; i
< kInitialMaxConcurrentStreams
; ++i
) {
1288 base::WeakPtr
<SpdyStream
> spdy_stream
=
1289 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1290 session
, test_url_
, MEDIUM
, BoundNetLog());
1291 ASSERT_TRUE(spdy_stream
!= NULL
);
1294 StreamReleaserCallback stream_releaser
;
1295 SpdyStreamRequest request
;
1296 ASSERT_EQ(ERR_IO_PENDING
,
1297 request
.StartRequest(
1298 SPDY_BIDIRECTIONAL_STREAM
, session
, test_url_
, MEDIUM
,
1300 stream_releaser
.MakeCallback(&request
)));
1304 EXPECT_EQ(OK
, stream_releaser
.WaitForResult());
1307 EXPECT_TRUE(session
== NULL
);
1310 // Start with a persisted value for max concurrent streams. Receive a
1311 // settings frame increasing the max concurrent streams by 1 and which
1312 // also clears the persisted data. Verify that persisted data is
1314 TEST_P(SpdySessionTest
, ClearSettings
) {
1315 if (spdy_util_
.spdy_version() >= SPDY4
) {
1316 // SPDY4 doesn't include settings persistence, or a CLEAR_SETTINGS flag.
1317 // Flag 0x1, CLEAR_SETTINGS in SPDY3, is instead settings ACK in SPDY4.
1320 session_deps_
.host_resolver
->set_synchronous_mode(true);
1322 SettingsMap new_settings
;
1323 const uint32 max_concurrent_streams
= kInitialMaxConcurrentStreams
+ 1;
1324 new_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1325 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1326 scoped_ptr
<SpdyFrame
> settings_frame(
1327 spdy_util_
.ConstructSpdySettings(new_settings
));
1328 uint8 flags
= SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS
;
1329 test::SetFrameFlags(settings_frame
.get(), flags
, spdy_util_
.spdy_version());
1330 MockRead reads
[] = {
1331 CreateMockRead(*settings_frame
, 0),
1332 MockRead(ASYNC
, 0, 1),
1335 DeterministicSocketData
data(reads
, arraysize(reads
), NULL
, 0);
1336 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1337 data
.set_connect_data(connect_data
);
1338 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1340 CreateDeterministicNetworkSession();
1342 // Initialize the SpdySetting with the default.
1343 spdy_session_pool_
->http_server_properties()->SetSpdySetting(
1344 test_host_port_pair_
,
1345 SETTINGS_MAX_CONCURRENT_STREAMS
,
1346 SETTINGS_FLAG_PLEASE_PERSIST
,
1347 kInitialMaxConcurrentStreams
);
1350 spdy_session_pool_
->http_server_properties()->GetSpdySettings(
1351 test_host_port_pair_
).empty());
1353 base::WeakPtr
<SpdySession
> session
=
1354 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1356 // Create the maximum number of concurrent streams.
1357 for (size_t i
= 0; i
< kInitialMaxConcurrentStreams
; ++i
) {
1358 base::WeakPtr
<SpdyStream
> spdy_stream
=
1359 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1360 session
, test_url_
, MEDIUM
, BoundNetLog());
1361 ASSERT_TRUE(spdy_stream
!= NULL
);
1364 StreamReleaserCallback stream_releaser
;
1366 SpdyStreamRequest request
;
1367 ASSERT_EQ(ERR_IO_PENDING
,
1368 request
.StartRequest(
1369 SPDY_BIDIRECTIONAL_STREAM
, session
, test_url_
, MEDIUM
,
1371 stream_releaser
.MakeCallback(&request
)));
1375 EXPECT_EQ(OK
, stream_releaser
.WaitForResult());
1377 // Make sure that persisted data is cleared.
1379 spdy_session_pool_
->http_server_properties()->GetSpdySettings(
1380 test_host_port_pair_
).empty());
1382 // Make sure session's max_concurrent_streams is correct.
1383 EXPECT_EQ(kInitialMaxConcurrentStreams
+ 1,
1384 session
->max_concurrent_streams());
1387 EXPECT_TRUE(session
== NULL
);
1390 // Start with max concurrent streams set to 1. Request two streams.
1391 // When the first completes, have the callback close its stream, which
1392 // should trigger the second stream creation. Then cancel that one
1393 // immediately. Don't crash. This is a regression test for
1394 // http://crbug.com/63532 .
1395 TEST_P(SpdySessionTest
, CancelPendingCreateStream
) {
1396 session_deps_
.host_resolver
->set_synchronous_mode(true);
1398 MockRead reads
[] = {
1399 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
1402 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
1403 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1405 data
.set_connect_data(connect_data
);
1406 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
1408 CreateNetworkSession();
1410 // Initialize the SpdySetting with 1 max concurrent streams.
1411 spdy_session_pool_
->http_server_properties()->SetSpdySetting(
1412 test_host_port_pair_
,
1413 SETTINGS_MAX_CONCURRENT_STREAMS
,
1414 SETTINGS_FLAG_PLEASE_PERSIST
,
1417 base::WeakPtr
<SpdySession
> session
=
1418 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1420 // Leave room for only one more stream to be created.
1421 for (size_t i
= 0; i
< kInitialMaxConcurrentStreams
- 1; ++i
) {
1422 base::WeakPtr
<SpdyStream
> spdy_stream
=
1423 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1424 session
, test_url_
, MEDIUM
, BoundNetLog());
1425 ASSERT_TRUE(spdy_stream
!= NULL
);
1428 // Create 2 more streams. First will succeed. Second will be pending.
1429 base::WeakPtr
<SpdyStream
> spdy_stream1
=
1430 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1431 session
, test_url_
, MEDIUM
, BoundNetLog());
1432 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
1434 // Use scoped_ptr to let us invalidate the memory when we want to, to trigger
1435 // a valgrind error if the callback is invoked when it's not supposed to be.
1436 scoped_ptr
<TestCompletionCallback
> callback(new TestCompletionCallback
);
1438 SpdyStreamRequest request
;
1439 ASSERT_EQ(ERR_IO_PENDING
,
1440 request
.StartRequest(
1441 SPDY_BIDIRECTIONAL_STREAM
, session
, test_url_
, MEDIUM
,
1443 callback
->callback()));
1445 // Release the first one, this will allow the second to be created.
1446 spdy_stream1
->Cancel();
1447 EXPECT_EQ(NULL
, spdy_stream1
.get());
1449 request
.CancelRequest();
1452 // Should not crash when running the pending callback.
1453 base::MessageLoop::current()->RunUntilIdle();
1456 TEST_P(SpdySessionTest
, SendInitialDataOnNewSession
) {
1457 session_deps_
.host_resolver
->set_synchronous_mode(true);
1459 MockRead reads
[] = {
1460 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
1463 SettingsMap settings
;
1464 const SpdySettingsIds kSpdySettingsIds1
= SETTINGS_MAX_CONCURRENT_STREAMS
;
1465 const SpdySettingsIds kSpdySettingsIds2
= SETTINGS_INITIAL_WINDOW_SIZE
;
1466 const uint32 kInitialRecvWindowSize
= 10 * 1024 * 1024;
1467 settings
[kSpdySettingsIds1
] =
1468 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
1469 if (spdy_util_
.spdy_version() >= SPDY3
) {
1470 settings
[kSpdySettingsIds2
] =
1471 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kInitialRecvWindowSize
);
1473 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1474 scoped_ptr
<SpdyFrame
> settings_frame(
1475 spdy_util_
.ConstructSpdySettings(settings
));
1476 scoped_ptr
<SpdyFrame
> initial_window_update(
1477 spdy_util_
.ConstructSpdyWindowUpdate(
1478 kSessionFlowControlStreamId
,
1479 kDefaultInitialRecvWindowSize
- kSpdySessionInitialWindowSize
));
1480 std::vector
<MockWrite
> writes
;
1481 if (GetParam() == kProtoSPDY4
) {
1484 kHttp2ConnectionHeaderPrefix
,
1485 kHttp2ConnectionHeaderPrefixSize
));
1487 writes
.push_back(CreateMockWrite(*settings_frame
));
1488 if (GetParam() >= kProtoSPDY31
) {
1489 writes
.push_back(CreateMockWrite(*initial_window_update
));
1492 SettingsMap server_settings
;
1493 const uint32 initial_max_concurrent_streams
= 1;
1494 server_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1495 SettingsFlagsAndValue(SETTINGS_FLAG_PERSISTED
,
1496 initial_max_concurrent_streams
);
1497 scoped_ptr
<SpdyFrame
> server_settings_frame(
1498 spdy_util_
.ConstructSpdySettings(server_settings
));
1499 writes
.push_back(CreateMockWrite(*server_settings_frame
));
1501 session_deps_
.stream_initial_recv_window_size
= kInitialRecvWindowSize
;
1503 StaticSocketDataProvider
data(reads
, arraysize(reads
),
1504 vector_as_array(&writes
), writes
.size());
1505 data
.set_connect_data(connect_data
);
1506 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
1508 CreateNetworkSession();
1510 spdy_session_pool_
->http_server_properties()->SetSpdySetting(
1511 test_host_port_pair_
,
1512 SETTINGS_MAX_CONCURRENT_STREAMS
,
1513 SETTINGS_FLAG_PLEASE_PERSIST
,
1514 initial_max_concurrent_streams
);
1516 SpdySessionPoolPeer
pool_peer(spdy_session_pool_
);
1517 pool_peer
.SetEnableSendingInitialData(true);
1519 base::WeakPtr
<SpdySession
> session
=
1520 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1522 base::MessageLoop::current()->RunUntilIdle();
1523 EXPECT_TRUE(data
.at_write_eof());
1526 TEST_P(SpdySessionTest
, ClearSettingsStorageOnIPAddressChanged
) {
1527 CreateNetworkSession();
1529 base::WeakPtr
<HttpServerProperties
> test_http_server_properties
=
1530 spdy_session_pool_
->http_server_properties();
1531 SettingsFlagsAndValue
flags_and_value1(SETTINGS_FLAG_PLEASE_PERSIST
, 2);
1532 test_http_server_properties
->SetSpdySetting(
1533 test_host_port_pair_
,
1534 SETTINGS_MAX_CONCURRENT_STREAMS
,
1535 SETTINGS_FLAG_PLEASE_PERSIST
,
1537 EXPECT_NE(0u, test_http_server_properties
->GetSpdySettings(
1538 test_host_port_pair_
).size());
1539 spdy_session_pool_
->OnIPAddressChanged();
1540 EXPECT_EQ(0u, test_http_server_properties
->GetSpdySettings(
1541 test_host_port_pair_
).size());
1544 TEST_P(SpdySessionTest
, Initialize
) {
1545 CapturingBoundNetLog log
;
1546 session_deps_
.net_log
= log
.bound().net_log();
1547 session_deps_
.host_resolver
->set_synchronous_mode(true);
1549 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1550 MockRead reads
[] = {
1551 MockRead(ASYNC
, 0, 0) // EOF
1554 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
1555 data
.set_connect_data(connect_data
);
1556 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
1558 CreateNetworkSession();
1560 base::WeakPtr
<SpdySession
> session
=
1561 CreateInsecureSpdySession(http_session_
, key_
, log
.bound());
1562 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
1564 // Flush the read completion task.
1565 base::MessageLoop::current()->RunUntilIdle();
1567 net::CapturingNetLog::CapturedEntryList entries
;
1568 log
.GetEntries(&entries
);
1569 EXPECT_LT(0u, entries
.size());
1571 // Check that we logged TYPE_SPDY_SESSION_INITIALIZED correctly.
1572 int pos
= net::ExpectLogContainsSomewhere(
1574 net::NetLog::TYPE_SPDY_SESSION_INITIALIZED
,
1575 net::NetLog::PHASE_NONE
);
1578 CapturingNetLog::CapturedEntry entry
= entries
[pos
];
1579 NetLog::Source socket_source
;
1580 EXPECT_TRUE(NetLog::Source::FromEventParameters(entry
.params
.get(),
1582 EXPECT_TRUE(socket_source
.IsValid());
1583 EXPECT_NE(log
.bound().source().id
, socket_source
.id
);
1586 TEST_P(SpdySessionTest
, CloseSessionOnError
) {
1587 session_deps_
.host_resolver
->set_synchronous_mode(true);
1589 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1590 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway());
1591 MockRead reads
[] = {
1592 CreateMockRead(*goaway
),
1593 MockRead(SYNCHRONOUS
, 0, 0) // EOF
1596 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
1597 data
.set_connect_data(connect_data
);
1598 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
1600 CreateNetworkSession();
1602 CapturingBoundNetLog log
;
1603 base::WeakPtr
<SpdySession
> session
=
1604 CreateInsecureSpdySession(http_session_
, key_
, log
.bound());
1605 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
1607 // Flush the read completion task.
1608 base::MessageLoop::current()->RunUntilIdle();
1610 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
1611 EXPECT_TRUE(session
== NULL
);
1613 // Check that the NetLog was filled reasonably.
1614 net::CapturingNetLog::CapturedEntryList entries
;
1615 log
.GetEntries(&entries
);
1616 EXPECT_LT(0u, entries
.size());
1618 // Check that we logged SPDY_SESSION_CLOSE correctly.
1619 int pos
= net::ExpectLogContainsSomewhere(
1621 net::NetLog::TYPE_SPDY_SESSION_CLOSE
,
1622 net::NetLog::PHASE_NONE
);
1624 if (pos
< static_cast<int>(entries
.size())) {
1625 CapturingNetLog::CapturedEntry entry
= entries
[pos
];
1627 ASSERT_TRUE(entry
.GetNetErrorCode(&error_code
));
1628 EXPECT_EQ(ERR_CONNECTION_CLOSED
, error_code
);
1634 // Queue up a low-priority SYN_STREAM followed by a high-priority
1635 // one. The high priority one should still send first and receive
1637 TEST_P(SpdySessionTest
, OutOfOrderSynStreams
) {
1638 // Construct the request.
1639 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1640 scoped_ptr
<SpdyFrame
> req_highest(
1641 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, HIGHEST
, true));
1642 scoped_ptr
<SpdyFrame
> req_lowest(
1643 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1644 MockWrite writes
[] = {
1645 CreateMockWrite(*req_highest
, 0),
1646 CreateMockWrite(*req_lowest
, 1),
1649 scoped_ptr
<SpdyFrame
> resp_highest(
1650 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1651 scoped_ptr
<SpdyFrame
> body_highest(
1652 spdy_util_
.ConstructSpdyBodyFrame(1, true));
1653 scoped_ptr
<SpdyFrame
> resp_lowest(
1654 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1655 scoped_ptr
<SpdyFrame
> body_lowest(
1656 spdy_util_
.ConstructSpdyBodyFrame(3, true));
1657 MockRead reads
[] = {
1658 CreateMockRead(*resp_highest
, 2),
1659 CreateMockRead(*body_highest
, 3),
1660 CreateMockRead(*resp_lowest
, 4),
1661 CreateMockRead(*body_lowest
, 5),
1662 MockRead(ASYNC
, 0, 6) // EOF
1665 session_deps_
.host_resolver
->set_synchronous_mode(true);
1667 DeterministicSocketData
data(reads
, arraysize(reads
),
1668 writes
, arraysize(writes
));
1669 data
.set_connect_data(connect_data
);
1670 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1672 CreateDeterministicNetworkSession();
1674 base::WeakPtr
<SpdySession
> session
=
1675 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1677 GURL
url(kDefaultURL
);
1679 base::WeakPtr
<SpdyStream
> spdy_stream_lowest
=
1680 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
1681 session
, url
, LOWEST
, BoundNetLog());
1682 ASSERT_TRUE(spdy_stream_lowest
);
1683 EXPECT_EQ(0u, spdy_stream_lowest
->stream_id());
1684 test::StreamDelegateDoNothing
delegate_lowest(spdy_stream_lowest
);
1685 spdy_stream_lowest
->SetDelegate(&delegate_lowest
);
1687 base::WeakPtr
<SpdyStream
> spdy_stream_highest
=
1688 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
1689 session
, url
, HIGHEST
, BoundNetLog());
1690 ASSERT_TRUE(spdy_stream_highest
);
1691 EXPECT_EQ(0u, spdy_stream_highest
->stream_id());
1692 test::StreamDelegateDoNothing
delegate_highest(spdy_stream_highest
);
1693 spdy_stream_highest
->SetDelegate(&delegate_highest
);
1695 // Queue the lower priority one first.
1697 scoped_ptr
<SpdyHeaderBlock
> headers_lowest(
1698 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
1699 spdy_stream_lowest
->SendRequestHeaders(
1700 headers_lowest
.Pass(), NO_MORE_DATA_TO_SEND
);
1701 EXPECT_TRUE(spdy_stream_lowest
->HasUrlFromHeaders());
1703 scoped_ptr
<SpdyHeaderBlock
> headers_highest(
1704 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
1705 spdy_stream_highest
->SendRequestHeaders(
1706 headers_highest
.Pass(), NO_MORE_DATA_TO_SEND
);
1707 EXPECT_TRUE(spdy_stream_highest
->HasUrlFromHeaders());
1711 EXPECT_FALSE(spdy_stream_lowest
);
1712 EXPECT_FALSE(spdy_stream_highest
);
1713 EXPECT_EQ(3u, delegate_lowest
.stream_id());
1714 EXPECT_EQ(1u, delegate_highest
.stream_id());
1717 TEST_P(SpdySessionTest
, CancelStream
) {
1718 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1719 // Request 1, at HIGHEST priority, will be cancelled before it writes data.
1720 // Request 2, at LOWEST priority, will be a full request and will be id 1.
1721 scoped_ptr
<SpdyFrame
> req2(
1722 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1723 MockWrite writes
[] = {
1724 CreateMockWrite(*req2
, 0),
1727 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1728 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1729 MockRead reads
[] = {
1730 CreateMockRead(*resp2
, 1),
1731 CreateMockRead(*body2
, 2),
1732 MockRead(ASYNC
, 0, 3) // EOF
1735 session_deps_
.host_resolver
->set_synchronous_mode(true);
1737 DeterministicSocketData
data(reads
, arraysize(reads
),
1738 writes
, arraysize(writes
));
1739 data
.set_connect_data(connect_data
);
1740 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1742 CreateDeterministicNetworkSession();
1744 base::WeakPtr
<SpdySession
> session
=
1745 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1747 GURL
url1(kDefaultURL
);
1748 base::WeakPtr
<SpdyStream
> spdy_stream1
=
1749 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
1750 session
, url1
, HIGHEST
, BoundNetLog());
1751 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
1752 EXPECT_EQ(0u, spdy_stream1
->stream_id());
1753 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
1754 spdy_stream1
->SetDelegate(&delegate1
);
1756 GURL
url2(kDefaultURL
);
1757 base::WeakPtr
<SpdyStream
> spdy_stream2
=
1758 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
1759 session
, url2
, LOWEST
, BoundNetLog());
1760 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
1761 EXPECT_EQ(0u, spdy_stream2
->stream_id());
1762 test::StreamDelegateDoNothing
delegate2(spdy_stream2
);
1763 spdy_stream2
->SetDelegate(&delegate2
);
1765 scoped_ptr
<SpdyHeaderBlock
> headers(
1766 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
1767 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
1768 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
1770 scoped_ptr
<SpdyHeaderBlock
> headers2(
1771 spdy_util_
.ConstructGetHeaderBlock(url2
.spec()));
1772 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
1773 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
1775 EXPECT_EQ(0u, spdy_stream1
->stream_id());
1777 spdy_stream1
->Cancel();
1778 EXPECT_EQ(NULL
, spdy_stream1
.get());
1780 EXPECT_EQ(0u, delegate1
.stream_id());
1784 EXPECT_EQ(0u, delegate1
.stream_id());
1785 EXPECT_EQ(1u, delegate2
.stream_id());
1787 spdy_stream2
->Cancel();
1788 EXPECT_EQ(NULL
, spdy_stream2
.get());
1791 // Create two streams that are set to re-close themselves on close,
1792 // and then close the session. Nothing should blow up. Also a
1793 // regression test for http://crbug.com/139518 .
1794 TEST_P(SpdySessionTest
, CloseSessionWithTwoCreatedSelfClosingStreams
) {
1795 session_deps_
.host_resolver
->set_synchronous_mode(true);
1797 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1799 // No actual data will be sent.
1800 MockWrite writes
[] = {
1801 MockWrite(ASYNC
, 0, 1) // EOF
1804 MockRead reads
[] = {
1805 MockRead(ASYNC
, 0, 0) // EOF
1807 DeterministicSocketData
data(reads
, arraysize(reads
),
1808 writes
, arraysize(writes
));
1809 data
.set_connect_data(connect_data
);
1810 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1812 CreateDeterministicNetworkSession();
1814 base::WeakPtr
<SpdySession
> session
=
1815 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1817 GURL
url1(kDefaultURL
);
1818 base::WeakPtr
<SpdyStream
> spdy_stream1
=
1819 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1820 session
, url1
, HIGHEST
, BoundNetLog());
1821 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
1822 EXPECT_EQ(0u, spdy_stream1
->stream_id());
1824 GURL
url2(kDefaultURL
);
1825 base::WeakPtr
<SpdyStream
> spdy_stream2
=
1826 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1827 session
, url2
, LOWEST
, BoundNetLog());
1828 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
1829 EXPECT_EQ(0u, spdy_stream2
->stream_id());
1831 test::ClosingDelegate
delegate1(spdy_stream1
);
1832 spdy_stream1
->SetDelegate(&delegate1
);
1834 test::ClosingDelegate
delegate2(spdy_stream2
);
1835 spdy_stream2
->SetDelegate(&delegate2
);
1837 scoped_ptr
<SpdyHeaderBlock
> headers(
1838 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
1839 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
1840 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
1842 scoped_ptr
<SpdyHeaderBlock
> headers2(
1843 spdy_util_
.ConstructGetHeaderBlock(url2
.spec()));
1844 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
1845 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
1847 // Ensure that the streams have not yet been activated and assigned an id.
1848 EXPECT_EQ(0u, spdy_stream1
->stream_id());
1849 EXPECT_EQ(0u, spdy_stream2
->stream_id());
1851 // Ensure we don't crash while closing the session.
1852 session
->CloseSessionOnError(ERR_ABORTED
, std::string());
1854 EXPECT_EQ(NULL
, spdy_stream1
.get());
1855 EXPECT_EQ(NULL
, spdy_stream2
.get());
1857 EXPECT_TRUE(delegate1
.StreamIsClosed());
1858 EXPECT_TRUE(delegate2
.StreamIsClosed());
1860 EXPECT_TRUE(session
== NULL
);
1863 // Create two streams that are set to close each other on close, and
1864 // then close the session. Nothing should blow up.
1865 TEST_P(SpdySessionTest
, CloseSessionWithTwoCreatedMutuallyClosingStreams
) {
1866 session_deps_
.host_resolver
->set_synchronous_mode(true);
1868 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1870 // No actual data will be sent.
1871 MockWrite writes
[] = {
1872 MockWrite(ASYNC
, 0, 1) // EOF
1875 MockRead reads
[] = {
1876 MockRead(ASYNC
, 0, 0) // EOF
1878 DeterministicSocketData
data(reads
, arraysize(reads
),
1879 writes
, arraysize(writes
));
1880 data
.set_connect_data(connect_data
);
1881 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1883 CreateDeterministicNetworkSession();
1885 base::WeakPtr
<SpdySession
> session
=
1886 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1888 GURL
url1(kDefaultURL
);
1889 base::WeakPtr
<SpdyStream
> spdy_stream1
=
1890 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1891 session
, url1
, HIGHEST
, BoundNetLog());
1892 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
1893 EXPECT_EQ(0u, spdy_stream1
->stream_id());
1895 GURL
url2(kDefaultURL
);
1896 base::WeakPtr
<SpdyStream
> spdy_stream2
=
1897 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1898 session
, url2
, LOWEST
, BoundNetLog());
1899 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
1900 EXPECT_EQ(0u, spdy_stream2
->stream_id());
1902 // Make |spdy_stream1| close |spdy_stream2|.
1903 test::ClosingDelegate
delegate1(spdy_stream2
);
1904 spdy_stream1
->SetDelegate(&delegate1
);
1906 // Make |spdy_stream2| close |spdy_stream1|.
1907 test::ClosingDelegate
delegate2(spdy_stream1
);
1908 spdy_stream2
->SetDelegate(&delegate2
);
1910 scoped_ptr
<SpdyHeaderBlock
> headers(
1911 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
1912 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
1913 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
1915 scoped_ptr
<SpdyHeaderBlock
> headers2(
1916 spdy_util_
.ConstructGetHeaderBlock(url2
.spec()));
1917 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
1918 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
1920 // Ensure that the streams have not yet been activated and assigned an id.
1921 EXPECT_EQ(0u, spdy_stream1
->stream_id());
1922 EXPECT_EQ(0u, spdy_stream2
->stream_id());
1924 // Ensure we don't crash while closing the session.
1925 session
->CloseSessionOnError(ERR_ABORTED
, std::string());
1927 EXPECT_EQ(NULL
, spdy_stream1
.get());
1928 EXPECT_EQ(NULL
, spdy_stream2
.get());
1930 EXPECT_TRUE(delegate1
.StreamIsClosed());
1931 EXPECT_TRUE(delegate2
.StreamIsClosed());
1933 EXPECT_TRUE(session
== NULL
);
1936 // Create two streams that are set to re-close themselves on close,
1937 // activate them, and then close the session. Nothing should blow up.
1938 TEST_P(SpdySessionTest
, CloseSessionWithTwoActivatedSelfClosingStreams
) {
1939 session_deps_
.host_resolver
->set_synchronous_mode(true);
1941 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1943 scoped_ptr
<SpdyFrame
> req1(
1944 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
1945 scoped_ptr
<SpdyFrame
> req2(
1946 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, MEDIUM
, true));
1947 MockWrite writes
[] = {
1948 CreateMockWrite(*req1
, 0),
1949 CreateMockWrite(*req2
, 1),
1952 MockRead reads
[] = {
1953 MockRead(ASYNC
, 0, 2) // EOF
1956 DeterministicSocketData
data(reads
, arraysize(reads
),
1957 writes
, arraysize(writes
));
1958 data
.set_connect_data(connect_data
);
1959 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1961 CreateDeterministicNetworkSession();
1963 base::WeakPtr
<SpdySession
> session
=
1964 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1966 GURL
url1(kDefaultURL
);
1967 base::WeakPtr
<SpdyStream
> spdy_stream1
=
1968 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
1969 session
, url1
, MEDIUM
, BoundNetLog());
1970 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
1971 EXPECT_EQ(0u, spdy_stream1
->stream_id());
1973 GURL
url2(kDefaultURL
);
1974 base::WeakPtr
<SpdyStream
> spdy_stream2
=
1975 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
1976 session
, url2
, MEDIUM
, BoundNetLog());
1977 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
1978 EXPECT_EQ(0u, spdy_stream2
->stream_id());
1980 test::ClosingDelegate
delegate1(spdy_stream1
);
1981 spdy_stream1
->SetDelegate(&delegate1
);
1983 test::ClosingDelegate
delegate2(spdy_stream2
);
1984 spdy_stream2
->SetDelegate(&delegate2
);
1986 scoped_ptr
<SpdyHeaderBlock
> headers(
1987 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
1988 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
1989 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
1991 scoped_ptr
<SpdyHeaderBlock
> headers2(
1992 spdy_util_
.ConstructGetHeaderBlock(url2
.spec()));
1993 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
1994 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
1996 // Ensure that the streams have not yet been activated and assigned an id.
1997 EXPECT_EQ(0u, spdy_stream1
->stream_id());
1998 EXPECT_EQ(0u, spdy_stream2
->stream_id());
2002 EXPECT_EQ(1u, spdy_stream1
->stream_id());
2003 EXPECT_EQ(3u, spdy_stream2
->stream_id());
2005 // Ensure we don't crash while closing the session.
2006 session
->CloseSessionOnError(ERR_ABORTED
, std::string());
2008 EXPECT_EQ(NULL
, spdy_stream1
.get());
2009 EXPECT_EQ(NULL
, spdy_stream2
.get());
2011 EXPECT_TRUE(delegate1
.StreamIsClosed());
2012 EXPECT_TRUE(delegate2
.StreamIsClosed());
2014 EXPECT_TRUE(session
== NULL
);
2017 // Create two streams that are set to close each other on close,
2018 // activate them, and then close the session. Nothing should blow up.
2019 TEST_P(SpdySessionTest
, CloseSessionWithTwoActivatedMutuallyClosingStreams
) {
2020 session_deps_
.host_resolver
->set_synchronous_mode(true);
2022 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2024 scoped_ptr
<SpdyFrame
> req1(
2025 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
2026 scoped_ptr
<SpdyFrame
> req2(
2027 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, MEDIUM
, true));
2028 MockWrite writes
[] = {
2029 CreateMockWrite(*req1
, 0),
2030 CreateMockWrite(*req2
, 1),
2033 MockRead reads
[] = {
2034 MockRead(ASYNC
, 0, 2) // EOF
2037 DeterministicSocketData
data(reads
, arraysize(reads
),
2038 writes
, arraysize(writes
));
2039 data
.set_connect_data(connect_data
);
2040 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2042 CreateDeterministicNetworkSession();
2044 base::WeakPtr
<SpdySession
> session
=
2045 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2047 GURL
url1(kDefaultURL
);
2048 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2049 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2050 session
, url1
, MEDIUM
, BoundNetLog());
2051 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2052 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2054 GURL
url2(kDefaultURL
);
2055 base::WeakPtr
<SpdyStream
> spdy_stream2
=
2056 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2057 session
, url2
, MEDIUM
, BoundNetLog());
2058 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
2059 EXPECT_EQ(0u, spdy_stream2
->stream_id());
2061 // Make |spdy_stream1| close |spdy_stream2|.
2062 test::ClosingDelegate
delegate1(spdy_stream2
);
2063 spdy_stream1
->SetDelegate(&delegate1
);
2065 // Make |spdy_stream2| close |spdy_stream1|.
2066 test::ClosingDelegate
delegate2(spdy_stream1
);
2067 spdy_stream2
->SetDelegate(&delegate2
);
2069 scoped_ptr
<SpdyHeaderBlock
> headers(
2070 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2071 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
2072 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2074 scoped_ptr
<SpdyHeaderBlock
> headers2(
2075 spdy_util_
.ConstructGetHeaderBlock(url2
.spec()));
2076 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
2077 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
2079 // Ensure that the streams have not yet been activated and assigned an id.
2080 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2081 EXPECT_EQ(0u, spdy_stream2
->stream_id());
2085 EXPECT_EQ(1u, spdy_stream1
->stream_id());
2086 EXPECT_EQ(3u, spdy_stream2
->stream_id());
2088 // Ensure we don't crash while closing the session.
2089 session
->CloseSessionOnError(ERR_ABORTED
, std::string());
2091 EXPECT_EQ(NULL
, spdy_stream1
.get());
2092 EXPECT_EQ(NULL
, spdy_stream2
.get());
2094 EXPECT_TRUE(delegate1
.StreamIsClosed());
2095 EXPECT_TRUE(delegate2
.StreamIsClosed());
2097 EXPECT_TRUE(session
== NULL
);
2100 // Delegate that closes a given session when the stream is closed.
2101 class SessionClosingDelegate
: public test::StreamDelegateDoNothing
{
2103 SessionClosingDelegate(const base::WeakPtr
<SpdyStream
>& stream
,
2104 const base::WeakPtr
<SpdySession
>& session_to_close
)
2105 : StreamDelegateDoNothing(stream
),
2106 session_to_close_(session_to_close
) {}
2108 virtual ~SessionClosingDelegate() {}
2110 virtual void OnClose(int status
) OVERRIDE
{
2111 session_to_close_
->CloseSessionOnError(ERR_ABORTED
, "Aborted");
2115 base::WeakPtr
<SpdySession
> session_to_close_
;
2118 // Close an activated stream that closes its session. Nothing should
2119 // blow up. This is a regression test for http://crbug.com/263691 .
2120 TEST_P(SpdySessionTest
, CloseActivatedStreamThatClosesSession
) {
2121 session_deps_
.host_resolver
->set_synchronous_mode(true);
2123 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2125 scoped_ptr
<SpdyFrame
> req(
2126 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
2127 MockWrite writes
[] = {
2128 CreateMockWrite(*req
, 0),
2131 MockRead reads
[] = {
2132 MockRead(ASYNC
, 0, 1) // EOF
2134 DeterministicSocketData
data(reads
, arraysize(reads
),
2135 writes
, arraysize(writes
));
2136 data
.set_connect_data(connect_data
);
2137 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2139 CreateDeterministicNetworkSession();
2141 base::WeakPtr
<SpdySession
> session
=
2142 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2144 GURL
url(kDefaultURL
);
2145 base::WeakPtr
<SpdyStream
> spdy_stream
=
2146 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2147 session
, url
, MEDIUM
, BoundNetLog());
2148 ASSERT_TRUE(spdy_stream
.get() != NULL
);
2149 EXPECT_EQ(0u, spdy_stream
->stream_id());
2151 SessionClosingDelegate
delegate(spdy_stream
, session
);
2152 spdy_stream
->SetDelegate(&delegate
);
2154 scoped_ptr
<SpdyHeaderBlock
> headers(
2155 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
2156 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
2157 EXPECT_TRUE(spdy_stream
->HasUrlFromHeaders());
2159 EXPECT_EQ(0u, spdy_stream
->stream_id());
2163 EXPECT_EQ(1u, spdy_stream
->stream_id());
2165 // Ensure we don't crash while closing the stream (which closes the
2167 spdy_stream
->Cancel();
2169 EXPECT_EQ(NULL
, spdy_stream
.get());
2170 EXPECT_TRUE(delegate
.StreamIsClosed());
2171 EXPECT_TRUE(session
== NULL
);
2174 TEST_P(SpdySessionTest
, VerifyDomainAuthentication
) {
2175 session_deps_
.host_resolver
->set_synchronous_mode(true);
2177 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2179 // No actual data will be sent.
2180 MockWrite writes
[] = {
2181 MockWrite(ASYNC
, 0, 1) // EOF
2184 MockRead reads
[] = {
2185 MockRead(ASYNC
, 0, 0) // EOF
2187 DeterministicSocketData
data(reads
, arraysize(reads
),
2188 writes
, arraysize(writes
));
2189 data
.set_connect_data(connect_data
);
2190 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2192 // Load a cert that is valid for:
2196 base::FilePath certs_dir
= GetTestCertsDirectory();
2197 scoped_refptr
<X509Certificate
> test_cert(
2198 ImportCertFromFile(certs_dir
, "spdy_pooling.pem"));
2199 ASSERT_NE(static_cast<X509Certificate
*>(NULL
), test_cert
);
2201 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
2202 ssl
.cert
= test_cert
;
2203 session_deps_
.deterministic_socket_factory
->AddSSLSocketDataProvider(&ssl
);
2205 CreateDeterministicNetworkSession();
2207 base::WeakPtr
<SpdySession
> session
=
2208 CreateSecureSpdySession(http_session_
, key_
, BoundNetLog());
2210 EXPECT_TRUE(session
->VerifyDomainAuthentication("www.example.org"));
2211 EXPECT_TRUE(session
->VerifyDomainAuthentication("mail.example.org"));
2212 EXPECT_TRUE(session
->VerifyDomainAuthentication("mail.example.com"));
2213 EXPECT_FALSE(session
->VerifyDomainAuthentication("mail.google.com"));
2216 TEST_P(SpdySessionTest
, ConnectionPooledWithTlsChannelId
) {
2217 session_deps_
.host_resolver
->set_synchronous_mode(true);
2219 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2221 // No actual data will be sent.
2222 MockWrite writes
[] = {
2223 MockWrite(ASYNC
, 0, 1) // EOF
2226 MockRead reads
[] = {
2227 MockRead(ASYNC
, 0, 0) // EOF
2229 DeterministicSocketData
data(reads
, arraysize(reads
),
2230 writes
, arraysize(writes
));
2231 data
.set_connect_data(connect_data
);
2232 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2234 // Load a cert that is valid for:
2238 base::FilePath certs_dir
= GetTestCertsDirectory();
2239 scoped_refptr
<X509Certificate
> test_cert(
2240 ImportCertFromFile(certs_dir
, "spdy_pooling.pem"));
2241 ASSERT_NE(static_cast<X509Certificate
*>(NULL
), test_cert
);
2243 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
2244 ssl
.channel_id_sent
= true;
2245 ssl
.cert
= test_cert
;
2246 session_deps_
.deterministic_socket_factory
->AddSSLSocketDataProvider(&ssl
);
2248 CreateDeterministicNetworkSession();
2250 base::WeakPtr
<SpdySession
> session
=
2251 CreateSecureSpdySession(http_session_
, key_
, BoundNetLog());
2253 EXPECT_TRUE(session
->VerifyDomainAuthentication("www.example.org"));
2254 EXPECT_TRUE(session
->VerifyDomainAuthentication("mail.example.org"));
2255 EXPECT_FALSE(session
->VerifyDomainAuthentication("mail.example.com"));
2256 EXPECT_FALSE(session
->VerifyDomainAuthentication("mail.google.com"));
2259 TEST_P(SpdySessionTest
, CloseTwoStalledCreateStream
) {
2260 // TODO(rtenneti): Define a helper class/methods and move the common code in
2262 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2264 SettingsMap new_settings
;
2265 const SpdySettingsIds kSpdySettingsIds1
= SETTINGS_MAX_CONCURRENT_STREAMS
;
2266 const uint32 max_concurrent_streams
= 1;
2267 new_settings
[kSpdySettingsIds1
] =
2268 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
2270 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
2271 scoped_ptr
<SpdyFrame
> req1(
2272 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2273 scoped_ptr
<SpdyFrame
> req2(
2274 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
2275 scoped_ptr
<SpdyFrame
> req3(
2276 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
2277 MockWrite writes
[] = {
2278 CreateMockWrite(*settings_ack
, 1),
2279 CreateMockWrite(*req1
, 2),
2280 CreateMockWrite(*req2
, 5),
2281 CreateMockWrite(*req3
, 8),
2284 // Set up the socket so we read a SETTINGS frame that sets max concurrent
2286 scoped_ptr
<SpdyFrame
> settings_frame(
2287 spdy_util_
.ConstructSpdySettings(new_settings
));
2289 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2290 scoped_ptr
<SpdyFrame
> body1(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2292 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
2293 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
2295 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
2296 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
2298 MockRead reads
[] = {
2299 CreateMockRead(*settings_frame
),
2300 CreateMockRead(*resp1
, 3),
2301 CreateMockRead(*body1
, 4),
2302 CreateMockRead(*resp2
, 6),
2303 CreateMockRead(*body2
, 7),
2304 CreateMockRead(*resp3
, 9),
2305 CreateMockRead(*body3
, 10),
2306 MockRead(ASYNC
, 0, 11) // EOF
2309 DeterministicSocketData
data(reads
, arraysize(reads
),
2310 writes
, arraysize(writes
));
2311 data
.set_connect_data(connect_data
);
2312 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2314 CreateDeterministicNetworkSession();
2316 base::WeakPtr
<SpdySession
> session
=
2317 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2319 // Read the settings frame.
2322 GURL
url1(kDefaultURL
);
2323 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2324 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2325 session
, url1
, LOWEST
, BoundNetLog());
2326 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2327 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2328 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
2329 spdy_stream1
->SetDelegate(&delegate1
);
2331 TestCompletionCallback callback2
;
2332 GURL
url2(kDefaultURL
);
2333 SpdyStreamRequest request2
;
2334 ASSERT_EQ(ERR_IO_PENDING
,
2335 request2
.StartRequest(
2336 SPDY_REQUEST_RESPONSE_STREAM
,
2337 session
, url2
, LOWEST
, BoundNetLog(), callback2
.callback()));
2339 TestCompletionCallback callback3
;
2340 GURL
url3(kDefaultURL
);
2341 SpdyStreamRequest request3
;
2342 ASSERT_EQ(ERR_IO_PENDING
,
2343 request3
.StartRequest(
2344 SPDY_REQUEST_RESPONSE_STREAM
,
2345 session
, url3
, LOWEST
, BoundNetLog(), callback3
.callback()));
2347 EXPECT_EQ(0u, session
->num_active_streams());
2348 EXPECT_EQ(1u, session
->num_created_streams());
2349 EXPECT_EQ(2u, session
->pending_create_stream_queue_size(LOWEST
));
2351 scoped_ptr
<SpdyHeaderBlock
> headers(
2352 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2353 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
2354 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2356 // Run until 1st stream is activated and then closed.
2357 EXPECT_EQ(0u, delegate1
.stream_id());
2359 EXPECT_EQ(NULL
, spdy_stream1
.get());
2360 EXPECT_EQ(1u, delegate1
.stream_id());
2362 EXPECT_EQ(0u, session
->num_active_streams());
2363 EXPECT_EQ(0u, session
->num_created_streams());
2364 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(LOWEST
));
2366 // Pump loop for SpdySession::ProcessPendingStreamRequests() to
2367 // create the 2nd stream.
2368 base::MessageLoop::current()->RunUntilIdle();
2370 EXPECT_EQ(0u, session
->num_active_streams());
2371 EXPECT_EQ(1u, session
->num_created_streams());
2372 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(LOWEST
));
2374 base::WeakPtr
<SpdyStream
> stream2
= request2
.ReleaseStream();
2375 test::StreamDelegateDoNothing
delegate2(stream2
);
2376 stream2
->SetDelegate(&delegate2
);
2377 scoped_ptr
<SpdyHeaderBlock
> headers2(
2378 spdy_util_
.ConstructGetHeaderBlock(url2
.spec()));
2379 stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
2380 EXPECT_TRUE(stream2
->HasUrlFromHeaders());
2382 // Run until 2nd stream is activated and then closed.
2383 EXPECT_EQ(0u, delegate2
.stream_id());
2385 EXPECT_EQ(NULL
, stream2
.get());
2386 EXPECT_EQ(3u, delegate2
.stream_id());
2388 EXPECT_EQ(0u, session
->num_active_streams());
2389 EXPECT_EQ(0u, session
->num_created_streams());
2390 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(LOWEST
));
2392 // Pump loop for SpdySession::ProcessPendingStreamRequests() to
2393 // create the 3rd stream.
2394 base::MessageLoop::current()->RunUntilIdle();
2396 EXPECT_EQ(0u, session
->num_active_streams());
2397 EXPECT_EQ(1u, session
->num_created_streams());
2398 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(LOWEST
));
2400 base::WeakPtr
<SpdyStream
> stream3
= request3
.ReleaseStream();
2401 test::StreamDelegateDoNothing
delegate3(stream3
);
2402 stream3
->SetDelegate(&delegate3
);
2403 scoped_ptr
<SpdyHeaderBlock
> headers3(
2404 spdy_util_
.ConstructGetHeaderBlock(url3
.spec()));
2405 stream3
->SendRequestHeaders(headers3
.Pass(), NO_MORE_DATA_TO_SEND
);
2406 EXPECT_TRUE(stream3
->HasUrlFromHeaders());
2408 // Run until 2nd stream is activated and then closed.
2409 EXPECT_EQ(0u, delegate3
.stream_id());
2411 EXPECT_EQ(NULL
, stream3
.get());
2412 EXPECT_EQ(5u, delegate3
.stream_id());
2414 EXPECT_EQ(0u, session
->num_active_streams());
2415 EXPECT_EQ(0u, session
->num_created_streams());
2416 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(LOWEST
));
2421 TEST_P(SpdySessionTest
, CancelTwoStalledCreateStream
) {
2422 session_deps_
.host_resolver
->set_synchronous_mode(true);
2424 MockRead reads
[] = {
2425 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
2428 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
2429 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2431 data
.set_connect_data(connect_data
);
2432 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
2434 CreateNetworkSession();
2436 base::WeakPtr
<SpdySession
> session
=
2437 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2439 // Leave room for only one more stream to be created.
2440 for (size_t i
= 0; i
< kInitialMaxConcurrentStreams
- 1; ++i
) {
2441 base::WeakPtr
<SpdyStream
> spdy_stream
=
2442 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
2443 session
, test_url_
, MEDIUM
, BoundNetLog());
2444 ASSERT_TRUE(spdy_stream
!= NULL
);
2447 GURL
url1(kDefaultURL
);
2448 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2449 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
2450 session
, url1
, LOWEST
, BoundNetLog());
2451 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2452 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2454 TestCompletionCallback callback2
;
2455 GURL
url2(kDefaultURL
);
2456 SpdyStreamRequest request2
;
2457 ASSERT_EQ(ERR_IO_PENDING
,
2458 request2
.StartRequest(
2459 SPDY_BIDIRECTIONAL_STREAM
, session
, url2
, LOWEST
, BoundNetLog(),
2460 callback2
.callback()));
2462 TestCompletionCallback callback3
;
2463 GURL
url3(kDefaultURL
);
2464 SpdyStreamRequest request3
;
2465 ASSERT_EQ(ERR_IO_PENDING
,
2466 request3
.StartRequest(
2467 SPDY_BIDIRECTIONAL_STREAM
, session
, url3
, LOWEST
, BoundNetLog(),
2468 callback3
.callback()));
2470 EXPECT_EQ(0u, session
->num_active_streams());
2471 EXPECT_EQ(kInitialMaxConcurrentStreams
, session
->num_created_streams());
2472 EXPECT_EQ(2u, session
->pending_create_stream_queue_size(LOWEST
));
2474 // Cancel the first stream; this will allow the second stream to be created.
2475 EXPECT_TRUE(spdy_stream1
.get() != NULL
);
2476 spdy_stream1
->Cancel();
2477 EXPECT_EQ(NULL
, spdy_stream1
.get());
2479 EXPECT_EQ(OK
, callback2
.WaitForResult());
2480 EXPECT_EQ(0u, session
->num_active_streams());
2481 EXPECT_EQ(kInitialMaxConcurrentStreams
, session
->num_created_streams());
2482 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(LOWEST
));
2484 // Cancel the second stream; this will allow the third stream to be created.
2485 base::WeakPtr
<SpdyStream
> spdy_stream2
= request2
.ReleaseStream();
2486 spdy_stream2
->Cancel();
2487 EXPECT_EQ(NULL
, spdy_stream2
.get());
2489 EXPECT_EQ(OK
, callback3
.WaitForResult());
2490 EXPECT_EQ(0u, session
->num_active_streams());
2491 EXPECT_EQ(kInitialMaxConcurrentStreams
, session
->num_created_streams());
2492 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(LOWEST
));
2494 // Cancel the third stream.
2495 base::WeakPtr
<SpdyStream
> spdy_stream3
= request3
.ReleaseStream();
2496 spdy_stream3
->Cancel();
2497 EXPECT_EQ(NULL
, spdy_stream3
.get());
2498 EXPECT_EQ(0u, session
->num_active_streams());
2499 EXPECT_EQ(kInitialMaxConcurrentStreams
- 1, session
->num_created_streams());
2500 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(LOWEST
));
2503 // Test that SpdySession::DoReadLoop reads data from the socket
2504 // without yielding. This test makes 32k - 1 bytes of data available
2505 // on the socket for reading. It then verifies that it has read all
2506 // the available data without yielding.
2507 TEST_P(SpdySessionTest
, ReadDataWithoutYielding
) {
2508 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2509 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
2511 scoped_ptr
<SpdyFrame
> req1(
2512 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
2513 MockWrite writes
[] = {
2514 CreateMockWrite(*req1
, 0),
2517 // Build buffer of size kMaxReadBytesWithoutYielding / 4
2518 // (-spdy_data_frame_size).
2519 ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding
);
2520 const int kPayloadSize
=
2521 kMaxReadBytesWithoutYielding
/ 4 - framer
.GetControlFrameHeaderSize();
2522 TestDataStream test_stream
;
2523 scoped_refptr
<net::IOBuffer
> payload(new net::IOBuffer(kPayloadSize
));
2524 char* payload_data
= payload
->data();
2525 test_stream
.GetBytes(payload_data
, kPayloadSize
);
2527 scoped_ptr
<SpdyFrame
> partial_data_frame(
2528 framer
.CreateDataFrame(1, payload_data
, kPayloadSize
, DATA_FLAG_NONE
));
2529 scoped_ptr
<SpdyFrame
> finish_data_frame(
2530 framer
.CreateDataFrame(1, payload_data
, kPayloadSize
- 1, DATA_FLAG_FIN
));
2532 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2534 // Write 1 byte less than kMaxReadBytes to check that DoRead reads up to 32k
2536 MockRead reads
[] = {
2537 CreateMockRead(*resp1
, 1),
2538 CreateMockRead(*partial_data_frame
, 2),
2539 CreateMockRead(*partial_data_frame
, 3, SYNCHRONOUS
),
2540 CreateMockRead(*partial_data_frame
, 4, SYNCHRONOUS
),
2541 CreateMockRead(*finish_data_frame
, 5, SYNCHRONOUS
),
2542 MockRead(ASYNC
, 0, 6) // EOF
2545 // Create SpdySession and SpdyStream and send the request.
2546 DeterministicSocketData
data(reads
, arraysize(reads
),
2547 writes
, arraysize(writes
));
2548 data
.set_connect_data(connect_data
);
2549 session_deps_
.host_resolver
->set_synchronous_mode(true);
2550 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2552 CreateDeterministicNetworkSession();
2554 base::WeakPtr
<SpdySession
> session
=
2555 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2557 GURL
url1(kDefaultURL
);
2558 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2559 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2560 session
, url1
, MEDIUM
, BoundNetLog());
2561 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2562 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2563 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
2564 spdy_stream1
->SetDelegate(&delegate1
);
2566 scoped_ptr
<SpdyHeaderBlock
> headers1(
2567 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2568 spdy_stream1
->SendRequestHeaders(headers1
.Pass(), NO_MORE_DATA_TO_SEND
);
2569 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2571 // Set up the TaskObserver to verify SpdySession::DoReadLoop doesn't
2573 SpdySessionTestTaskObserver
observer("spdy_session.cc", "DoReadLoop");
2575 // Run until 1st read.
2576 EXPECT_EQ(0u, delegate1
.stream_id());
2578 EXPECT_EQ(1u, delegate1
.stream_id());
2579 EXPECT_EQ(0u, observer
.executed_count());
2581 // Read all the data and verify SpdySession::DoReadLoop has not
2584 EXPECT_EQ(NULL
, spdy_stream1
.get());
2586 // Verify task observer's executed_count is zero, which indicates DoRead read
2587 // all the available data.
2588 EXPECT_EQ(0u, observer
.executed_count());
2589 EXPECT_TRUE(data
.at_write_eof());
2590 EXPECT_TRUE(data
.at_read_eof());
2593 // Test that SpdySession::DoReadLoop yields while reading the
2594 // data. This test makes 32k + 1 bytes of data available on the socket
2595 // for reading. It then verifies that DoRead has yielded even though
2596 // there is data available for it to read (i.e, socket()->Read didn't
2597 // return ERR_IO_PENDING during socket reads).
2598 TEST_P(SpdySessionTest
, TestYieldingDuringReadData
) {
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 // Build buffer of size kMaxReadBytesWithoutYielding / 4
2609 // (-spdy_data_frame_size).
2610 ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding
);
2611 const int kPayloadSize
=
2612 kMaxReadBytesWithoutYielding
/ 4 - framer
.GetControlFrameHeaderSize();
2613 TestDataStream test_stream
;
2614 scoped_refptr
<net::IOBuffer
> payload(new net::IOBuffer(kPayloadSize
));
2615 char* payload_data
= payload
->data();
2616 test_stream
.GetBytes(payload_data
, kPayloadSize
);
2618 scoped_ptr
<SpdyFrame
> partial_data_frame(
2619 framer
.CreateDataFrame(1, payload_data
, kPayloadSize
, DATA_FLAG_NONE
));
2620 scoped_ptr
<SpdyFrame
> finish_data_frame(
2621 framer
.CreateDataFrame(1, "h", 1, DATA_FLAG_FIN
));
2623 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2625 // Write 1 byte more than kMaxReadBytes to check that DoRead yields.
2626 MockRead reads
[] = {
2627 CreateMockRead(*resp1
, 1),
2628 CreateMockRead(*partial_data_frame
, 2),
2629 CreateMockRead(*partial_data_frame
, 3, SYNCHRONOUS
),
2630 CreateMockRead(*partial_data_frame
, 4, SYNCHRONOUS
),
2631 CreateMockRead(*partial_data_frame
, 5, SYNCHRONOUS
),
2632 CreateMockRead(*finish_data_frame
, 6, SYNCHRONOUS
),
2633 MockRead(ASYNC
, 0, 7) // EOF
2636 // Create SpdySession and SpdyStream and send the request.
2637 DeterministicSocketData
data(reads
, arraysize(reads
),
2638 writes
, arraysize(writes
));
2639 data
.set_connect_data(connect_data
);
2640 session_deps_
.host_resolver
->set_synchronous_mode(true);
2641 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2643 CreateDeterministicNetworkSession();
2645 base::WeakPtr
<SpdySession
> session
=
2646 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2648 GURL
url1(kDefaultURL
);
2649 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2650 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2651 session
, url1
, MEDIUM
, BoundNetLog());
2652 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2653 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2654 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
2655 spdy_stream1
->SetDelegate(&delegate1
);
2657 scoped_ptr
<SpdyHeaderBlock
> headers1(
2658 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2659 spdy_stream1
->SendRequestHeaders(headers1
.Pass(), NO_MORE_DATA_TO_SEND
);
2660 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2662 // Set up the TaskObserver to verify SpdySession::DoReadLoop posts a
2664 SpdySessionTestTaskObserver
observer("spdy_session.cc", "DoReadLoop");
2666 // Run until 1st read.
2667 EXPECT_EQ(0u, delegate1
.stream_id());
2669 EXPECT_EQ(1u, delegate1
.stream_id());
2670 EXPECT_EQ(0u, observer
.executed_count());
2672 // Read all the data and verify SpdySession::DoReadLoop has posted a
2675 EXPECT_EQ(NULL
, spdy_stream1
.get());
2677 // Verify task observer's executed_count is 1, which indicates DoRead has
2678 // posted only one task and thus yielded though there is data available for it
2680 EXPECT_EQ(1u, observer
.executed_count());
2681 EXPECT_TRUE(data
.at_write_eof());
2682 EXPECT_TRUE(data
.at_read_eof());
2685 // Test that SpdySession::DoReadLoop() tests interactions of yielding
2686 // + async, by doing the following MockReads.
2688 // MockRead of SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K
2689 // ASYNC 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K.
2691 // The above reads 26K synchronously. Since that is less that 32K, we
2692 // will attempt to read again. However, that DoRead() will return
2693 // ERR_IO_PENDING (because of async read), so DoReadLoop() will
2694 // yield. When we come back, DoRead() will read the results from the
2695 // async read, and rest of the data synchronously.
2696 TEST_P(SpdySessionTest
, TestYieldingDuringAsyncReadData
) {
2697 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2698 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
2700 scoped_ptr
<SpdyFrame
> req1(
2701 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
2702 MockWrite writes
[] = {
2703 CreateMockWrite(*req1
, 0),
2706 // Build buffer of size kMaxReadBytesWithoutYielding / 4
2707 // (-spdy_data_frame_size).
2708 ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding
);
2709 TestDataStream test_stream
;
2710 const int kEightKPayloadSize
=
2711 kMaxReadBytesWithoutYielding
/ 4 - framer
.GetControlFrameHeaderSize();
2712 scoped_refptr
<net::IOBuffer
> eightk_payload(
2713 new net::IOBuffer(kEightKPayloadSize
));
2714 char* eightk_payload_data
= eightk_payload
->data();
2715 test_stream
.GetBytes(eightk_payload_data
, kEightKPayloadSize
);
2717 // Build buffer of 2k size.
2718 TestDataStream test_stream2
;
2719 const int kTwoKPayloadSize
= kEightKPayloadSize
- 6 * 1024;
2720 scoped_refptr
<net::IOBuffer
> twok_payload(
2721 new net::IOBuffer(kTwoKPayloadSize
));
2722 char* twok_payload_data
= twok_payload
->data();
2723 test_stream2
.GetBytes(twok_payload_data
, kTwoKPayloadSize
);
2725 scoped_ptr
<SpdyFrame
> eightk_data_frame(framer
.CreateDataFrame(
2726 1, eightk_payload_data
, kEightKPayloadSize
, DATA_FLAG_NONE
));
2727 scoped_ptr
<SpdyFrame
> twok_data_frame(framer
.CreateDataFrame(
2728 1, twok_payload_data
, kTwoKPayloadSize
, DATA_FLAG_NONE
));
2729 scoped_ptr
<SpdyFrame
> finish_data_frame(framer
.CreateDataFrame(
2730 1, "h", 1, DATA_FLAG_FIN
));
2732 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2734 MockRead reads
[] = {
2735 CreateMockRead(*resp1
, 1),
2736 CreateMockRead(*eightk_data_frame
, 2),
2737 CreateMockRead(*eightk_data_frame
, 3, SYNCHRONOUS
),
2738 CreateMockRead(*eightk_data_frame
, 4, SYNCHRONOUS
),
2739 CreateMockRead(*twok_data_frame
, 5, SYNCHRONOUS
),
2740 CreateMockRead(*eightk_data_frame
, 6, ASYNC
),
2741 CreateMockRead(*eightk_data_frame
, 7, SYNCHRONOUS
),
2742 CreateMockRead(*eightk_data_frame
, 8, SYNCHRONOUS
),
2743 CreateMockRead(*eightk_data_frame
, 9, SYNCHRONOUS
),
2744 CreateMockRead(*twok_data_frame
, 10, SYNCHRONOUS
),
2745 CreateMockRead(*finish_data_frame
, 11, SYNCHRONOUS
),
2746 MockRead(ASYNC
, 0, 12) // EOF
2749 // Create SpdySession and SpdyStream and send the request.
2750 DeterministicSocketData
data(reads
, arraysize(reads
),
2751 writes
, arraysize(writes
));
2752 data
.set_connect_data(connect_data
);
2753 session_deps_
.host_resolver
->set_synchronous_mode(true);
2754 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2756 CreateDeterministicNetworkSession();
2758 base::WeakPtr
<SpdySession
> session
=
2759 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2761 GURL
url1(kDefaultURL
);
2762 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2763 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2764 session
, url1
, MEDIUM
, BoundNetLog());
2765 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2766 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2767 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
2768 spdy_stream1
->SetDelegate(&delegate1
);
2770 scoped_ptr
<SpdyHeaderBlock
> headers1(
2771 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2772 spdy_stream1
->SendRequestHeaders(headers1
.Pass(), NO_MORE_DATA_TO_SEND
);
2773 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2775 // Set up the TaskObserver to monitor SpdySession::DoReadLoop
2776 // posting of tasks.
2777 SpdySessionTestTaskObserver
observer("spdy_session.cc", "DoReadLoop");
2779 // Run until 1st read.
2780 EXPECT_EQ(0u, delegate1
.stream_id());
2782 EXPECT_EQ(1u, delegate1
.stream_id());
2783 EXPECT_EQ(0u, observer
.executed_count());
2785 // Read all the data and verify SpdySession::DoReadLoop has posted a
2788 EXPECT_EQ(NULL
, spdy_stream1
.get());
2790 // Verify task observer's executed_count is 1, which indicates DoRead has
2791 // posted only one task and thus yielded though there is data available for
2793 EXPECT_EQ(1u, observer
.executed_count());
2794 EXPECT_TRUE(data
.at_write_eof());
2795 EXPECT_TRUE(data
.at_read_eof());
2798 // Send a GoAway frame when SpdySession is in DoReadLoop. Make sure
2799 // nothing blows up.
2800 TEST_P(SpdySessionTest
, GoAwayWhileInDoReadLoop
) {
2801 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2802 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
2804 scoped_ptr
<SpdyFrame
> req1(
2805 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
2806 MockWrite writes
[] = {
2807 CreateMockWrite(*req1
, 0),
2810 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2811 scoped_ptr
<SpdyFrame
> body1(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2812 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway());
2814 MockRead reads
[] = {
2815 CreateMockRead(*resp1
, 1),
2816 CreateMockRead(*body1
, 2),
2817 CreateMockRead(*goaway
, 3),
2820 // Create SpdySession and SpdyStream and send the request.
2821 DeterministicSocketData
data(reads
, arraysize(reads
),
2822 writes
, arraysize(writes
));
2823 data
.set_connect_data(connect_data
);
2824 session_deps_
.host_resolver
->set_synchronous_mode(true);
2825 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2827 CreateDeterministicNetworkSession();
2829 base::WeakPtr
<SpdySession
> session
=
2830 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2832 GURL
url1(kDefaultURL
);
2833 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2834 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2835 session
, url1
, MEDIUM
, BoundNetLog());
2836 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
2837 spdy_stream1
->SetDelegate(&delegate1
);
2838 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2839 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2841 scoped_ptr
<SpdyHeaderBlock
> headers1(
2842 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2843 spdy_stream1
->SendRequestHeaders(headers1
.Pass(), NO_MORE_DATA_TO_SEND
);
2844 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2846 // Run until 1st read.
2847 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2849 EXPECT_EQ(1u, spdy_stream1
->stream_id());
2851 // Run until GoAway.
2853 EXPECT_EQ(NULL
, spdy_stream1
.get());
2854 EXPECT_TRUE(data
.at_write_eof());
2855 EXPECT_TRUE(data
.at_read_eof());
2856 EXPECT_TRUE(session
== NULL
);
2859 // Within this framework, a SpdySession should be initialized with
2860 // flow control disabled for protocol version 2, with flow control
2861 // enabled only for streams for protocol version 3, and with flow
2862 // control enabled for streams and sessions for higher versions.
2863 TEST_P(SpdySessionTest
, ProtocolNegotiation
) {
2864 session_deps_
.host_resolver
->set_synchronous_mode(true);
2866 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2867 MockRead reads
[] = {
2868 MockRead(SYNCHRONOUS
, 0, 0) // EOF
2870 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
2871 data
.set_connect_data(connect_data
);
2872 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
2874 CreateNetworkSession();
2875 base::WeakPtr
<SpdySession
> session
=
2876 CreateFakeSpdySession(spdy_session_pool_
, key_
);
2878 EXPECT_EQ(spdy_util_
.spdy_version(),
2879 session
->buffered_spdy_framer_
->protocol_version());
2880 if (GetParam() == kProtoDeprecatedSPDY2
) {
2881 EXPECT_EQ(SpdySession::FLOW_CONTROL_NONE
, session
->flow_control_state());
2882 EXPECT_EQ(0, session
->session_send_window_size_
);
2883 EXPECT_EQ(0, session
->session_recv_window_size_
);
2884 } else if (GetParam() == kProtoSPDY3
) {
2885 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM
, session
->flow_control_state());
2886 EXPECT_EQ(0, session
->session_send_window_size_
);
2887 EXPECT_EQ(0, session
->session_recv_window_size_
);
2889 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
2890 session
->flow_control_state());
2891 EXPECT_EQ(kSpdySessionInitialWindowSize
,
2892 session
->session_send_window_size_
);
2893 EXPECT_EQ(kSpdySessionInitialWindowSize
,
2894 session
->session_recv_window_size_
);
2896 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
2899 // Tests the case of a non-SPDY request closing an idle SPDY session when no
2900 // pointers to the idle session are currently held.
2901 TEST_P(SpdySessionTest
, CloseOneIdleConnection
) {
2902 ClientSocketPoolManager::set_max_sockets_per_group(
2903 HttpNetworkSession::NORMAL_SOCKET_POOL
, 1);
2904 ClientSocketPoolManager::set_max_sockets_per_pool(
2905 HttpNetworkSession::NORMAL_SOCKET_POOL
, 1);
2907 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2908 MockRead reads
[] = {
2909 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
2911 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
2912 data
.set_connect_data(connect_data
);
2913 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
2914 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
2916 CreateNetworkSession();
2918 TransportClientSocketPool
* pool
=
2919 http_session_
->GetTransportSocketPool(
2920 HttpNetworkSession::NORMAL_SOCKET_POOL
);
2922 // Create an idle SPDY session.
2923 SpdySessionKey
key1(HostPortPair("1.com", 80), ProxyServer::Direct(),
2924 PRIVACY_MODE_DISABLED
);
2925 base::WeakPtr
<SpdySession
> session1
=
2926 CreateInsecureSpdySession(http_session_
, key1
, BoundNetLog());
2927 EXPECT_FALSE(pool
->IsStalled());
2929 // Trying to create a new connection should cause the pool to be stalled, and
2930 // post a task asynchronously to try and close the session.
2931 TestCompletionCallback callback2
;
2932 HostPortPair
host_port2("2.com", 80);
2933 scoped_refptr
<TransportSocketParams
> params2(
2934 new TransportSocketParams(host_port2
, false, false,
2935 OnHostResolutionCallback()));
2936 scoped_ptr
<ClientSocketHandle
> connection2(new ClientSocketHandle
);
2937 EXPECT_EQ(ERR_IO_PENDING
,
2938 connection2
->Init(host_port2
.ToString(), params2
, DEFAULT_PRIORITY
,
2939 callback2
.callback(), pool
, BoundNetLog()));
2940 EXPECT_TRUE(pool
->IsStalled());
2942 // The socket pool should close the connection asynchronously and establish a
2944 EXPECT_EQ(OK
, callback2
.WaitForResult());
2945 EXPECT_FALSE(pool
->IsStalled());
2946 EXPECT_TRUE(session1
== NULL
);
2949 // Tests the case of a non-SPDY request closing an idle SPDY session when no
2950 // pointers to the idle session are currently held, in the case the SPDY session
2952 TEST_P(SpdySessionTest
, CloseOneIdleConnectionWithAlias
) {
2953 ClientSocketPoolManager::set_max_sockets_per_group(
2954 HttpNetworkSession::NORMAL_SOCKET_POOL
, 1);
2955 ClientSocketPoolManager::set_max_sockets_per_pool(
2956 HttpNetworkSession::NORMAL_SOCKET_POOL
, 1);
2958 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2959 MockRead reads
[] = {
2960 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
2962 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
2963 data
.set_connect_data(connect_data
);
2964 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
2965 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
2967 session_deps_
.host_resolver
->set_synchronous_mode(true);
2968 session_deps_
.host_resolver
->rules()->AddIPLiteralRule(
2969 "1.com", "192.168.0.2", std::string());
2970 session_deps_
.host_resolver
->rules()->AddIPLiteralRule(
2971 "2.com", "192.168.0.2", std::string());
2972 // Not strictly needed.
2973 session_deps_
.host_resolver
->rules()->AddIPLiteralRule(
2974 "3.com", "192.168.0.3", std::string());
2976 CreateNetworkSession();
2978 TransportClientSocketPool
* pool
=
2979 http_session_
->GetTransportSocketPool(
2980 HttpNetworkSession::NORMAL_SOCKET_POOL
);
2982 // Create an idle SPDY session.
2983 SpdySessionKey
key1(HostPortPair("1.com", 80), ProxyServer::Direct(),
2984 PRIVACY_MODE_DISABLED
);
2985 base::WeakPtr
<SpdySession
> session1
=
2986 CreateInsecureSpdySession(http_session_
, key1
, BoundNetLog());
2987 EXPECT_FALSE(pool
->IsStalled());
2989 // Set up an alias for the idle SPDY session, increasing its ref count to 2.
2990 SpdySessionKey
key2(HostPortPair("2.com", 80), ProxyServer::Direct(),
2991 PRIVACY_MODE_DISABLED
);
2992 HostResolver::RequestInfo
info(key2
.host_port_pair());
2993 AddressList addresses
;
2994 // Pre-populate the DNS cache, since a synchronous resolution is required in
2995 // order to create the alias.
2996 session_deps_
.host_resolver
->Resolve(info
,
2999 CompletionCallback(),
3002 // Get a session for |key2|, which should return the session created earlier.
3003 base::WeakPtr
<SpdySession
> session2
=
3004 spdy_session_pool_
->FindAvailableSession(key2
, BoundNetLog());
3005 ASSERT_EQ(session1
.get(), session2
.get());
3006 EXPECT_FALSE(pool
->IsStalled());
3008 // Trying to create a new connection should cause the pool to be stalled, and
3009 // post a task asynchronously to try and close the session.
3010 TestCompletionCallback callback3
;
3011 HostPortPair
host_port3("3.com", 80);
3012 scoped_refptr
<TransportSocketParams
> params3(
3013 new TransportSocketParams(host_port3
, false, false,
3014 OnHostResolutionCallback()));
3015 scoped_ptr
<ClientSocketHandle
> connection3(new ClientSocketHandle
);
3016 EXPECT_EQ(ERR_IO_PENDING
,
3017 connection3
->Init(host_port3
.ToString(), params3
, DEFAULT_PRIORITY
,
3018 callback3
.callback(), pool
, BoundNetLog()));
3019 EXPECT_TRUE(pool
->IsStalled());
3021 // The socket pool should close the connection asynchronously and establish a
3023 EXPECT_EQ(OK
, callback3
.WaitForResult());
3024 EXPECT_FALSE(pool
->IsStalled());
3025 EXPECT_TRUE(session1
== NULL
);
3026 EXPECT_TRUE(session2
== NULL
);
3029 // Tests that when a SPDY session becomes idle, it closes itself if there is
3030 // a lower layer pool stalled on the per-pool socket limit.
3031 TEST_P(SpdySessionTest
, CloseSessionOnIdleWhenPoolStalled
) {
3032 ClientSocketPoolManager::set_max_sockets_per_group(
3033 HttpNetworkSession::NORMAL_SOCKET_POOL
, 1);
3034 ClientSocketPoolManager::set_max_sockets_per_pool(
3035 HttpNetworkSession::NORMAL_SOCKET_POOL
, 1);
3037 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3038 MockRead reads
[] = {
3039 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
3041 scoped_ptr
<SpdyFrame
> req1(
3042 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3043 scoped_ptr
<SpdyFrame
> cancel1(
3044 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
3045 MockWrite writes
[] = {
3046 CreateMockWrite(*req1
, 1),
3047 CreateMockWrite(*cancel1
, 1),
3049 StaticSocketDataProvider
data(reads
, arraysize(reads
),
3050 writes
, arraysize(writes
));
3051 data
.set_connect_data(connect_data
);
3052 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
3054 MockRead http_reads
[] = {
3055 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
3057 StaticSocketDataProvider
http_data(http_reads
, arraysize(http_reads
),
3059 http_data
.set_connect_data(connect_data
);
3060 session_deps_
.socket_factory
->AddSocketDataProvider(&http_data
);
3063 CreateNetworkSession();
3065 TransportClientSocketPool
* pool
=
3066 http_session_
->GetTransportSocketPool(
3067 HttpNetworkSession::NORMAL_SOCKET_POOL
);
3069 // Create a SPDY session.
3070 GURL
url1(kDefaultURL
);
3071 SpdySessionKey
key1(HostPortPair(url1
.host(), 80),
3072 ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
3073 base::WeakPtr
<SpdySession
> session1
=
3074 CreateInsecureSpdySession(http_session_
, key1
, BoundNetLog());
3075 EXPECT_FALSE(pool
->IsStalled());
3077 // Create a stream using the session, and send a request.
3079 TestCompletionCallback callback1
;
3080 base::WeakPtr
<SpdyStream
> spdy_stream1
=
3081 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
3082 session1
, url1
, DEFAULT_PRIORITY
,
3084 ASSERT_TRUE(spdy_stream1
.get());
3085 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
3086 spdy_stream1
->SetDelegate(&delegate1
);
3088 scoped_ptr
<SpdyHeaderBlock
> headers1(
3089 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
3090 EXPECT_EQ(ERR_IO_PENDING
,
3091 spdy_stream1
->SendRequestHeaders(
3092 headers1
.Pass(), NO_MORE_DATA_TO_SEND
));
3093 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
3095 base::MessageLoop::current()->RunUntilIdle();
3097 // Trying to create a new connection should cause the pool to be stalled, and
3098 // post a task asynchronously to try and close the session.
3099 TestCompletionCallback callback2
;
3100 HostPortPair
host_port2("2.com", 80);
3101 scoped_refptr
<TransportSocketParams
> params2(
3102 new TransportSocketParams(host_port2
, false, false,
3103 OnHostResolutionCallback()));
3104 scoped_ptr
<ClientSocketHandle
> connection2(new ClientSocketHandle
);
3105 EXPECT_EQ(ERR_IO_PENDING
,
3106 connection2
->Init(host_port2
.ToString(), params2
, DEFAULT_PRIORITY
,
3107 callback2
.callback(), pool
, BoundNetLog()));
3108 EXPECT_TRUE(pool
->IsStalled());
3110 // Running the message loop should cause the socket pool to ask the SPDY
3111 // session to close an idle socket, but since the socket is in use, nothing
3113 base::RunLoop().RunUntilIdle();
3114 EXPECT_TRUE(pool
->IsStalled());
3115 EXPECT_FALSE(callback2
.have_result());
3117 // Cancelling the request should result in the session's socket being
3118 // closed, since the pool is stalled.
3119 ASSERT_TRUE(spdy_stream1
.get());
3120 spdy_stream1
->Cancel();
3121 base::RunLoop().RunUntilIdle();
3122 ASSERT_FALSE(pool
->IsStalled());
3123 EXPECT_EQ(OK
, callback2
.WaitForResult());
3126 // Verify that SpdySessionKey and therefore SpdySession is different when
3127 // privacy mode is enabled or disabled.
3128 TEST_P(SpdySessionTest
, SpdySessionKeyPrivacyMode
) {
3129 CreateDeterministicNetworkSession();
3131 HostPortPair
host_port_pair("www.google.com", 443);
3132 SpdySessionKey
key_privacy_enabled(host_port_pair
, ProxyServer::Direct(),
3133 PRIVACY_MODE_ENABLED
);
3134 SpdySessionKey
key_privacy_disabled(host_port_pair
, ProxyServer::Direct(),
3135 PRIVACY_MODE_DISABLED
);
3137 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_privacy_enabled
));
3138 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_privacy_disabled
));
3140 // Add SpdySession with PrivacyMode Enabled to the pool.
3141 base::WeakPtr
<SpdySession
> session_privacy_enabled
=
3142 CreateFakeSpdySession(spdy_session_pool_
, key_privacy_enabled
);
3144 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_privacy_enabled
));
3145 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_privacy_disabled
));
3147 // Add SpdySession with PrivacyMode Disabled to the pool.
3148 base::WeakPtr
<SpdySession
> session_privacy_disabled
=
3149 CreateFakeSpdySession(spdy_session_pool_
, key_privacy_disabled
);
3151 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_privacy_enabled
));
3152 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_privacy_disabled
));
3154 session_privacy_enabled
->CloseSessionOnError(ERR_ABORTED
, std::string());
3155 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_privacy_enabled
));
3156 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_privacy_disabled
));
3158 session_privacy_disabled
->CloseSessionOnError(ERR_ABORTED
, std::string());
3159 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_privacy_enabled
));
3160 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_privacy_disabled
));
3163 // Delegate that creates another stream when its stream is closed.
3164 class StreamCreatingDelegate
: public test::StreamDelegateDoNothing
{
3166 StreamCreatingDelegate(const base::WeakPtr
<SpdyStream
>& stream
,
3167 const base::WeakPtr
<SpdySession
>& session
)
3168 : StreamDelegateDoNothing(stream
),
3169 session_(session
) {}
3171 virtual ~StreamCreatingDelegate() {}
3173 virtual void OnClose(int status
) OVERRIDE
{
3174 GURL
url(kDefaultURL
);
3176 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
3177 session_
, url
, MEDIUM
, BoundNetLog()));
3181 const base::WeakPtr
<SpdySession
> session_
;
3184 // Create another stream in response to a stream being reset. Nothing
3185 // should blow up. This is a regression test for
3186 // http://crbug.com/263690 .
3187 TEST_P(SpdySessionTest
, CreateStreamOnStreamReset
) {
3188 session_deps_
.host_resolver
->set_synchronous_mode(true);
3190 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3192 scoped_ptr
<SpdyFrame
> req(
3193 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
3194 MockWrite writes
[] = {
3195 CreateMockWrite(*req
, 0),
3198 scoped_ptr
<SpdyFrame
> rst(
3199 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM
));
3200 MockRead reads
[] = {
3201 CreateMockRead(*rst
, 1),
3202 MockRead(ASYNC
, 0, 2) // EOF
3204 DeterministicSocketData
data(reads
, arraysize(reads
),
3205 writes
, arraysize(writes
));
3206 data
.set_connect_data(connect_data
);
3207 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3209 CreateDeterministicNetworkSession();
3211 base::WeakPtr
<SpdySession
> session
=
3212 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3214 GURL
url(kDefaultURL
);
3215 base::WeakPtr
<SpdyStream
> spdy_stream
=
3216 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
3217 session
, url
, MEDIUM
, BoundNetLog());
3218 ASSERT_TRUE(spdy_stream
.get() != NULL
);
3219 EXPECT_EQ(0u, spdy_stream
->stream_id());
3221 StreamCreatingDelegate
delegate(spdy_stream
, session
);
3222 spdy_stream
->SetDelegate(&delegate
);
3224 scoped_ptr
<SpdyHeaderBlock
> headers(
3225 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
3226 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
3227 EXPECT_TRUE(spdy_stream
->HasUrlFromHeaders());
3229 EXPECT_EQ(0u, spdy_stream
->stream_id());
3233 EXPECT_EQ(1u, spdy_stream
->stream_id());
3235 // Cause the stream to be reset, which should cause another stream
3239 EXPECT_EQ(NULL
, spdy_stream
.get());
3240 EXPECT_TRUE(delegate
.StreamIsClosed());
3241 EXPECT_EQ(0u, session
->num_active_streams());
3242 EXPECT_EQ(1u, session
->num_created_streams());
3245 // The tests below are only for SPDY/3 and above.
3247 TEST_P(SpdySessionTest
, UpdateStreamsSendWindowSize
) {
3248 if (GetParam() < kProtoSPDY3
)
3251 // Set SETTINGS_INITIAL_WINDOW_SIZE to a small number so that WINDOW_UPDATE
3253 SettingsMap new_settings
;
3254 int32 window_size
= 1;
3255 new_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
3256 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, window_size
);
3258 // Set up the socket so we read a SETTINGS frame that sets
3259 // INITIAL_WINDOW_SIZE.
3260 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3261 scoped_ptr
<SpdyFrame
> settings_frame(
3262 spdy_util_
.ConstructSpdySettings(new_settings
));
3263 MockRead reads
[] = {
3264 CreateMockRead(*settings_frame
, 0),
3265 MockRead(ASYNC
, 0, 1) // EOF
3268 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
3269 MockWrite writes
[] = {
3270 CreateMockWrite(*settings_ack
, 2),
3273 session_deps_
.host_resolver
->set_synchronous_mode(true);
3275 DeterministicSocketData
data(reads
, arraysize(reads
),
3276 writes
, arraysize(writes
));
3277 data
.set_connect_data(connect_data
);
3278 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3280 CreateDeterministicNetworkSession();
3282 base::WeakPtr
<SpdySession
> session
=
3283 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3284 base::WeakPtr
<SpdyStream
> spdy_stream1
=
3285 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
3286 session
, test_url_
, MEDIUM
, BoundNetLog());
3287 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
3288 TestCompletionCallback callback1
;
3289 EXPECT_NE(spdy_stream1
->send_window_size(), window_size
);
3291 data
.RunFor(1); // Process the SETTINGS frame, but not the EOF
3292 base::MessageLoop::current()->RunUntilIdle();
3293 EXPECT_EQ(session
->stream_initial_send_window_size(), window_size
);
3294 EXPECT_EQ(spdy_stream1
->send_window_size(), window_size
);
3296 // Release the first one, this will allow the second to be created.
3297 spdy_stream1
->Cancel();
3298 EXPECT_EQ(NULL
, spdy_stream1
.get());
3300 base::WeakPtr
<SpdyStream
> spdy_stream2
=
3301 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
3302 session
, test_url_
, MEDIUM
, BoundNetLog());
3303 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
3304 EXPECT_EQ(spdy_stream2
->send_window_size(), window_size
);
3305 spdy_stream2
->Cancel();
3306 EXPECT_EQ(NULL
, spdy_stream2
.get());
3309 // The tests below are only for SPDY/3.1 and above.
3311 // SpdySession::{Increase,Decrease}RecvWindowSize should properly
3312 // adjust the session receive window size for SPDY 3.1 and higher. In
3313 // addition, SpdySession::IncreaseRecvWindowSize should trigger
3314 // sending a WINDOW_UPDATE frame for a large enough delta.
3315 TEST_P(SpdySessionTest
, AdjustRecvWindowSize
) {
3316 if (GetParam() < kProtoSPDY31
)
3319 session_deps_
.host_resolver
->set_synchronous_mode(true);
3321 const int32 delta_window_size
= 100;
3323 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3324 MockRead reads
[] = {
3325 MockRead(ASYNC
, 0, 1) // EOF
3327 scoped_ptr
<SpdyFrame
> window_update(
3328 spdy_util_
.ConstructSpdyWindowUpdate(
3329 kSessionFlowControlStreamId
,
3330 kSpdySessionInitialWindowSize
+ delta_window_size
));
3331 MockWrite writes
[] = {
3332 CreateMockWrite(*window_update
, 0),
3334 DeterministicSocketData
data(reads
, arraysize(reads
),
3335 writes
, arraysize(writes
));
3336 data
.set_connect_data(connect_data
);
3337 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3339 CreateDeterministicNetworkSession();
3340 base::WeakPtr
<SpdySession
> session
=
3341 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3342 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
3343 session
->flow_control_state());
3345 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3346 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3348 session
->IncreaseRecvWindowSize(delta_window_size
);
3349 EXPECT_EQ(kSpdySessionInitialWindowSize
+ delta_window_size
,
3350 session
->session_recv_window_size_
);
3351 EXPECT_EQ(delta_window_size
, session
->session_unacked_recv_window_bytes_
);
3353 // Should trigger sending a WINDOW_UPDATE frame.
3354 session
->IncreaseRecvWindowSize(kSpdySessionInitialWindowSize
);
3355 EXPECT_EQ(kSpdySessionInitialWindowSize
+ delta_window_size
+
3356 kSpdySessionInitialWindowSize
,
3357 session
->session_recv_window_size_
);
3358 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3362 // DecreaseRecvWindowSize() expects |in_io_loop_| to be true.
3363 session
->in_io_loop_
= true;
3364 session
->DecreaseRecvWindowSize(
3365 kSpdySessionInitialWindowSize
+ delta_window_size
+
3366 kSpdySessionInitialWindowSize
);
3367 session
->in_io_loop_
= false;
3368 EXPECT_EQ(0, session
->session_recv_window_size_
);
3369 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3372 // SpdySession::{Increase,Decrease}SendWindowSize should properly
3373 // adjust the session send window size when the "enable_spdy_31" flag
3375 TEST_P(SpdySessionTest
, AdjustSendWindowSize
) {
3376 if (GetParam() < kProtoSPDY31
)
3379 session_deps_
.host_resolver
->set_synchronous_mode(true);
3381 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3382 MockRead reads
[] = {
3383 MockRead(SYNCHRONOUS
, 0, 0) // EOF
3385 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
3386 data
.set_connect_data(connect_data
);
3387 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
3389 CreateNetworkSession();
3390 base::WeakPtr
<SpdySession
> session
=
3391 CreateFakeSpdySession(spdy_session_pool_
, key_
);
3392 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
3393 session
->flow_control_state());
3395 const int32 delta_window_size
= 100;
3397 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3399 session
->IncreaseSendWindowSize(delta_window_size
);
3400 EXPECT_EQ(kSpdySessionInitialWindowSize
+ delta_window_size
,
3401 session
->session_send_window_size_
);
3403 session
->DecreaseSendWindowSize(delta_window_size
);
3404 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3407 // Incoming data for an inactive stream should not cause the session
3408 // receive window size to decrease, but it should cause the unacked
3409 // bytes to increase.
3410 TEST_P(SpdySessionTest
, SessionFlowControlInactiveStream
) {
3411 if (GetParam() < kProtoSPDY31
)
3414 session_deps_
.host_resolver
->set_synchronous_mode(true);
3416 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3417 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyBodyFrame(1, false));
3418 MockRead reads
[] = {
3419 CreateMockRead(*resp
, 0),
3420 MockRead(ASYNC
, 0, 1) // EOF
3422 DeterministicSocketData
data(reads
, arraysize(reads
), NULL
, 0);
3423 data
.set_connect_data(connect_data
);
3424 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3426 CreateDeterministicNetworkSession();
3427 base::WeakPtr
<SpdySession
> session
=
3428 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3429 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
3430 session
->flow_control_state());
3432 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3433 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3437 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3438 EXPECT_EQ(kUploadDataSize
, session
->session_unacked_recv_window_bytes_
);
3443 // A delegate that drops any received data.
3444 class DropReceivedDataDelegate
: public test::StreamDelegateSendImmediate
{
3446 DropReceivedDataDelegate(const base::WeakPtr
<SpdyStream
>& stream
,
3447 base::StringPiece data
)
3448 : StreamDelegateSendImmediate(stream
, data
) {}
3450 virtual ~DropReceivedDataDelegate() {}
3452 // Drop any received data.
3453 virtual void OnDataReceived(scoped_ptr
<SpdyBuffer
> buffer
) OVERRIDE
{}
3456 // Send data back and forth but use a delegate that drops its received
3457 // data. The receive window should still increase to its original
3458 // value, i.e. we shouldn't "leak" receive window bytes.
3459 TEST_P(SpdySessionTest
, SessionFlowControlNoReceiveLeaks
) {
3460 if (GetParam() < kProtoSPDY31
)
3463 const char kStreamUrl
[] = "http://www.google.com/";
3465 const int32 msg_data_size
= 100;
3466 const std::string
msg_data(msg_data_size
, 'a');
3468 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3470 scoped_ptr
<SpdyFrame
> req(
3471 spdy_util_
.ConstructSpdyPost(
3472 kStreamUrl
, 1, msg_data_size
, MEDIUM
, NULL
, 0));
3473 scoped_ptr
<SpdyFrame
> msg(
3474 spdy_util_
.ConstructSpdyBodyFrame(
3475 1, msg_data
.data(), msg_data_size
, false));
3476 MockWrite writes
[] = {
3477 CreateMockWrite(*req
, 0),
3478 CreateMockWrite(*msg
, 2),
3481 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3482 scoped_ptr
<SpdyFrame
> echo(
3483 spdy_util_
.ConstructSpdyBodyFrame(
3484 1, msg_data
.data(), msg_data_size
, false));
3485 scoped_ptr
<SpdyFrame
> window_update(
3486 spdy_util_
.ConstructSpdyWindowUpdate(
3487 kSessionFlowControlStreamId
, msg_data_size
));
3488 MockRead reads
[] = {
3489 CreateMockRead(*resp
, 1),
3490 CreateMockRead(*echo
, 3),
3491 MockRead(ASYNC
, 0, 4) // EOF
3494 // Create SpdySession and SpdyStream and send the request.
3495 DeterministicSocketData
data(reads
, arraysize(reads
),
3496 writes
, arraysize(writes
));
3497 data
.set_connect_data(connect_data
);
3498 session_deps_
.host_resolver
->set_synchronous_mode(true);
3499 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3501 CreateDeterministicNetworkSession();
3503 base::WeakPtr
<SpdySession
> session
=
3504 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3506 GURL
url(kStreamUrl
);
3507 base::WeakPtr
<SpdyStream
> stream
=
3508 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
3509 session
, url
, MEDIUM
, BoundNetLog());
3510 ASSERT_TRUE(stream
.get() != NULL
);
3511 EXPECT_EQ(0u, stream
->stream_id());
3513 DropReceivedDataDelegate
delegate(stream
, msg_data
);
3514 stream
->SetDelegate(&delegate
);
3516 scoped_ptr
<SpdyHeaderBlock
> headers(
3517 spdy_util_
.ConstructPostHeaderBlock(url
.spec(), msg_data_size
));
3518 EXPECT_EQ(ERR_IO_PENDING
,
3519 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
3520 EXPECT_TRUE(stream
->HasUrlFromHeaders());
3522 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3523 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3527 EXPECT_TRUE(data
.at_write_eof());
3528 EXPECT_TRUE(data
.at_read_eof());
3530 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3531 EXPECT_EQ(msg_data_size
, session
->session_unacked_recv_window_bytes_
);
3534 EXPECT_EQ(NULL
, stream
.get());
3536 EXPECT_EQ(OK
, delegate
.WaitForClose());
3538 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3539 EXPECT_EQ(msg_data_size
, session
->session_unacked_recv_window_bytes_
);
3542 // Send data back and forth but close the stream before its data frame
3543 // can be written to the socket. The send window should then increase
3544 // to its original value, i.e. we shouldn't "leak" send window bytes.
3545 TEST_P(SpdySessionTest
, SessionFlowControlNoSendLeaks
) {
3546 if (GetParam() < kProtoSPDY31
)
3549 const char kStreamUrl
[] = "http://www.google.com/";
3551 const int32 msg_data_size
= 100;
3552 const std::string
msg_data(msg_data_size
, 'a');
3554 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3556 scoped_ptr
<SpdyFrame
> req(
3557 spdy_util_
.ConstructSpdyPost(
3558 kStreamUrl
, 1, msg_data_size
, MEDIUM
, NULL
, 0));
3559 MockWrite writes
[] = {
3560 CreateMockWrite(*req
, 0),
3563 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3564 MockRead reads
[] = {
3565 CreateMockRead(*resp
, 1),
3566 MockRead(ASYNC
, 0, 2) // EOF
3569 // Create SpdySession and SpdyStream and send the request.
3570 DeterministicSocketData
data(reads
, arraysize(reads
),
3571 writes
, arraysize(writes
));
3572 data
.set_connect_data(connect_data
);
3573 session_deps_
.host_resolver
->set_synchronous_mode(true);
3574 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3576 CreateDeterministicNetworkSession();
3578 base::WeakPtr
<SpdySession
> session
=
3579 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3581 GURL
url(kStreamUrl
);
3582 base::WeakPtr
<SpdyStream
> stream
=
3583 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
3584 session
, url
, MEDIUM
, BoundNetLog());
3585 ASSERT_TRUE(stream
.get() != NULL
);
3586 EXPECT_EQ(0u, stream
->stream_id());
3588 test::StreamDelegateSendImmediate
delegate(stream
, msg_data
);
3589 stream
->SetDelegate(&delegate
);
3591 scoped_ptr
<SpdyHeaderBlock
> headers(
3592 spdy_util_
.ConstructPostHeaderBlock(url
.spec(), msg_data_size
));
3593 EXPECT_EQ(ERR_IO_PENDING
,
3594 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
3595 EXPECT_TRUE(stream
->HasUrlFromHeaders());
3597 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3601 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3605 EXPECT_TRUE(data
.at_write_eof());
3606 EXPECT_TRUE(data
.at_read_eof());
3608 EXPECT_EQ(kSpdySessionInitialWindowSize
- msg_data_size
,
3609 session
->session_send_window_size_
);
3611 // Closing the stream should increase the session's send window.
3613 EXPECT_EQ(NULL
, stream
.get());
3615 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3617 EXPECT_EQ(OK
, delegate
.WaitForClose());
3620 // Send data back and forth; the send and receive windows should
3621 // change appropriately.
3622 TEST_P(SpdySessionTest
, SessionFlowControlEndToEnd
) {
3623 if (GetParam() < kProtoSPDY31
)
3626 const char kStreamUrl
[] = "http://www.google.com/";
3628 const int32 msg_data_size
= 100;
3629 const std::string
msg_data(msg_data_size
, 'a');
3631 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3633 scoped_ptr
<SpdyFrame
> req(
3634 spdy_util_
.ConstructSpdyPost(
3635 kStreamUrl
, 1, msg_data_size
, MEDIUM
, NULL
, 0));
3636 scoped_ptr
<SpdyFrame
> msg(
3637 spdy_util_
.ConstructSpdyBodyFrame(
3638 1, msg_data
.data(), msg_data_size
, false));
3639 MockWrite writes
[] = {
3640 CreateMockWrite(*req
, 0),
3641 CreateMockWrite(*msg
, 2),
3644 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3645 scoped_ptr
<SpdyFrame
> echo(
3646 spdy_util_
.ConstructSpdyBodyFrame(
3647 1, msg_data
.data(), msg_data_size
, false));
3648 scoped_ptr
<SpdyFrame
> window_update(
3649 spdy_util_
.ConstructSpdyWindowUpdate(
3650 kSessionFlowControlStreamId
, msg_data_size
));
3651 MockRead reads
[] = {
3652 CreateMockRead(*resp
, 1),
3653 CreateMockRead(*echo
, 3),
3654 CreateMockRead(*window_update
, 4),
3655 MockRead(ASYNC
, 0, 5) // EOF
3658 // Create SpdySession and SpdyStream and send the request.
3659 DeterministicSocketData
data(reads
, arraysize(reads
),
3660 writes
, arraysize(writes
));
3661 data
.set_connect_data(connect_data
);
3662 session_deps_
.host_resolver
->set_synchronous_mode(true);
3663 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3665 CreateDeterministicNetworkSession();
3667 base::WeakPtr
<SpdySession
> session
=
3668 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3670 GURL
url(kStreamUrl
);
3671 base::WeakPtr
<SpdyStream
> stream
=
3672 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
3673 session
, url
, MEDIUM
, BoundNetLog());
3674 ASSERT_TRUE(stream
.get() != NULL
);
3675 EXPECT_EQ(0u, stream
->stream_id());
3677 test::StreamDelegateSendImmediate
delegate(stream
, msg_data
);
3678 stream
->SetDelegate(&delegate
);
3680 scoped_ptr
<SpdyHeaderBlock
> headers(
3681 spdy_util_
.ConstructPostHeaderBlock(url
.spec(), msg_data_size
));
3682 EXPECT_EQ(ERR_IO_PENDING
,
3683 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
3684 EXPECT_TRUE(stream
->HasUrlFromHeaders());
3686 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3687 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3688 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3692 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3693 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3694 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3698 EXPECT_EQ(kSpdySessionInitialWindowSize
- msg_data_size
,
3699 session
->session_send_window_size_
);
3700 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3701 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3705 EXPECT_EQ(kSpdySessionInitialWindowSize
- msg_data_size
,
3706 session
->session_send_window_size_
);
3707 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3708 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3712 EXPECT_EQ(kSpdySessionInitialWindowSize
- msg_data_size
,
3713 session
->session_send_window_size_
);
3714 EXPECT_EQ(kSpdySessionInitialWindowSize
- msg_data_size
,
3715 session
->session_recv_window_size_
);
3716 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3720 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3721 EXPECT_EQ(kSpdySessionInitialWindowSize
- msg_data_size
,
3722 session
->session_recv_window_size_
);
3723 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3725 EXPECT_TRUE(data
.at_write_eof());
3726 EXPECT_TRUE(data
.at_read_eof());
3728 EXPECT_EQ(msg_data
, delegate
.TakeReceivedData());
3730 // Draining the delegate's read queue should increase the session's
3732 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3733 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3734 EXPECT_EQ(msg_data_size
, session
->session_unacked_recv_window_bytes_
);
3737 EXPECT_EQ(NULL
, stream
.get());
3739 EXPECT_EQ(OK
, delegate
.WaitForClose());
3741 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3742 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3743 EXPECT_EQ(msg_data_size
, session
->session_unacked_recv_window_bytes_
);
3746 // Given a stall function and an unstall function, runs a test to make
3747 // sure that a stream resumes after unstall.
3748 void SpdySessionTest::RunResumeAfterUnstallTest(
3749 const base::Callback
<void(SpdySession
*, SpdyStream
*)>& stall_function
,
3750 const base::Callback
<void(SpdySession
*, SpdyStream
*, int32
)>&
3752 const char kStreamUrl
[] = "http://www.google.com/";
3753 GURL
url(kStreamUrl
);
3755 session_deps_
.host_resolver
->set_synchronous_mode(true);
3757 scoped_ptr
<SpdyFrame
> req(
3758 spdy_util_
.ConstructSpdyPost(
3759 kStreamUrl
, 1, kBodyDataSize
, LOWEST
, NULL
, 0));
3760 scoped_ptr
<SpdyFrame
> body(
3761 spdy_util_
.ConstructSpdyBodyFrame(1, kBodyData
, kBodyDataSize
, true));
3762 MockWrite writes
[] = {
3763 CreateMockWrite(*req
, 0),
3764 CreateMockWrite(*body
, 1),
3767 scoped_ptr
<SpdyFrame
> resp(
3768 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3769 scoped_ptr
<SpdyFrame
> echo(
3770 spdy_util_
.ConstructSpdyBodyFrame(1, kBodyData
, kBodyDataSize
, false));
3771 MockRead reads
[] = {
3772 CreateMockRead(*resp
, 2),
3773 MockRead(ASYNC
, 0, 0, 3), // EOF
3776 DeterministicSocketData
data(reads
, arraysize(reads
),
3777 writes
, arraysize(writes
));
3778 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3779 data
.set_connect_data(connect_data
);
3781 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3783 CreateDeterministicNetworkSession();
3784 base::WeakPtr
<SpdySession
> session
=
3785 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3786 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
3787 session
->flow_control_state());
3789 base::WeakPtr
<SpdyStream
> stream
=
3790 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
3791 session
, url
, LOWEST
, BoundNetLog());
3792 ASSERT_TRUE(stream
.get() != NULL
);
3794 test::StreamDelegateWithBody
delegate(stream
, kBodyDataStringPiece
);
3795 stream
->SetDelegate(&delegate
);
3797 EXPECT_FALSE(stream
->HasUrlFromHeaders());
3798 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
3800 scoped_ptr
<SpdyHeaderBlock
> headers(
3801 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
3802 EXPECT_EQ(ERR_IO_PENDING
,
3803 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
3804 EXPECT_TRUE(stream
->HasUrlFromHeaders());
3805 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
3807 stall_function
.Run(session
.get(), stream
.get());
3811 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
3813 unstall_function
.Run(session
.get(), stream
.get(), kBodyDataSize
);
3815 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
3819 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
3821 EXPECT_TRUE(delegate
.send_headers_completed());
3822 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
3823 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
3824 EXPECT_TRUE(data
.at_write_eof());
3827 // Run the resume-after-unstall test with all possible stall and
3828 // unstall sequences.
3830 TEST_P(SpdySessionTest
, ResumeAfterUnstallSession
) {
3831 if (GetParam() < kProtoSPDY31
)
3834 RunResumeAfterUnstallTest(
3835 base::Bind(&SpdySessionTest::StallSessionOnly
,
3836 base::Unretained(this)),
3837 base::Bind(&SpdySessionTest::UnstallSessionOnly
,
3838 base::Unretained(this)));
3842 // SpdyStreamTest.ResumeAfterSendWindowSizeIncrease.
3843 TEST_P(SpdySessionTest
, ResumeAfterUnstallStream
) {
3844 if (GetParam() < kProtoSPDY31
)
3847 RunResumeAfterUnstallTest(
3848 base::Bind(&SpdySessionTest::StallStreamOnly
,
3849 base::Unretained(this)),
3850 base::Bind(&SpdySessionTest::UnstallStreamOnly
,
3851 base::Unretained(this)));
3854 TEST_P(SpdySessionTest
, StallSessionStreamResumeAfterUnstallSessionStream
) {
3855 if (GetParam() < kProtoSPDY31
)
3858 RunResumeAfterUnstallTest(
3859 base::Bind(&SpdySessionTest::StallSessionStream
,
3860 base::Unretained(this)),
3861 base::Bind(&SpdySessionTest::UnstallSessionStream
,
3862 base::Unretained(this)));
3865 TEST_P(SpdySessionTest
, StallStreamSessionResumeAfterUnstallSessionStream
) {
3866 if (GetParam() < kProtoSPDY31
)
3869 RunResumeAfterUnstallTest(
3870 base::Bind(&SpdySessionTest::StallStreamSession
,
3871 base::Unretained(this)),
3872 base::Bind(&SpdySessionTest::UnstallSessionStream
,
3873 base::Unretained(this)));
3876 TEST_P(SpdySessionTest
, StallStreamSessionResumeAfterUnstallStreamSession
) {
3877 if (GetParam() < kProtoSPDY31
)
3880 RunResumeAfterUnstallTest(
3881 base::Bind(&SpdySessionTest::StallStreamSession
,
3882 base::Unretained(this)),
3883 base::Bind(&SpdySessionTest::UnstallStreamSession
,
3884 base::Unretained(this)));
3887 TEST_P(SpdySessionTest
, StallSessionStreamResumeAfterUnstallStreamSession
) {
3888 if (GetParam() < kProtoSPDY31
)
3891 RunResumeAfterUnstallTest(
3892 base::Bind(&SpdySessionTest::StallSessionStream
,
3893 base::Unretained(this)),
3894 base::Bind(&SpdySessionTest::UnstallStreamSession
,
3895 base::Unretained(this)));
3898 // Cause a stall by reducing the flow control send window to 0. The
3899 // streams should resume in priority order when that window is then
3901 TEST_P(SpdySessionTest
, ResumeByPriorityAfterSendWindowSizeIncrease
) {
3902 if (GetParam() < kProtoSPDY31
)
3905 const char kStreamUrl
[] = "http://www.google.com/";
3906 GURL
url(kStreamUrl
);
3908 session_deps_
.host_resolver
->set_synchronous_mode(true);
3910 scoped_ptr
<SpdyFrame
> req1(
3911 spdy_util_
.ConstructSpdyPost(
3912 kStreamUrl
, 1, kBodyDataSize
, LOWEST
, NULL
, 0));
3913 scoped_ptr
<SpdyFrame
> req2(
3914 spdy_util_
.ConstructSpdyPost(
3915 kStreamUrl
, 3, kBodyDataSize
, MEDIUM
, NULL
, 0));
3916 scoped_ptr
<SpdyFrame
> body1(
3917 spdy_util_
.ConstructSpdyBodyFrame(1, kBodyData
, kBodyDataSize
, true));
3918 scoped_ptr
<SpdyFrame
> body2(
3919 spdy_util_
.ConstructSpdyBodyFrame(3, kBodyData
, kBodyDataSize
, true));
3920 MockWrite writes
[] = {
3921 CreateMockWrite(*req1
, 0),
3922 CreateMockWrite(*req2
, 1),
3923 CreateMockWrite(*body2
, 2),
3924 CreateMockWrite(*body1
, 3),
3927 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3928 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
3929 MockRead reads
[] = {
3930 CreateMockRead(*resp1
, 4),
3931 CreateMockRead(*resp2
, 5),
3932 MockRead(ASYNC
, 0, 0, 6), // EOF
3935 DeterministicSocketData
data(reads
, arraysize(reads
),
3936 writes
, arraysize(writes
));
3937 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3938 data
.set_connect_data(connect_data
);
3940 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3942 CreateDeterministicNetworkSession();
3943 base::WeakPtr
<SpdySession
> session
=
3944 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3945 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
3946 session
->flow_control_state());
3948 base::WeakPtr
<SpdyStream
> stream1
=
3949 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
3950 session
, url
, LOWEST
, BoundNetLog());
3951 ASSERT_TRUE(stream1
.get() != NULL
);
3953 test::StreamDelegateWithBody
delegate1(stream1
, kBodyDataStringPiece
);
3954 stream1
->SetDelegate(&delegate1
);
3956 EXPECT_FALSE(stream1
->HasUrlFromHeaders());
3958 base::WeakPtr
<SpdyStream
> stream2
=
3959 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
3960 session
, url
, MEDIUM
, BoundNetLog());
3961 ASSERT_TRUE(stream2
.get() != NULL
);
3963 test::StreamDelegateWithBody
delegate2(stream2
, kBodyDataStringPiece
);
3964 stream2
->SetDelegate(&delegate2
);
3966 EXPECT_FALSE(stream2
->HasUrlFromHeaders());
3968 EXPECT_FALSE(stream1
->send_stalled_by_flow_control());
3969 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
3971 StallSessionSend(session
.get());
3973 scoped_ptr
<SpdyHeaderBlock
> headers1(
3974 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
3975 EXPECT_EQ(ERR_IO_PENDING
,
3976 stream1
->SendRequestHeaders(headers1
.Pass(), MORE_DATA_TO_SEND
));
3977 EXPECT_TRUE(stream1
->HasUrlFromHeaders());
3978 EXPECT_EQ(kStreamUrl
, stream1
->GetUrlFromHeaders().spec());
3981 EXPECT_EQ(1u, stream1
->stream_id());
3982 EXPECT_TRUE(stream1
->send_stalled_by_flow_control());
3984 scoped_ptr
<SpdyHeaderBlock
> headers2(
3985 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
3986 EXPECT_EQ(ERR_IO_PENDING
,
3987 stream2
->SendRequestHeaders(headers2
.Pass(), MORE_DATA_TO_SEND
));
3988 EXPECT_TRUE(stream2
->HasUrlFromHeaders());
3989 EXPECT_EQ(kStreamUrl
, stream2
->GetUrlFromHeaders().spec());
3992 EXPECT_EQ(3u, stream2
->stream_id());
3993 EXPECT_TRUE(stream2
->send_stalled_by_flow_control());
3995 // This should unstall only stream2.
3996 UnstallSessionSend(session
.get(), kBodyDataSize
);
3998 EXPECT_TRUE(stream1
->send_stalled_by_flow_control());
3999 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4003 EXPECT_TRUE(stream1
->send_stalled_by_flow_control());
4004 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4006 // This should then unstall stream1.
4007 UnstallSessionSend(session
.get(), kBodyDataSize
);
4009 EXPECT_FALSE(stream1
->send_stalled_by_flow_control());
4010 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4014 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate1
.WaitForClose());
4015 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate2
.WaitForClose());
4017 EXPECT_TRUE(delegate1
.send_headers_completed());
4018 EXPECT_EQ("200", delegate1
.GetResponseHeaderValue(":status"));
4019 EXPECT_EQ(std::string(), delegate1
.TakeReceivedData());
4021 EXPECT_TRUE(delegate2
.send_headers_completed());
4022 EXPECT_EQ("200", delegate2
.GetResponseHeaderValue(":status"));
4023 EXPECT_EQ(std::string(), delegate2
.TakeReceivedData());
4025 EXPECT_TRUE(data
.at_write_eof());
4028 // Delegate that closes a given stream after sending its body.
4029 class StreamClosingDelegate
: public test::StreamDelegateWithBody
{
4031 StreamClosingDelegate(const base::WeakPtr
<SpdyStream
>& stream
,
4032 base::StringPiece data
)
4033 : StreamDelegateWithBody(stream
, data
) {}
4035 virtual ~StreamClosingDelegate() {}
4037 void set_stream_to_close(const base::WeakPtr
<SpdyStream
>& stream_to_close
) {
4038 stream_to_close_
= stream_to_close
;
4041 virtual void OnDataSent() OVERRIDE
{
4042 test::StreamDelegateWithBody::OnDataSent();
4043 if (stream_to_close_
.get()) {
4044 stream_to_close_
->Close();
4045 EXPECT_EQ(NULL
, stream_to_close_
.get());
4050 base::WeakPtr
<SpdyStream
> stream_to_close_
;
4053 // Cause a stall by reducing the flow control send window to
4054 // 0. Unstalling the session should properly handle deleted streams.
4055 TEST_P(SpdySessionTest
, SendWindowSizeIncreaseWithDeletedStreams
) {
4056 if (GetParam() < kProtoSPDY31
)
4059 const char kStreamUrl
[] = "http://www.google.com/";
4060 GURL
url(kStreamUrl
);
4062 session_deps_
.host_resolver
->set_synchronous_mode(true);
4064 scoped_ptr
<SpdyFrame
> req1(
4065 spdy_util_
.ConstructSpdyPost(
4066 kStreamUrl
, 1, kBodyDataSize
, LOWEST
, NULL
, 0));
4067 scoped_ptr
<SpdyFrame
> req2(
4068 spdy_util_
.ConstructSpdyPost(
4069 kStreamUrl
, 3, kBodyDataSize
, LOWEST
, NULL
, 0));
4070 scoped_ptr
<SpdyFrame
> req3(
4071 spdy_util_
.ConstructSpdyPost(
4072 kStreamUrl
, 5, kBodyDataSize
, LOWEST
, NULL
, 0));
4073 scoped_ptr
<SpdyFrame
> body2(
4074 spdy_util_
.ConstructSpdyBodyFrame(3, kBodyData
, kBodyDataSize
, true));
4075 MockWrite writes
[] = {
4076 CreateMockWrite(*req1
, 0),
4077 CreateMockWrite(*req2
, 1),
4078 CreateMockWrite(*req3
, 2),
4079 CreateMockWrite(*body2
, 3),
4082 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
4083 MockRead reads
[] = {
4084 CreateMockRead(*resp2
, 4),
4085 MockRead(ASYNC
, 0, 0, 5), // EOF
4088 DeterministicSocketData
data(reads
, arraysize(reads
),
4089 writes
, arraysize(writes
));
4090 MockConnect
connect_data(SYNCHRONOUS
, OK
);
4091 data
.set_connect_data(connect_data
);
4093 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
4095 CreateDeterministicNetworkSession();
4096 base::WeakPtr
<SpdySession
> session
=
4097 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
4098 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
4099 session
->flow_control_state());
4101 base::WeakPtr
<SpdyStream
> stream1
=
4102 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
4103 session
, url
, LOWEST
, BoundNetLog());
4104 ASSERT_TRUE(stream1
.get() != NULL
);
4106 test::StreamDelegateWithBody
delegate1(stream1
, kBodyDataStringPiece
);
4107 stream1
->SetDelegate(&delegate1
);
4109 EXPECT_FALSE(stream1
->HasUrlFromHeaders());
4111 base::WeakPtr
<SpdyStream
> stream2
=
4112 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
4113 session
, url
, LOWEST
, BoundNetLog());
4114 ASSERT_TRUE(stream2
.get() != NULL
);
4116 StreamClosingDelegate
delegate2(stream2
, kBodyDataStringPiece
);
4117 stream2
->SetDelegate(&delegate2
);
4119 EXPECT_FALSE(stream2
->HasUrlFromHeaders());
4121 base::WeakPtr
<SpdyStream
> stream3
=
4122 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
4123 session
, url
, LOWEST
, BoundNetLog());
4124 ASSERT_TRUE(stream3
.get() != NULL
);
4126 test::StreamDelegateWithBody
delegate3(stream3
, kBodyDataStringPiece
);
4127 stream3
->SetDelegate(&delegate3
);
4129 EXPECT_FALSE(stream3
->HasUrlFromHeaders());
4131 EXPECT_FALSE(stream1
->send_stalled_by_flow_control());
4132 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4133 EXPECT_FALSE(stream3
->send_stalled_by_flow_control());
4135 StallSessionSend(session
.get());
4137 scoped_ptr
<SpdyHeaderBlock
> headers1(
4138 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
4139 EXPECT_EQ(ERR_IO_PENDING
,
4140 stream1
->SendRequestHeaders(headers1
.Pass(), MORE_DATA_TO_SEND
));
4141 EXPECT_TRUE(stream1
->HasUrlFromHeaders());
4142 EXPECT_EQ(kStreamUrl
, stream1
->GetUrlFromHeaders().spec());
4145 EXPECT_EQ(1u, stream1
->stream_id());
4146 EXPECT_TRUE(stream1
->send_stalled_by_flow_control());
4148 scoped_ptr
<SpdyHeaderBlock
> headers2(
4149 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
4150 EXPECT_EQ(ERR_IO_PENDING
,
4151 stream2
->SendRequestHeaders(headers2
.Pass(), MORE_DATA_TO_SEND
));
4152 EXPECT_TRUE(stream2
->HasUrlFromHeaders());
4153 EXPECT_EQ(kStreamUrl
, stream2
->GetUrlFromHeaders().spec());
4156 EXPECT_EQ(3u, stream2
->stream_id());
4157 EXPECT_TRUE(stream2
->send_stalled_by_flow_control());
4159 scoped_ptr
<SpdyHeaderBlock
> headers3(
4160 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
4161 EXPECT_EQ(ERR_IO_PENDING
,
4162 stream3
->SendRequestHeaders(headers3
.Pass(), MORE_DATA_TO_SEND
));
4163 EXPECT_TRUE(stream3
->HasUrlFromHeaders());
4164 EXPECT_EQ(kStreamUrl
, stream3
->GetUrlFromHeaders().spec());
4167 EXPECT_EQ(5u, stream3
->stream_id());
4168 EXPECT_TRUE(stream3
->send_stalled_by_flow_control());
4170 SpdyStreamId stream_id1
= stream1
->stream_id();
4171 SpdyStreamId stream_id2
= stream2
->stream_id();
4172 SpdyStreamId stream_id3
= stream3
->stream_id();
4174 // Close stream1 preemptively.
4175 session
->CloseActiveStream(stream_id1
, ERR_CONNECTION_CLOSED
);
4176 EXPECT_EQ(NULL
, stream1
.get());
4178 EXPECT_FALSE(session
->IsStreamActive(stream_id1
));
4179 EXPECT_TRUE(session
->IsStreamActive(stream_id2
));
4180 EXPECT_TRUE(session
->IsStreamActive(stream_id3
));
4182 // Unstall stream2, which should then close stream3.
4183 delegate2
.set_stream_to_close(stream3
);
4184 UnstallSessionSend(session
.get(), kBodyDataSize
);
4187 EXPECT_EQ(NULL
, stream3
.get());
4189 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4190 EXPECT_FALSE(session
->IsStreamActive(stream_id1
));
4191 EXPECT_TRUE(session
->IsStreamActive(stream_id2
));
4192 EXPECT_FALSE(session
->IsStreamActive(stream_id3
));
4195 EXPECT_EQ(NULL
, stream2
.get());
4197 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate1
.WaitForClose());
4198 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate2
.WaitForClose());
4199 EXPECT_EQ(OK
, delegate3
.WaitForClose());
4201 EXPECT_TRUE(delegate1
.send_headers_completed());
4202 EXPECT_EQ(std::string(), delegate1
.TakeReceivedData());
4204 EXPECT_TRUE(delegate2
.send_headers_completed());
4205 EXPECT_EQ("200", delegate2
.GetResponseHeaderValue(":status"));
4206 EXPECT_EQ(std::string(), delegate2
.TakeReceivedData());
4208 EXPECT_TRUE(delegate3
.send_headers_completed());
4209 EXPECT_EQ(std::string(), delegate3
.TakeReceivedData());
4211 EXPECT_TRUE(data
.at_write_eof());
4214 // Cause a stall by reducing the flow control send window to
4215 // 0. Unstalling the session should properly handle the session itself
4217 TEST_P(SpdySessionTest
, SendWindowSizeIncreaseWithDeletedSession
) {
4218 if (GetParam() < kProtoSPDY31
)
4221 const char kStreamUrl
[] = "http://www.google.com/";
4222 GURL
url(kStreamUrl
);
4224 session_deps_
.host_resolver
->set_synchronous_mode(true);
4226 scoped_ptr
<SpdyFrame
> req1(
4227 spdy_util_
.ConstructSpdyPost(
4228 kStreamUrl
, 1, kBodyDataSize
, LOWEST
, NULL
, 0));
4229 scoped_ptr
<SpdyFrame
> req2(
4230 spdy_util_
.ConstructSpdyPost(
4231 kStreamUrl
, 3, kBodyDataSize
, LOWEST
, NULL
, 0));
4232 scoped_ptr
<SpdyFrame
> body1(
4233 spdy_util_
.ConstructSpdyBodyFrame(1, kBodyData
, kBodyDataSize
, false));
4234 MockWrite writes
[] = {
4235 CreateMockWrite(*req1
, 0),
4236 CreateMockWrite(*req2
, 1),
4239 MockRead reads
[] = {
4240 MockRead(ASYNC
, 0, 0, 2), // EOF
4243 DeterministicSocketData
data(reads
, arraysize(reads
),
4244 writes
, arraysize(writes
));
4245 MockConnect
connect_data(SYNCHRONOUS
, OK
);
4246 data
.set_connect_data(connect_data
);
4248 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
4250 CreateDeterministicNetworkSession();
4251 base::WeakPtr
<SpdySession
> session
=
4252 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
4253 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
4254 session
->flow_control_state());
4256 base::WeakPtr
<SpdyStream
> stream1
=
4257 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
4258 session
, url
, LOWEST
, BoundNetLog());
4259 ASSERT_TRUE(stream1
.get() != NULL
);
4261 test::StreamDelegateWithBody
delegate1(stream1
, kBodyDataStringPiece
);
4262 stream1
->SetDelegate(&delegate1
);
4264 EXPECT_FALSE(stream1
->HasUrlFromHeaders());
4266 base::WeakPtr
<SpdyStream
> stream2
=
4267 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
4268 session
, url
, LOWEST
, BoundNetLog());
4269 ASSERT_TRUE(stream2
.get() != NULL
);
4271 test::StreamDelegateWithBody
delegate2(stream2
, kBodyDataStringPiece
);
4272 stream2
->SetDelegate(&delegate2
);
4274 EXPECT_FALSE(stream2
->HasUrlFromHeaders());
4276 EXPECT_FALSE(stream1
->send_stalled_by_flow_control());
4277 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4279 StallSessionSend(session
.get());
4281 scoped_ptr
<SpdyHeaderBlock
> headers1(
4282 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
4283 EXPECT_EQ(ERR_IO_PENDING
,
4284 stream1
->SendRequestHeaders(headers1
.Pass(), MORE_DATA_TO_SEND
));
4285 EXPECT_TRUE(stream1
->HasUrlFromHeaders());
4286 EXPECT_EQ(kStreamUrl
, stream1
->GetUrlFromHeaders().spec());
4289 EXPECT_EQ(1u, stream1
->stream_id());
4290 EXPECT_TRUE(stream1
->send_stalled_by_flow_control());
4292 scoped_ptr
<SpdyHeaderBlock
> headers2(
4293 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
4294 EXPECT_EQ(ERR_IO_PENDING
,
4295 stream2
->SendRequestHeaders(headers2
.Pass(), MORE_DATA_TO_SEND
));
4296 EXPECT_TRUE(stream2
->HasUrlFromHeaders());
4297 EXPECT_EQ(kStreamUrl
, stream2
->GetUrlFromHeaders().spec());
4300 EXPECT_EQ(3u, stream2
->stream_id());
4301 EXPECT_TRUE(stream2
->send_stalled_by_flow_control());
4303 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
4306 UnstallSessionSend(session
.get(), kBodyDataSize
);
4308 // Close the session (since we can't do it from within the delegate
4309 // method, since it's in the stream's loop).
4310 session
->CloseSessionOnError(ERR_CONNECTION_CLOSED
, "Closing session");
4311 EXPECT_TRUE(session
== NULL
);
4313 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
4315 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate1
.WaitForClose());
4316 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate2
.WaitForClose());
4318 EXPECT_TRUE(delegate1
.send_headers_completed());
4319 EXPECT_EQ(std::string(), delegate1
.TakeReceivedData());
4321 EXPECT_TRUE(delegate2
.send_headers_completed());
4322 EXPECT_EQ(std::string(), delegate2
.TakeReceivedData());
4324 EXPECT_TRUE(data
.at_write_eof());
4327 TEST(MapFramerErrorToProtocolError
, MapsValues
) {
4328 CHECK_EQ(SPDY_ERROR_INVALID_CONTROL_FRAME
,
4329 MapFramerErrorToProtocolError(
4330 SpdyFramer::SPDY_INVALID_CONTROL_FRAME
));
4331 CHECK_EQ(SPDY_ERROR_INVALID_DATA_FRAME_FLAGS
,
4332 MapFramerErrorToProtocolError(
4333 SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS
));
4334 CHECK_EQ(SPDY_ERROR_GOAWAY_FRAME_CORRUPT
,
4335 MapFramerErrorToProtocolError(
4336 SpdyFramer::SPDY_GOAWAY_FRAME_CORRUPT
));
4337 CHECK_EQ(SPDY_ERROR_UNEXPECTED_FRAME
,
4338 MapFramerErrorToProtocolError(
4339 SpdyFramer::SPDY_UNEXPECTED_FRAME
));
4342 TEST(MapRstStreamStatusToProtocolError
, MapsValues
) {
4343 CHECK_EQ(STATUS_CODE_PROTOCOL_ERROR
,
4344 MapRstStreamStatusToProtocolError(
4345 RST_STREAM_PROTOCOL_ERROR
));
4346 CHECK_EQ(STATUS_CODE_FRAME_SIZE_ERROR
,
4347 MapRstStreamStatusToProtocolError(
4348 RST_STREAM_FRAME_SIZE_ERROR
));
4349 CHECK_EQ(STATUS_CODE_ENHANCE_YOUR_CALM
,
4350 MapRstStreamStatusToProtocolError(
4351 RST_STREAM_ENHANCE_YOUR_CALM
));