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_CONNECTION_CLOSED
);
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 close.
286 TEST_P(SpdySessionTest
, GoAwayWithNoActiveStreams
) {
287 session_deps_
.host_resolver
->set_synchronous_mode(true);
289 MockConnect
connect_data(SYNCHRONOUS
, OK
);
290 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
292 CreateMockRead(*goaway
, 0),
294 DeterministicSocketData
data(reads
, arraysize(reads
), NULL
, 0);
295 data
.set_connect_data(connect_data
);
296 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
298 CreateDeterministicNetworkSession();
300 base::WeakPtr
<SpdySession
> session
=
301 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
303 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
305 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
307 // Read and process the GOAWAY frame.
309 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
310 base::RunLoop().RunUntilIdle();
311 EXPECT_TRUE(session
== NULL
);
314 // A session receiving a GOAWAY frame immediately with no active
315 // streams should then close.
316 TEST_P(SpdySessionTest
, GoAwayImmediatelyWithNoActiveStreams
) {
317 session_deps_
.host_resolver
->set_synchronous_mode(true);
319 MockConnect
connect_data(SYNCHRONOUS
, OK
);
320 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
322 CreateMockRead(*goaway
, 0, SYNCHRONOUS
),
324 DeterministicSocketData
data(reads
, arraysize(reads
), NULL
, 0);
325 data
.set_connect_data(connect_data
);
326 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
328 CreateDeterministicNetworkSession();
332 base::WeakPtr
<SpdySession
> session
=
333 TryCreateInsecureSpdySessionExpectingFailure(
334 http_session_
, key_
, ERR_CONNECTION_CLOSED
, BoundNetLog());
335 base::RunLoop().RunUntilIdle();
337 EXPECT_FALSE(session
);
338 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
341 // A session receiving a GOAWAY frame with active streams should close
342 // when the last active stream is closed.
343 TEST_P(SpdySessionTest
, GoAwayWithActiveStreams
) {
344 session_deps_
.host_resolver
->set_synchronous_mode(true);
346 MockConnect
connect_data(SYNCHRONOUS
, OK
);
347 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
349 CreateMockRead(*goaway
, 2),
350 MockRead(ASYNC
, 0, 3) // EOF
352 scoped_ptr
<SpdyFrame
> req1(
353 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
354 scoped_ptr
<SpdyFrame
> req2(
355 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, MEDIUM
, true));
356 MockWrite writes
[] = {
357 CreateMockWrite(*req1
, 0),
358 CreateMockWrite(*req2
, 1),
360 DeterministicSocketData
data(reads
, arraysize(reads
),
361 writes
, arraysize(writes
));
362 data
.set_connect_data(connect_data
);
363 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
365 CreateDeterministicNetworkSession();
367 base::WeakPtr
<SpdySession
> session
=
368 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
370 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
372 GURL
url(kDefaultURL
);
373 base::WeakPtr
<SpdyStream
> spdy_stream1
=
374 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
375 session
, url
, MEDIUM
, BoundNetLog());
376 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
377 spdy_stream1
->SetDelegate(&delegate1
);
379 base::WeakPtr
<SpdyStream
> spdy_stream2
=
380 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
381 session
, url
, MEDIUM
, BoundNetLog());
382 test::StreamDelegateDoNothing
delegate2(spdy_stream2
);
383 spdy_stream2
->SetDelegate(&delegate2
);
385 scoped_ptr
<SpdyHeaderBlock
> headers(
386 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
387 scoped_ptr
<SpdyHeaderBlock
> headers2(new SpdyHeaderBlock(*headers
));
389 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
390 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
391 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
392 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
396 EXPECT_EQ(1u, spdy_stream1
->stream_id());
397 EXPECT_EQ(3u, spdy_stream2
->stream_id());
399 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
401 // Read and process the GOAWAY frame.
404 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
406 EXPECT_FALSE(session
->IsStreamActive(3));
407 EXPECT_EQ(NULL
, spdy_stream2
.get());
408 EXPECT_TRUE(session
->IsStreamActive(1));
410 EXPECT_TRUE(session
->IsGoingAway());
412 // Should close the session.
413 spdy_stream1
->Close();
414 EXPECT_EQ(NULL
, spdy_stream1
.get());
416 base::MessageLoop::current()->RunUntilIdle();
417 EXPECT_TRUE(session
== NULL
);
420 // Have a session receive two GOAWAY frames, with the last one causing
421 // the last active stream to be closed. The session should then be
422 // closed after the second GOAWAY frame.
423 TEST_P(SpdySessionTest
, GoAwayTwice
) {
424 session_deps_
.host_resolver
->set_synchronous_mode(true);
426 MockConnect
connect_data(SYNCHRONOUS
, OK
);
427 scoped_ptr
<SpdyFrame
> goaway1(spdy_util_
.ConstructSpdyGoAway(1));
428 scoped_ptr
<SpdyFrame
> goaway2(spdy_util_
.ConstructSpdyGoAway(0));
430 CreateMockRead(*goaway1
, 2),
431 CreateMockRead(*goaway2
, 3),
432 MockRead(ASYNC
, 0, 4) // EOF
434 scoped_ptr
<SpdyFrame
> req1(
435 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
436 scoped_ptr
<SpdyFrame
> req2(
437 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, MEDIUM
, true));
438 MockWrite writes
[] = {
439 CreateMockWrite(*req1
, 0),
440 CreateMockWrite(*req2
, 1),
442 DeterministicSocketData
data(reads
, arraysize(reads
),
443 writes
, arraysize(writes
));
444 data
.set_connect_data(connect_data
);
445 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
447 CreateDeterministicNetworkSession();
449 base::WeakPtr
<SpdySession
> session
=
450 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
452 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
454 GURL
url(kDefaultURL
);
455 base::WeakPtr
<SpdyStream
> spdy_stream1
=
456 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
457 session
, url
, MEDIUM
, BoundNetLog());
458 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
459 spdy_stream1
->SetDelegate(&delegate1
);
461 base::WeakPtr
<SpdyStream
> spdy_stream2
=
462 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
463 session
, url
, MEDIUM
, BoundNetLog());
464 test::StreamDelegateDoNothing
delegate2(spdy_stream2
);
465 spdy_stream2
->SetDelegate(&delegate2
);
467 scoped_ptr
<SpdyHeaderBlock
> headers(
468 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
469 scoped_ptr
<SpdyHeaderBlock
> headers2(new SpdyHeaderBlock(*headers
));
471 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
472 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
473 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
474 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
478 EXPECT_EQ(1u, spdy_stream1
->stream_id());
479 EXPECT_EQ(3u, spdy_stream2
->stream_id());
481 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
483 // Read and process the first GOAWAY frame.
486 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
488 EXPECT_FALSE(session
->IsStreamActive(3));
489 EXPECT_EQ(NULL
, spdy_stream2
.get());
490 EXPECT_TRUE(session
->IsStreamActive(1));
491 EXPECT_TRUE(session
->IsGoingAway());
493 // Read and process the second GOAWAY frame, which should close the
496 base::MessageLoop::current()->RunUntilIdle();
497 EXPECT_TRUE(session
== NULL
);
500 // Have a session with active streams receive a GOAWAY frame and then
501 // close it. It should handle the close properly (i.e., not try to
502 // make itself unavailable in its pool twice).
503 TEST_P(SpdySessionTest
, GoAwayWithActiveStreamsThenClose
) {
504 session_deps_
.host_resolver
->set_synchronous_mode(true);
506 MockConnect
connect_data(SYNCHRONOUS
, OK
);
507 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
509 CreateMockRead(*goaway
, 2),
510 MockRead(ASYNC
, 0, 3) // EOF
512 scoped_ptr
<SpdyFrame
> req1(
513 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
514 scoped_ptr
<SpdyFrame
> req2(
515 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, MEDIUM
, true));
516 MockWrite writes
[] = {
517 CreateMockWrite(*req1
, 0),
518 CreateMockWrite(*req2
, 1),
520 DeterministicSocketData
data(reads
, arraysize(reads
),
521 writes
, arraysize(writes
));
522 data
.set_connect_data(connect_data
);
523 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
525 CreateDeterministicNetworkSession();
527 base::WeakPtr
<SpdySession
> session
=
528 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
530 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
532 GURL
url(kDefaultURL
);
533 base::WeakPtr
<SpdyStream
> spdy_stream1
=
534 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
535 session
, url
, MEDIUM
, BoundNetLog());
536 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
537 spdy_stream1
->SetDelegate(&delegate1
);
539 base::WeakPtr
<SpdyStream
> spdy_stream2
=
540 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
541 session
, url
, MEDIUM
, BoundNetLog());
542 test::StreamDelegateDoNothing
delegate2(spdy_stream2
);
543 spdy_stream2
->SetDelegate(&delegate2
);
545 scoped_ptr
<SpdyHeaderBlock
> headers(
546 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
547 scoped_ptr
<SpdyHeaderBlock
> headers2(new SpdyHeaderBlock(*headers
));
549 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
550 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
551 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
552 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
556 EXPECT_EQ(1u, spdy_stream1
->stream_id());
557 EXPECT_EQ(3u, spdy_stream2
->stream_id());
559 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
561 // Read and process the GOAWAY frame.
564 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
566 EXPECT_FALSE(session
->IsStreamActive(3));
567 EXPECT_EQ(NULL
, spdy_stream2
.get());
568 EXPECT_TRUE(session
->IsStreamActive(1));
569 EXPECT_TRUE(session
->IsGoingAway());
571 session
->CloseSessionOnError(ERR_ABORTED
, "Aborting session");
572 EXPECT_EQ(NULL
, spdy_stream1
.get());
574 base::MessageLoop::current()->RunUntilIdle();
575 EXPECT_TRUE(session
== NULL
);
578 // Process a joint read buffer which causes the session to begin draining, and
579 // then processes a GOAWAY. The session should gracefully drain. Regression test
580 // for crbug.com/379469
581 TEST_P(SpdySessionTest
, GoAwayWhileDraining
) {
582 session_deps_
.host_resolver
->set_synchronous_mode(true);
584 scoped_ptr
<SpdyFrame
> req(
585 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
586 MockWrite writes
[] = {
587 CreateMockWrite(*req
, 0),
590 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
591 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
592 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
593 size_t joint_size
= goaway
->size() * 2 + body
->size();
595 // Compose interleaved |goaway| and |body| frames into a single read.
596 scoped_ptr
<char[]> buffer(new char[joint_size
]);
599 memcpy(&buffer
[out
], goaway
->data(), goaway
->size());
600 out
+= goaway
->size();
601 memcpy(&buffer
[out
], body
->data(), body
->size());
603 memcpy(&buffer
[out
], goaway
->data(), goaway
->size());
604 out
+= goaway
->size();
605 ASSERT_EQ(out
, joint_size
);
607 SpdyFrame
joint_frames(buffer
.get(), joint_size
, false);
610 CreateMockRead(*resp
, 1), CreateMockRead(joint_frames
, 2),
611 MockRead(ASYNC
, 0, 3) // EOF
614 MockConnect
connect_data(SYNCHRONOUS
, OK
);
615 DeterministicSocketData
data(
616 reads
, arraysize(reads
), writes
, arraysize(writes
));
617 data
.set_connect_data(connect_data
);
618 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
620 CreateDeterministicNetworkSession();
621 base::WeakPtr
<SpdySession
> session
=
622 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
624 GURL
url(kDefaultURL
);
625 base::WeakPtr
<SpdyStream
> spdy_stream
= CreateStreamSynchronously(
626 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
627 test::StreamDelegateDoNothing
delegate(spdy_stream
);
628 spdy_stream
->SetDelegate(&delegate
);
630 scoped_ptr
<SpdyHeaderBlock
> headers(
631 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
632 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
633 EXPECT_TRUE(spdy_stream
->HasUrlFromHeaders());
636 base::MessageLoop::current()->RunUntilIdle();
638 // Stream and session closed gracefully.
639 EXPECT_TRUE(delegate
.StreamIsClosed());
640 EXPECT_EQ(OK
, delegate
.WaitForClose());
641 EXPECT_EQ(kUploadData
, delegate
.TakeReceivedData());
642 EXPECT_TRUE(session
== NULL
);
645 // Try to create a stream after receiving a GOAWAY frame. It should
647 TEST_P(SpdySessionTest
, CreateStreamAfterGoAway
) {
648 session_deps_
.host_resolver
->set_synchronous_mode(true);
650 MockConnect
connect_data(SYNCHRONOUS
, OK
);
651 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
653 CreateMockRead(*goaway
, 1),
654 MockRead(ASYNC
, 0, 2) // EOF
656 scoped_ptr
<SpdyFrame
> req(
657 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
658 MockWrite writes
[] = {
659 CreateMockWrite(*req
, 0),
661 DeterministicSocketData
data(reads
, arraysize(reads
),
662 writes
, arraysize(writes
));
663 data
.set_connect_data(connect_data
);
664 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
666 CreateDeterministicNetworkSession();
668 base::WeakPtr
<SpdySession
> session
=
669 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
671 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
673 GURL
url(kDefaultURL
);
674 base::WeakPtr
<SpdyStream
> spdy_stream
=
675 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
676 session
, url
, MEDIUM
, BoundNetLog());
677 test::StreamDelegateDoNothing
delegate(spdy_stream
);
678 spdy_stream
->SetDelegate(&delegate
);
680 scoped_ptr
<SpdyHeaderBlock
> headers(
681 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
682 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
683 EXPECT_TRUE(spdy_stream
->HasUrlFromHeaders());
687 EXPECT_EQ(1u, spdy_stream
->stream_id());
689 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
691 // Read and process the GOAWAY frame.
694 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
695 EXPECT_TRUE(session
->IsStreamActive(1));
697 SpdyStreamRequest stream_request
;
698 int rv
= stream_request
.StartRequest(
699 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog(),
700 CompletionCallback());
701 EXPECT_EQ(ERR_FAILED
, rv
);
703 // Read and process EOF.
706 EXPECT_TRUE(session
== NULL
);
709 // Receiving a SYN_STREAM frame after a GOAWAY frame should result in
710 // the stream being refused.
711 TEST_P(SpdySessionTest
, SynStreamAfterGoAway
) {
712 session_deps_
.host_resolver
->set_synchronous_mode(true);
714 MockConnect
connect_data(SYNCHRONOUS
, OK
);
715 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(1));
716 scoped_ptr
<SpdyFrame
>
717 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kDefaultURL
));
719 CreateMockRead(*goaway
, 1),
720 CreateMockRead(*push
, 2),
721 MockRead(ASYNC
, 0, 4) // EOF
723 scoped_ptr
<SpdyFrame
> req(
724 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
725 scoped_ptr
<SpdyFrame
> rst(
726 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
727 MockWrite writes
[] = {
728 CreateMockWrite(*req
, 0),
729 CreateMockWrite(*rst
, 3)
731 DeterministicSocketData
data(reads
, arraysize(reads
),
732 writes
, arraysize(writes
));
733 data
.set_connect_data(connect_data
);
734 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
736 CreateDeterministicNetworkSession();
738 base::WeakPtr
<SpdySession
> session
=
739 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
741 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
743 GURL
url(kDefaultURL
);
744 base::WeakPtr
<SpdyStream
> spdy_stream
=
745 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
746 session
, url
, MEDIUM
, BoundNetLog());
747 test::StreamDelegateDoNothing
delegate(spdy_stream
);
748 spdy_stream
->SetDelegate(&delegate
);
750 scoped_ptr
<SpdyHeaderBlock
> headers(
751 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
752 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
753 EXPECT_TRUE(spdy_stream
->HasUrlFromHeaders());
757 EXPECT_EQ(1u, spdy_stream
->stream_id());
759 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
761 // Read and process the GOAWAY frame.
764 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
765 EXPECT_TRUE(session
->IsStreamActive(1));
767 // Read and process the SYN_STREAM frame, the subsequent RST_STREAM,
770 base::MessageLoop::current()->RunUntilIdle();
771 EXPECT_TRUE(session
== NULL
);
774 // A session observing a network change with active streams should close
775 // when the last active stream is closed.
776 TEST_P(SpdySessionTest
, NetworkChangeWithActiveStreams
) {
777 session_deps_
.host_resolver
->set_synchronous_mode(true);
779 MockConnect
connect_data(SYNCHRONOUS
, OK
);
781 MockRead(ASYNC
, 0, 1) // EOF
783 scoped_ptr
<SpdyFrame
> req1(
784 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
785 MockWrite writes
[] = {
786 CreateMockWrite(*req1
, 0),
788 DeterministicSocketData
data(reads
, arraysize(reads
),
789 writes
, arraysize(writes
));
790 data
.set_connect_data(connect_data
);
791 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
793 CreateDeterministicNetworkSession();
795 base::WeakPtr
<SpdySession
> session
=
796 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
798 EXPECT_EQ(spdy_util_
.spdy_version(), session
->GetProtocolVersion());
800 base::WeakPtr
<SpdyStream
> spdy_stream
=
801 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
, session
,
802 GURL(kDefaultURL
), MEDIUM
, BoundNetLog());
803 test::StreamDelegateDoNothing
delegate(spdy_stream
);
804 spdy_stream
->SetDelegate(&delegate
);
806 scoped_ptr
<SpdyHeaderBlock
> headers(
807 spdy_util_
.ConstructGetHeaderBlock(kDefaultURL
));
809 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
810 EXPECT_TRUE(spdy_stream
->HasUrlFromHeaders());
814 EXPECT_EQ(1u, spdy_stream
->stream_id());
816 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
818 spdy_session_pool_
->OnIPAddressChanged();
820 // The SpdySessionPool behavior differs based on how the OSs reacts to
821 // network changes; see comment in SpdySessionPool::OnIPAddressChanged().
822 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
823 // For OSs where the TCP connections will close upon relevant network
824 // changes, SpdySessionPool doesn't need to force them to close, so in these
825 // cases verify the session has become unavailable but remains open and the
826 // pre-existing stream is still active.
827 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
829 EXPECT_TRUE(session
->IsGoingAway());
831 EXPECT_TRUE(session
->IsStreamActive(1));
833 // Should close the session.
834 spdy_stream
->Close();
836 EXPECT_EQ(NULL
, spdy_stream
.get());
838 base::MessageLoop::current()->RunUntilIdle();
839 EXPECT_TRUE(session
== NULL
);
842 TEST_P(SpdySessionTest
, ClientPing
) {
843 session_deps_
.enable_ping
= true;
844 session_deps_
.host_resolver
->set_synchronous_mode(true);
846 MockConnect
connect_data(SYNCHRONOUS
, OK
);
847 scoped_ptr
<SpdyFrame
> read_ping(spdy_util_
.ConstructSpdyPing(1, true));
849 CreateMockRead(*read_ping
, 1),
850 MockRead(ASYNC
, 0, 0, 2) // EOF
852 scoped_ptr
<SpdyFrame
> write_ping(spdy_util_
.ConstructSpdyPing(1, false));
853 MockWrite writes
[] = {
854 CreateMockWrite(*write_ping
, 0),
856 DeterministicSocketData
data(
857 reads
, arraysize(reads
), writes
, arraysize(writes
));
858 data
.set_connect_data(connect_data
);
859 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
861 CreateDeterministicNetworkSession();
863 base::WeakPtr
<SpdySession
> session
=
864 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
866 base::WeakPtr
<SpdyStream
> spdy_stream1
=
867 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
868 session
, test_url_
, MEDIUM
, BoundNetLog());
869 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
870 test::StreamDelegateSendImmediate
delegate(spdy_stream1
, NULL
);
871 spdy_stream1
->SetDelegate(&delegate
);
873 base::TimeTicks before_ping_time
= base::TimeTicks::Now();
875 session
->set_connection_at_risk_of_loss_time(
876 base::TimeDelta::FromSeconds(-1));
877 session
->set_hung_interval(base::TimeDelta::FromMilliseconds(50));
879 session
->SendPrefacePingIfNoneInFlight();
883 session
->CheckPingStatus(before_ping_time
);
885 EXPECT_EQ(0, session
->pings_in_flight());
886 EXPECT_GE(session
->next_ping_id(), static_cast<uint32
>(1));
887 EXPECT_FALSE(session
->check_ping_status_pending());
888 EXPECT_GE(session
->last_activity_time(), before_ping_time
);
892 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
894 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
895 EXPECT_TRUE(session
== NULL
);
898 TEST_P(SpdySessionTest
, ServerPing
) {
899 session_deps_
.host_resolver
->set_synchronous_mode(true);
901 MockConnect
connect_data(SYNCHRONOUS
, OK
);
902 scoped_ptr
<SpdyFrame
> read_ping(spdy_util_
.ConstructSpdyPing(2, false));
904 CreateMockRead(*read_ping
),
905 MockRead(SYNCHRONOUS
, 0, 0) // EOF
907 scoped_ptr
<SpdyFrame
> write_ping(spdy_util_
.ConstructSpdyPing(2, true));
908 MockWrite writes
[] = {
909 CreateMockWrite(*write_ping
),
911 StaticSocketDataProvider
data(
912 reads
, arraysize(reads
), writes
, arraysize(writes
));
913 data
.set_connect_data(connect_data
);
914 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
916 CreateNetworkSession();
918 base::WeakPtr
<SpdySession
> session
=
919 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
921 base::WeakPtr
<SpdyStream
> spdy_stream1
=
922 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
923 session
, test_url_
, MEDIUM
, BoundNetLog());
924 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
925 test::StreamDelegateSendImmediate
delegate(spdy_stream1
, NULL
);
926 spdy_stream1
->SetDelegate(&delegate
);
928 // Flush the read completion task.
929 base::MessageLoop::current()->RunUntilIdle();
931 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
933 EXPECT_TRUE(session
== NULL
);
934 EXPECT_EQ(NULL
, spdy_stream1
.get());
937 // Cause a ping to be sent out while producing a write. The write loop
938 // should handle this properly, i.e. another DoWriteLoop task should
939 // not be posted. This is a regression test for
940 // http://crbug.com/261043 .
941 TEST_P(SpdySessionTest
, PingAndWriteLoop
) {
942 session_deps_
.enable_ping
= true;
943 session_deps_
.time_func
= TheNearFuture
;
945 MockConnect
connect_data(SYNCHRONOUS
, OK
);
946 scoped_ptr
<SpdyFrame
> write_ping(spdy_util_
.ConstructSpdyPing(1, false));
947 scoped_ptr
<SpdyFrame
> req(
948 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
949 MockWrite writes
[] = {
950 CreateMockWrite(*req
, 0),
951 CreateMockWrite(*write_ping
, 1),
955 MockRead(ASYNC
, 0, 2) // EOF
958 session_deps_
.host_resolver
->set_synchronous_mode(true);
960 DeterministicSocketData
data(reads
, arraysize(reads
),
961 writes
, arraysize(writes
));
962 data
.set_connect_data(connect_data
);
963 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
965 CreateDeterministicNetworkSession();
967 base::WeakPtr
<SpdySession
> session
=
968 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
970 GURL
url(kDefaultURL
);
971 base::WeakPtr
<SpdyStream
> spdy_stream
=
972 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
973 session
, url
, LOWEST
, BoundNetLog());
974 test::StreamDelegateDoNothing
delegate(spdy_stream
);
975 spdy_stream
->SetDelegate(&delegate
);
977 scoped_ptr
<SpdyHeaderBlock
> headers(
978 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
979 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
981 // Shift time so that a ping will be sent out.
982 g_time_delta
= base::TimeDelta::FromSeconds(11);
986 session
->CloseSessionOnError(ERR_ABORTED
, "Aborting");
989 TEST_P(SpdySessionTest
, StreamIdSpaceExhausted
) {
990 const SpdyStreamId kLastStreamId
= 0x7fffffff;
991 session_deps_
.host_resolver
->set_synchronous_mode(true);
993 // Test setup: |stream_hi_water_mark_| and |max_concurrent_streams_| are
994 // fixed to allow for two stream ID assignments, and three concurrent
995 // streams. Four streams are started, and two are activated. Verify the
996 // session goes away, and that the created (but not activated) and
997 // stalled streams are aborted. Also verify the activated streams complete,
998 // at which point the session closes.
1000 scoped_ptr
<SpdyFrame
> req1(spdy_util_
.ConstructSpdyGet(
1001 NULL
, 0, false, kLastStreamId
- 2, MEDIUM
, true));
1002 scoped_ptr
<SpdyFrame
> req2(
1003 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, kLastStreamId
, MEDIUM
, true));
1005 MockWrite writes
[] = {
1006 CreateMockWrite(*req1
, 0), CreateMockWrite(*req2
, 1),
1009 scoped_ptr
<SpdyFrame
> resp1(
1010 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, kLastStreamId
- 2));
1011 scoped_ptr
<SpdyFrame
> resp2(
1012 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, kLastStreamId
));
1014 scoped_ptr
<SpdyFrame
> body1(
1015 spdy_util_
.ConstructSpdyBodyFrame(kLastStreamId
- 2, true));
1016 scoped_ptr
<SpdyFrame
> body2(
1017 spdy_util_
.ConstructSpdyBodyFrame(kLastStreamId
, true));
1019 MockRead reads
[] = {
1020 CreateMockRead(*resp1
, 2), CreateMockRead(*resp2
, 3),
1021 CreateMockRead(*body1
, 4), CreateMockRead(*body2
, 5),
1022 MockRead(ASYNC
, 0, 6) // EOF
1025 DeterministicSocketData
data(
1026 reads
, arraysize(reads
), writes
, arraysize(writes
));
1028 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1029 data
.set_connect_data(connect_data
);
1030 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1032 CreateDeterministicNetworkSession();
1033 base::WeakPtr
<SpdySession
> session
=
1034 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1036 // Fix stream_hi_water_mark_ to allow for two stream activations.
1037 session
->stream_hi_water_mark_
= kLastStreamId
- 2;
1038 // Fix max_concurrent_streams to allow for three stream creations.
1039 session
->max_concurrent_streams_
= 3;
1041 // Create three streams synchronously, and begin a fourth (which is stalled).
1042 GURL
url(kDefaultURL
);
1043 base::WeakPtr
<SpdyStream
> stream1
= CreateStreamSynchronously(
1044 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
1045 test::StreamDelegateDoNothing
delegate1(stream1
);
1046 stream1
->SetDelegate(&delegate1
);
1048 base::WeakPtr
<SpdyStream
> stream2
= CreateStreamSynchronously(
1049 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
1050 test::StreamDelegateDoNothing
delegate2(stream2
);
1051 stream2
->SetDelegate(&delegate2
);
1053 base::WeakPtr
<SpdyStream
> stream3
= CreateStreamSynchronously(
1054 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
1055 test::StreamDelegateDoNothing
delegate3(stream3
);
1056 stream3
->SetDelegate(&delegate3
);
1058 SpdyStreamRequest request4
;
1059 TestCompletionCallback callback4
;
1060 EXPECT_EQ(ERR_IO_PENDING
,
1061 request4
.StartRequest(SPDY_REQUEST_RESPONSE_STREAM
,
1066 callback4
.callback()));
1068 // Streams 1-3 were created. 4th is stalled. No streams are active yet.
1069 EXPECT_EQ(0u, session
->num_active_streams());
1070 EXPECT_EQ(3u, session
->num_created_streams());
1071 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(MEDIUM
));
1073 // Activate stream 1. One ID remains available.
1074 stream1
->SendRequestHeaders(
1075 scoped_ptr
<SpdyHeaderBlock
>(
1076 spdy_util_
.ConstructGetHeaderBlock(url
.spec())),
1077 NO_MORE_DATA_TO_SEND
);
1080 EXPECT_EQ(kLastStreamId
- 2u, stream1
->stream_id());
1081 EXPECT_EQ(1u, session
->num_active_streams());
1082 EXPECT_EQ(2u, session
->num_created_streams());
1083 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(MEDIUM
));
1085 // Activate stream 2. ID space is exhausted.
1086 stream2
->SendRequestHeaders(
1087 scoped_ptr
<SpdyHeaderBlock
>(
1088 spdy_util_
.ConstructGetHeaderBlock(url
.spec())),
1089 NO_MORE_DATA_TO_SEND
);
1092 // Active streams remain active.
1093 EXPECT_EQ(kLastStreamId
, stream2
->stream_id());
1094 EXPECT_EQ(2u, session
->num_active_streams());
1096 // Session is going away. Created and stalled streams were aborted.
1097 EXPECT_EQ(SpdySession::STATE_GOING_AWAY
, session
->availability_state_
);
1098 EXPECT_EQ(ERR_ABORTED
, delegate3
.WaitForClose());
1099 EXPECT_EQ(ERR_ABORTED
, callback4
.WaitForResult());
1100 EXPECT_EQ(0u, session
->num_created_streams());
1101 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(MEDIUM
));
1103 // Read responses on remaining active streams.
1105 EXPECT_EQ(OK
, delegate1
.WaitForClose());
1106 EXPECT_EQ(kUploadData
, delegate1
.TakeReceivedData());
1107 EXPECT_EQ(OK
, delegate2
.WaitForClose());
1108 EXPECT_EQ(kUploadData
, delegate2
.TakeReceivedData());
1110 // Session was destroyed.
1111 base::MessageLoop::current()->RunUntilIdle();
1112 EXPECT_FALSE(session
.get());
1115 // Verifies that an unstalled pending stream creation racing with a new stream
1116 // creation doesn't violate the maximum stream concurrency. Regression test for
1117 // crbug.com/373858.
1118 TEST_P(SpdySessionTest
, UnstallRacesWithStreamCreation
) {
1119 session_deps_
.host_resolver
->set_synchronous_mode(true);
1121 MockRead reads
[] = {
1122 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
1125 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
1127 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1128 data
.set_connect_data(connect_data
);
1129 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
1131 CreateNetworkSession();
1132 base::WeakPtr
<SpdySession
> session
=
1133 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1135 // Fix max_concurrent_streams to allow for one open stream.
1136 session
->max_concurrent_streams_
= 1;
1138 // Create two streams: one synchronously, and one which stalls.
1139 GURL
url(kDefaultURL
);
1140 base::WeakPtr
<SpdyStream
> stream1
= CreateStreamSynchronously(
1141 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
1143 SpdyStreamRequest request2
;
1144 TestCompletionCallback callback2
;
1145 EXPECT_EQ(ERR_IO_PENDING
,
1146 request2
.StartRequest(SPDY_REQUEST_RESPONSE_STREAM
,
1151 callback2
.callback()));
1153 EXPECT_EQ(1u, session
->num_created_streams());
1154 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(MEDIUM
));
1156 // Cancel the first stream. A callback to unstall the second stream was
1157 // posted. Don't run it yet.
1160 EXPECT_EQ(0u, session
->num_created_streams());
1161 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(MEDIUM
));
1163 // Create a third stream prior to the second stream's callback.
1164 base::WeakPtr
<SpdyStream
> stream3
= CreateStreamSynchronously(
1165 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
1167 EXPECT_EQ(1u, session
->num_created_streams());
1168 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(MEDIUM
));
1170 // NOW run the message loop. The unstalled stream will re-stall itself.
1171 base::MessageLoop::current()->RunUntilIdle();
1172 EXPECT_EQ(1u, session
->num_created_streams());
1173 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(MEDIUM
));
1175 // Cancel the third stream and run the message loop. Verify that the second
1176 // stream creation now completes.
1178 base::MessageLoop::current()->RunUntilIdle();
1180 EXPECT_EQ(1u, session
->num_created_streams());
1181 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(MEDIUM
));
1182 EXPECT_EQ(OK
, callback2
.WaitForResult());
1185 TEST_P(SpdySessionTest
, DeleteExpiredPushStreams
) {
1186 session_deps_
.host_resolver
->set_synchronous_mode(true);
1187 session_deps_
.time_func
= TheNearFuture
;
1189 scoped_ptr
<SpdyFrame
> req(
1190 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
1191 scoped_ptr
<SpdyFrame
> rst(
1192 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM
));
1194 scoped_ptr
<SpdyFrame
> push_a(spdy_util_
.ConstructSpdyPush(
1195 NULL
, 0, 2, 1, "http://www.google.com/a.dat"));
1196 scoped_ptr
<SpdyFrame
> push_a_body(
1197 spdy_util_
.ConstructSpdyBodyFrame(2, false));
1198 scoped_ptr
<SpdyFrame
> push_b(spdy_util_
.ConstructSpdyPush(
1199 NULL
, 0, 4, 1, "http://www.google.com/b.dat"));
1200 MockWrite writes
[] = {CreateMockWrite(*req
, 0), CreateMockWrite(*rst
, 4)};
1201 MockRead reads
[] = {
1202 CreateMockRead(*push_a
, 1), CreateMockRead(*push_a_body
, 2),
1203 CreateMockRead(*push_b
, 3), MockRead(ASYNC
, 0, 5), // EOF
1205 DeterministicSocketData
data(
1206 reads
, arraysize(reads
), writes
, arraysize(writes
));
1208 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1209 data
.set_connect_data(connect_data
);
1210 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1212 CreateDeterministicNetworkSession();
1213 base::WeakPtr
<SpdySession
> session
=
1214 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1216 // Process the principal request, and the first push stream request & body.
1217 GURL
url(kDefaultURL
);
1218 base::WeakPtr
<SpdyStream
> spdy_stream
= CreateStreamSynchronously(
1219 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, MEDIUM
, BoundNetLog());
1220 test::StreamDelegateDoNothing
delegate(spdy_stream
);
1221 spdy_stream
->SetDelegate(&delegate
);
1223 scoped_ptr
<SpdyHeaderBlock
> headers(
1224 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
1225 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
1229 // Verify that there is one unclaimed push stream.
1230 EXPECT_EQ(1u, session
->num_unclaimed_pushed_streams());
1231 SpdySession::PushedStreamMap::iterator iter
=
1232 session
->unclaimed_pushed_streams_
.find(
1233 GURL("http://www.google.com/a.dat"));
1234 EXPECT_TRUE(session
->unclaimed_pushed_streams_
.end() != iter
);
1236 if (session
->flow_control_state_
==
1237 SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
) {
1238 // Unclaimed push body consumed bytes from the session window.
1239 EXPECT_EQ(kSpdySessionInitialWindowSize
- kUploadDataSize
,
1240 session
->session_recv_window_size_
);
1241 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
1244 // Shift time to expire the push stream. Read the second SYN_STREAM,
1245 // and verify a RST_STREAM was written.
1246 g_time_delta
= base::TimeDelta::FromSeconds(301);
1249 // Verify that the second pushed stream evicted the first pushed stream.
1250 EXPECT_EQ(1u, session
->num_unclaimed_pushed_streams());
1251 iter
= session
->unclaimed_pushed_streams_
.find(
1252 GURL("http://www.google.com/b.dat"));
1253 EXPECT_TRUE(session
->unclaimed_pushed_streams_
.end() != iter
);
1255 if (session
->flow_control_state_
==
1256 SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
) {
1257 // Verify that the session window reclaimed the evicted stream body.
1258 EXPECT_EQ(kSpdySessionInitialWindowSize
,
1259 session
->session_recv_window_size_
);
1260 EXPECT_EQ(kUploadDataSize
, session
->session_unacked_recv_window_bytes_
);
1263 // Read and process EOF.
1265 base::MessageLoop::current()->RunUntilIdle();
1266 EXPECT_TRUE(session
== NULL
);
1269 TEST_P(SpdySessionTest
, FailedPing
) {
1270 session_deps_
.host_resolver
->set_synchronous_mode(true);
1272 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1273 MockRead reads
[] = {
1274 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
1276 scoped_ptr
<SpdyFrame
> write_ping(spdy_util_
.ConstructSpdyPing(1, false));
1277 scoped_ptr
<SpdyFrame
> goaway(
1278 spdy_util_
.ConstructSpdyGoAway(0, GOAWAY_PROTOCOL_ERROR
, "Failed ping."));
1279 MockWrite writes
[] = {CreateMockWrite(*write_ping
), CreateMockWrite(*goaway
)};
1280 StaticSocketDataProvider
data(
1281 reads
, arraysize(reads
), writes
, arraysize(writes
));
1282 data
.set_connect_data(connect_data
);
1283 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
1285 CreateNetworkSession();
1287 base::WeakPtr
<SpdySession
> session
=
1288 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1290 base::WeakPtr
<SpdyStream
> spdy_stream1
=
1291 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1292 session
, test_url_
, MEDIUM
, BoundNetLog());
1293 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
1294 test::StreamDelegateSendImmediate
delegate(spdy_stream1
, NULL
);
1295 spdy_stream1
->SetDelegate(&delegate
);
1297 session
->set_connection_at_risk_of_loss_time(base::TimeDelta::FromSeconds(0));
1298 session
->set_hung_interval(base::TimeDelta::FromSeconds(0));
1300 // Send a PING frame.
1301 session
->WritePingFrame(1, false);
1302 EXPECT_LT(0, session
->pings_in_flight());
1303 EXPECT_GE(session
->next_ping_id(), static_cast<uint32
>(1));
1304 EXPECT_TRUE(session
->check_ping_status_pending());
1306 // Assert session is not closed.
1307 EXPECT_TRUE(session
->IsAvailable());
1308 EXPECT_LT(0u, session
->num_active_streams() + session
->num_created_streams());
1309 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
1311 // We set last time we have received any data in 1 sec less than now.
1312 // CheckPingStatus will trigger timeout because hung interval is zero.
1313 base::TimeTicks now
= base::TimeTicks::Now();
1314 session
->last_activity_time_
= now
- base::TimeDelta::FromSeconds(1);
1315 session
->CheckPingStatus(now
);
1316 base::MessageLoop::current()->RunUntilIdle();
1318 EXPECT_TRUE(session
== NULL
);
1319 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
1320 EXPECT_EQ(NULL
, spdy_stream1
.get());
1323 // Request kInitialMaxConcurrentStreams + 1 streams. Receive a
1324 // settings frame increasing the max concurrent streams by 1. Make
1325 // sure nothing blows up. This is a regression test for
1326 // http://crbug.com/57331 .
1327 TEST_P(SpdySessionTest
, OnSettings
) {
1328 session_deps_
.host_resolver
->set_synchronous_mode(true);
1330 const SpdySettingsIds kSpdySettingsIds
= SETTINGS_MAX_CONCURRENT_STREAMS
;
1332 SettingsMap new_settings
;
1333 const uint32 max_concurrent_streams
= kInitialMaxConcurrentStreams
+ 1;
1334 new_settings
[kSpdySettingsIds
] =
1335 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1336 scoped_ptr
<SpdyFrame
> settings_frame(
1337 spdy_util_
.ConstructSpdySettings(new_settings
));
1338 MockRead reads
[] = {
1339 CreateMockRead(*settings_frame
, 0),
1340 MockRead(ASYNC
, 0, 1),
1343 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
1344 MockWrite writes
[] = {
1345 CreateMockWrite(*settings_ack
, 2),
1348 DeterministicSocketData
data(reads
, arraysize(reads
),
1349 writes
, arraysize(writes
));
1350 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1351 data
.set_connect_data(connect_data
);
1352 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1354 CreateDeterministicNetworkSession();
1356 base::WeakPtr
<SpdySession
> session
=
1357 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1359 // Create the maximum number of concurrent streams.
1360 for (size_t i
= 0; i
< kInitialMaxConcurrentStreams
; ++i
) {
1361 base::WeakPtr
<SpdyStream
> spdy_stream
=
1362 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1363 session
, test_url_
, MEDIUM
, BoundNetLog());
1364 ASSERT_TRUE(spdy_stream
!= NULL
);
1367 StreamReleaserCallback stream_releaser
;
1368 SpdyStreamRequest request
;
1369 ASSERT_EQ(ERR_IO_PENDING
,
1370 request
.StartRequest(
1371 SPDY_BIDIRECTIONAL_STREAM
, session
, test_url_
, MEDIUM
,
1373 stream_releaser
.MakeCallback(&request
)));
1377 EXPECT_EQ(OK
, stream_releaser
.WaitForResult());
1380 if (spdy_util_
.spdy_version() >= SPDY4
) {
1381 // Allow the SETTINGS+ACK to write, so the session finishes draining.
1384 base::MessageLoop::current()->RunUntilIdle();
1385 EXPECT_TRUE(session
== NULL
);
1388 // Start with a persisted value for max concurrent streams. Receive a
1389 // settings frame increasing the max concurrent streams by 1 and which
1390 // also clears the persisted data. Verify that persisted data is
1392 TEST_P(SpdySessionTest
, ClearSettings
) {
1393 if (spdy_util_
.spdy_version() >= SPDY4
) {
1394 // SPDY4 doesn't include settings persistence, or a CLEAR_SETTINGS flag.
1395 // Flag 0x1, CLEAR_SETTINGS in SPDY3, is instead settings ACK in SPDY4.
1398 session_deps_
.host_resolver
->set_synchronous_mode(true);
1400 SettingsMap new_settings
;
1401 const uint32 max_concurrent_streams
= kInitialMaxConcurrentStreams
+ 1;
1402 new_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1403 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
1404 scoped_ptr
<SpdyFrame
> settings_frame(
1405 spdy_util_
.ConstructSpdySettings(new_settings
));
1406 uint8 flags
= SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS
;
1407 test::SetFrameFlags(settings_frame
.get(), flags
, spdy_util_
.spdy_version());
1408 MockRead reads
[] = {
1409 CreateMockRead(*settings_frame
, 0),
1410 MockRead(ASYNC
, 0, 1),
1413 DeterministicSocketData
data(reads
, arraysize(reads
), NULL
, 0);
1414 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1415 data
.set_connect_data(connect_data
);
1416 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1418 CreateDeterministicNetworkSession();
1420 // Initialize the SpdySetting with the default.
1421 spdy_session_pool_
->http_server_properties()->SetSpdySetting(
1422 test_host_port_pair_
,
1423 SETTINGS_MAX_CONCURRENT_STREAMS
,
1424 SETTINGS_FLAG_PLEASE_PERSIST
,
1425 kInitialMaxConcurrentStreams
);
1428 spdy_session_pool_
->http_server_properties()->GetSpdySettings(
1429 test_host_port_pair_
).empty());
1431 base::WeakPtr
<SpdySession
> session
=
1432 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1434 // Create the maximum number of concurrent streams.
1435 for (size_t i
= 0; i
< kInitialMaxConcurrentStreams
; ++i
) {
1436 base::WeakPtr
<SpdyStream
> spdy_stream
=
1437 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1438 session
, test_url_
, MEDIUM
, BoundNetLog());
1439 ASSERT_TRUE(spdy_stream
!= NULL
);
1442 StreamReleaserCallback stream_releaser
;
1444 SpdyStreamRequest request
;
1445 ASSERT_EQ(ERR_IO_PENDING
,
1446 request
.StartRequest(
1447 SPDY_BIDIRECTIONAL_STREAM
, session
, test_url_
, MEDIUM
,
1449 stream_releaser
.MakeCallback(&request
)));
1453 EXPECT_EQ(OK
, stream_releaser
.WaitForResult());
1455 // Make sure that persisted data is cleared.
1457 spdy_session_pool_
->http_server_properties()->GetSpdySettings(
1458 test_host_port_pair_
).empty());
1460 // Make sure session's max_concurrent_streams is correct.
1461 EXPECT_EQ(kInitialMaxConcurrentStreams
+ 1,
1462 session
->max_concurrent_streams());
1465 EXPECT_TRUE(session
== NULL
);
1468 // Start with max concurrent streams set to 1. Request two streams.
1469 // When the first completes, have the callback close its stream, which
1470 // should trigger the second stream creation. Then cancel that one
1471 // immediately. Don't crash. This is a regression test for
1472 // http://crbug.com/63532 .
1473 TEST_P(SpdySessionTest
, CancelPendingCreateStream
) {
1474 session_deps_
.host_resolver
->set_synchronous_mode(true);
1476 MockRead reads
[] = {
1477 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
1480 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
1481 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1483 data
.set_connect_data(connect_data
);
1484 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
1486 CreateNetworkSession();
1488 // Initialize the SpdySetting with 1 max concurrent streams.
1489 spdy_session_pool_
->http_server_properties()->SetSpdySetting(
1490 test_host_port_pair_
,
1491 SETTINGS_MAX_CONCURRENT_STREAMS
,
1492 SETTINGS_FLAG_PLEASE_PERSIST
,
1495 base::WeakPtr
<SpdySession
> session
=
1496 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1498 // Leave room for only one more stream to be created.
1499 for (size_t i
= 0; i
< kInitialMaxConcurrentStreams
- 1; ++i
) {
1500 base::WeakPtr
<SpdyStream
> spdy_stream
=
1501 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1502 session
, test_url_
, MEDIUM
, BoundNetLog());
1503 ASSERT_TRUE(spdy_stream
!= NULL
);
1506 // Create 2 more streams. First will succeed. Second will be pending.
1507 base::WeakPtr
<SpdyStream
> spdy_stream1
=
1508 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1509 session
, test_url_
, MEDIUM
, BoundNetLog());
1510 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
1512 // Use scoped_ptr to let us invalidate the memory when we want to, to trigger
1513 // a valgrind error if the callback is invoked when it's not supposed to be.
1514 scoped_ptr
<TestCompletionCallback
> callback(new TestCompletionCallback
);
1516 SpdyStreamRequest request
;
1517 ASSERT_EQ(ERR_IO_PENDING
,
1518 request
.StartRequest(
1519 SPDY_BIDIRECTIONAL_STREAM
, session
, test_url_
, MEDIUM
,
1521 callback
->callback()));
1523 // Release the first one, this will allow the second to be created.
1524 spdy_stream1
->Cancel();
1525 EXPECT_EQ(NULL
, spdy_stream1
.get());
1527 request
.CancelRequest();
1530 // Should not crash when running the pending callback.
1531 base::MessageLoop::current()->RunUntilIdle();
1534 TEST_P(SpdySessionTest
, SendInitialDataOnNewSession
) {
1535 session_deps_
.host_resolver
->set_synchronous_mode(true);
1537 MockRead reads
[] = {
1538 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
1541 SettingsMap settings
;
1542 const SpdySettingsIds kSpdySettingsIds1
= SETTINGS_MAX_CONCURRENT_STREAMS
;
1543 const SpdySettingsIds kSpdySettingsIds2
= SETTINGS_INITIAL_WINDOW_SIZE
;
1544 const uint32 kInitialRecvWindowSize
= 10 * 1024 * 1024;
1545 settings
[kSpdySettingsIds1
] =
1546 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kMaxConcurrentPushedStreams
);
1547 if (spdy_util_
.spdy_version() >= SPDY3
) {
1548 settings
[kSpdySettingsIds2
] =
1549 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, kInitialRecvWindowSize
);
1551 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1552 scoped_ptr
<SpdyFrame
> settings_frame(
1553 spdy_util_
.ConstructSpdySettings(settings
));
1554 scoped_ptr
<SpdyFrame
> initial_window_update(
1555 spdy_util_
.ConstructSpdyWindowUpdate(
1556 kSessionFlowControlStreamId
,
1557 kDefaultInitialRecvWindowSize
- kSpdySessionInitialWindowSize
));
1558 std::vector
<MockWrite
> writes
;
1559 if (GetParam() == kProtoSPDY4
) {
1562 kHttp2ConnectionHeaderPrefix
,
1563 kHttp2ConnectionHeaderPrefixSize
));
1565 writes
.push_back(CreateMockWrite(*settings_frame
));
1566 if (GetParam() >= kProtoSPDY31
) {
1567 writes
.push_back(CreateMockWrite(*initial_window_update
));
1570 SettingsMap server_settings
;
1571 const uint32 initial_max_concurrent_streams
= 1;
1572 server_settings
[SETTINGS_MAX_CONCURRENT_STREAMS
] =
1573 SettingsFlagsAndValue(SETTINGS_FLAG_PERSISTED
,
1574 initial_max_concurrent_streams
);
1575 scoped_ptr
<SpdyFrame
> server_settings_frame(
1576 spdy_util_
.ConstructSpdySettings(server_settings
));
1577 writes
.push_back(CreateMockWrite(*server_settings_frame
));
1579 session_deps_
.stream_initial_recv_window_size
= kInitialRecvWindowSize
;
1581 StaticSocketDataProvider
data(reads
, arraysize(reads
),
1582 vector_as_array(&writes
), writes
.size());
1583 data
.set_connect_data(connect_data
);
1584 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
1586 CreateNetworkSession();
1588 spdy_session_pool_
->http_server_properties()->SetSpdySetting(
1589 test_host_port_pair_
,
1590 SETTINGS_MAX_CONCURRENT_STREAMS
,
1591 SETTINGS_FLAG_PLEASE_PERSIST
,
1592 initial_max_concurrent_streams
);
1594 SpdySessionPoolPeer
pool_peer(spdy_session_pool_
);
1595 pool_peer
.SetEnableSendingInitialData(true);
1597 base::WeakPtr
<SpdySession
> session
=
1598 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1600 base::MessageLoop::current()->RunUntilIdle();
1601 EXPECT_TRUE(data
.at_write_eof());
1604 TEST_P(SpdySessionTest
, ClearSettingsStorageOnIPAddressChanged
) {
1605 CreateNetworkSession();
1607 base::WeakPtr
<HttpServerProperties
> test_http_server_properties
=
1608 spdy_session_pool_
->http_server_properties();
1609 SettingsFlagsAndValue
flags_and_value1(SETTINGS_FLAG_PLEASE_PERSIST
, 2);
1610 test_http_server_properties
->SetSpdySetting(
1611 test_host_port_pair_
,
1612 SETTINGS_MAX_CONCURRENT_STREAMS
,
1613 SETTINGS_FLAG_PLEASE_PERSIST
,
1615 EXPECT_NE(0u, test_http_server_properties
->GetSpdySettings(
1616 test_host_port_pair_
).size());
1617 spdy_session_pool_
->OnIPAddressChanged();
1618 EXPECT_EQ(0u, test_http_server_properties
->GetSpdySettings(
1619 test_host_port_pair_
).size());
1622 TEST_P(SpdySessionTest
, Initialize
) {
1623 CapturingBoundNetLog log
;
1624 session_deps_
.net_log
= log
.bound().net_log();
1625 session_deps_
.host_resolver
->set_synchronous_mode(true);
1627 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1628 MockRead reads
[] = {
1629 MockRead(ASYNC
, 0, 0) // EOF
1632 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
1633 data
.set_connect_data(connect_data
);
1634 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
1636 CreateNetworkSession();
1638 base::WeakPtr
<SpdySession
> session
=
1639 CreateInsecureSpdySession(http_session_
, key_
, log
.bound());
1640 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
1642 // Flush the read completion task.
1643 base::MessageLoop::current()->RunUntilIdle();
1645 net::CapturingNetLog::CapturedEntryList entries
;
1646 log
.GetEntries(&entries
);
1647 EXPECT_LT(0u, entries
.size());
1649 // Check that we logged TYPE_SPDY_SESSION_INITIALIZED correctly.
1650 int pos
= net::ExpectLogContainsSomewhere(
1652 net::NetLog::TYPE_SPDY_SESSION_INITIALIZED
,
1653 net::NetLog::PHASE_NONE
);
1656 CapturingNetLog::CapturedEntry entry
= entries
[pos
];
1657 NetLog::Source socket_source
;
1658 EXPECT_TRUE(NetLog::Source::FromEventParameters(entry
.params
.get(),
1660 EXPECT_TRUE(socket_source
.IsValid());
1661 EXPECT_NE(log
.bound().source().id
, socket_source
.id
);
1664 TEST_P(SpdySessionTest
, NetLogOnSessionGoaway
) {
1665 session_deps_
.host_resolver
->set_synchronous_mode(true);
1667 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1668 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway());
1669 MockRead reads
[] = {
1670 CreateMockRead(*goaway
),
1671 MockRead(SYNCHRONOUS
, 0, 0) // EOF
1674 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
1675 data
.set_connect_data(connect_data
);
1676 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
1678 CreateNetworkSession();
1680 CapturingBoundNetLog log
;
1681 base::WeakPtr
<SpdySession
> session
=
1682 CreateInsecureSpdySession(http_session_
, key_
, log
.bound());
1683 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
1685 // Flush the read completion task.
1686 base::MessageLoop::current()->RunUntilIdle();
1688 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
1689 EXPECT_TRUE(session
== NULL
);
1691 // Check that the NetLog was filled reasonably.
1692 net::CapturingNetLog::CapturedEntryList entries
;
1693 log
.GetEntries(&entries
);
1694 EXPECT_LT(0u, entries
.size());
1696 // Check that we logged SPDY_SESSION_CLOSE correctly.
1697 int pos
= net::ExpectLogContainsSomewhere(
1699 net::NetLog::TYPE_SPDY_SESSION_CLOSE
,
1700 net::NetLog::PHASE_NONE
);
1702 if (pos
< static_cast<int>(entries
.size())) {
1703 CapturingNetLog::CapturedEntry entry
= entries
[pos
];
1705 ASSERT_TRUE(entry
.GetNetErrorCode(&error_code
));
1706 EXPECT_EQ(OK
, error_code
);
1712 TEST_P(SpdySessionTest
, NetLogOnSessionEOF
) {
1713 session_deps_
.host_resolver
->set_synchronous_mode(true);
1715 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1716 MockRead reads
[] = {
1717 MockRead(SYNCHRONOUS
, 0, 0) // EOF
1720 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
1721 data
.set_connect_data(connect_data
);
1722 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
1724 CreateNetworkSession();
1726 CapturingBoundNetLog log
;
1727 base::WeakPtr
<SpdySession
> session
=
1728 CreateInsecureSpdySession(http_session_
, key_
, log
.bound());
1729 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
1731 // Flush the read completion task.
1732 base::MessageLoop::current()->RunUntilIdle();
1734 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
1735 EXPECT_TRUE(session
== NULL
);
1737 // Check that the NetLog was filled reasonably.
1738 net::CapturingNetLog::CapturedEntryList entries
;
1739 log
.GetEntries(&entries
);
1740 EXPECT_LT(0u, entries
.size());
1742 // Check that we logged SPDY_SESSION_CLOSE correctly.
1744 net::ExpectLogContainsSomewhere(entries
,
1746 net::NetLog::TYPE_SPDY_SESSION_CLOSE
,
1747 net::NetLog::PHASE_NONE
);
1749 if (pos
< static_cast<int>(entries
.size())) {
1750 CapturingNetLog::CapturedEntry entry
= entries
[pos
];
1752 ASSERT_TRUE(entry
.GetNetErrorCode(&error_code
));
1753 EXPECT_EQ(ERR_CONNECTION_CLOSED
, error_code
);
1759 // Queue up a low-priority SYN_STREAM followed by a high-priority
1760 // one. The high priority one should still send first and receive
1762 TEST_P(SpdySessionTest
, OutOfOrderSynStreams
) {
1763 // Construct the request.
1764 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1765 scoped_ptr
<SpdyFrame
> req_highest(
1766 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, HIGHEST
, true));
1767 scoped_ptr
<SpdyFrame
> req_lowest(
1768 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
1769 MockWrite writes
[] = {
1770 CreateMockWrite(*req_highest
, 0),
1771 CreateMockWrite(*req_lowest
, 1),
1774 scoped_ptr
<SpdyFrame
> resp_highest(
1775 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1776 scoped_ptr
<SpdyFrame
> body_highest(
1777 spdy_util_
.ConstructSpdyBodyFrame(1, true));
1778 scoped_ptr
<SpdyFrame
> resp_lowest(
1779 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
1780 scoped_ptr
<SpdyFrame
> body_lowest(
1781 spdy_util_
.ConstructSpdyBodyFrame(3, true));
1782 MockRead reads
[] = {
1783 CreateMockRead(*resp_highest
, 2),
1784 CreateMockRead(*body_highest
, 3),
1785 CreateMockRead(*resp_lowest
, 4),
1786 CreateMockRead(*body_lowest
, 5),
1787 MockRead(ASYNC
, 0, 6) // EOF
1790 session_deps_
.host_resolver
->set_synchronous_mode(true);
1792 DeterministicSocketData
data(reads
, arraysize(reads
),
1793 writes
, arraysize(writes
));
1794 data
.set_connect_data(connect_data
);
1795 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1797 CreateDeterministicNetworkSession();
1799 base::WeakPtr
<SpdySession
> session
=
1800 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1802 GURL
url(kDefaultURL
);
1804 base::WeakPtr
<SpdyStream
> spdy_stream_lowest
=
1805 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
1806 session
, url
, LOWEST
, BoundNetLog());
1807 ASSERT_TRUE(spdy_stream_lowest
);
1808 EXPECT_EQ(0u, spdy_stream_lowest
->stream_id());
1809 test::StreamDelegateDoNothing
delegate_lowest(spdy_stream_lowest
);
1810 spdy_stream_lowest
->SetDelegate(&delegate_lowest
);
1812 base::WeakPtr
<SpdyStream
> spdy_stream_highest
=
1813 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
1814 session
, url
, HIGHEST
, BoundNetLog());
1815 ASSERT_TRUE(spdy_stream_highest
);
1816 EXPECT_EQ(0u, spdy_stream_highest
->stream_id());
1817 test::StreamDelegateDoNothing
delegate_highest(spdy_stream_highest
);
1818 spdy_stream_highest
->SetDelegate(&delegate_highest
);
1820 // Queue the lower priority one first.
1822 scoped_ptr
<SpdyHeaderBlock
> headers_lowest(
1823 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
1824 spdy_stream_lowest
->SendRequestHeaders(
1825 headers_lowest
.Pass(), NO_MORE_DATA_TO_SEND
);
1826 EXPECT_TRUE(spdy_stream_lowest
->HasUrlFromHeaders());
1828 scoped_ptr
<SpdyHeaderBlock
> headers_highest(
1829 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
1830 spdy_stream_highest
->SendRequestHeaders(
1831 headers_highest
.Pass(), NO_MORE_DATA_TO_SEND
);
1832 EXPECT_TRUE(spdy_stream_highest
->HasUrlFromHeaders());
1836 EXPECT_FALSE(spdy_stream_lowest
);
1837 EXPECT_FALSE(spdy_stream_highest
);
1838 EXPECT_EQ(3u, delegate_lowest
.stream_id());
1839 EXPECT_EQ(1u, delegate_highest
.stream_id());
1842 TEST_P(SpdySessionTest
, CancelStream
) {
1843 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1844 // Request 1, at HIGHEST priority, will be cancelled before it writes data.
1845 // Request 2, at LOWEST priority, will be a full request and will be id 1.
1846 scoped_ptr
<SpdyFrame
> req2(
1847 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1848 MockWrite writes
[] = {
1849 CreateMockWrite(*req2
, 0),
1852 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1853 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(1, true));
1854 MockRead reads
[] = {
1855 CreateMockRead(*resp2
, 1),
1856 CreateMockRead(*body2
, 2),
1857 MockRead(ASYNC
, 0, 3) // EOF
1860 session_deps_
.host_resolver
->set_synchronous_mode(true);
1862 DeterministicSocketData
data(reads
, arraysize(reads
),
1863 writes
, arraysize(writes
));
1864 data
.set_connect_data(connect_data
);
1865 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1867 CreateDeterministicNetworkSession();
1869 base::WeakPtr
<SpdySession
> session
=
1870 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1872 GURL
url1(kDefaultURL
);
1873 base::WeakPtr
<SpdyStream
> spdy_stream1
=
1874 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
1875 session
, url1
, HIGHEST
, BoundNetLog());
1876 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
1877 EXPECT_EQ(0u, spdy_stream1
->stream_id());
1878 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
1879 spdy_stream1
->SetDelegate(&delegate1
);
1881 GURL
url2(kDefaultURL
);
1882 base::WeakPtr
<SpdyStream
> spdy_stream2
=
1883 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
1884 session
, url2
, LOWEST
, BoundNetLog());
1885 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
1886 EXPECT_EQ(0u, spdy_stream2
->stream_id());
1887 test::StreamDelegateDoNothing
delegate2(spdy_stream2
);
1888 spdy_stream2
->SetDelegate(&delegate2
);
1890 scoped_ptr
<SpdyHeaderBlock
> headers(
1891 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
1892 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
1893 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
1895 scoped_ptr
<SpdyHeaderBlock
> headers2(
1896 spdy_util_
.ConstructGetHeaderBlock(url2
.spec()));
1897 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
1898 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
1900 EXPECT_EQ(0u, spdy_stream1
->stream_id());
1902 spdy_stream1
->Cancel();
1903 EXPECT_EQ(NULL
, spdy_stream1
.get());
1905 EXPECT_EQ(0u, delegate1
.stream_id());
1909 EXPECT_EQ(0u, delegate1
.stream_id());
1910 EXPECT_EQ(1u, delegate2
.stream_id());
1912 spdy_stream2
->Cancel();
1913 EXPECT_EQ(NULL
, spdy_stream2
.get());
1916 // Create two streams that are set to re-close themselves on close,
1917 // and then close the session. Nothing should blow up. Also a
1918 // regression test for http://crbug.com/139518 .
1919 TEST_P(SpdySessionTest
, CloseSessionWithTwoCreatedSelfClosingStreams
) {
1920 session_deps_
.host_resolver
->set_synchronous_mode(true);
1922 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1924 // No actual data will be sent.
1925 MockWrite writes
[] = {
1926 MockWrite(ASYNC
, 0, 1) // EOF
1929 MockRead reads
[] = {
1930 MockRead(ASYNC
, 0, 0) // EOF
1932 DeterministicSocketData
data(reads
, arraysize(reads
),
1933 writes
, arraysize(writes
));
1934 data
.set_connect_data(connect_data
);
1935 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1937 CreateDeterministicNetworkSession();
1939 base::WeakPtr
<SpdySession
> session
=
1940 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
1942 GURL
url1(kDefaultURL
);
1943 base::WeakPtr
<SpdyStream
> spdy_stream1
=
1944 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1945 session
, url1
, HIGHEST
, BoundNetLog());
1946 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
1947 EXPECT_EQ(0u, spdy_stream1
->stream_id());
1949 GURL
url2(kDefaultURL
);
1950 base::WeakPtr
<SpdyStream
> spdy_stream2
=
1951 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
1952 session
, url2
, LOWEST
, BoundNetLog());
1953 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
1954 EXPECT_EQ(0u, spdy_stream2
->stream_id());
1956 test::ClosingDelegate
delegate1(spdy_stream1
);
1957 spdy_stream1
->SetDelegate(&delegate1
);
1959 test::ClosingDelegate
delegate2(spdy_stream2
);
1960 spdy_stream2
->SetDelegate(&delegate2
);
1962 scoped_ptr
<SpdyHeaderBlock
> headers(
1963 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
1964 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
1965 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
1967 scoped_ptr
<SpdyHeaderBlock
> headers2(
1968 spdy_util_
.ConstructGetHeaderBlock(url2
.spec()));
1969 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
1970 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
1972 // Ensure that the streams have not yet been activated and assigned an id.
1973 EXPECT_EQ(0u, spdy_stream1
->stream_id());
1974 EXPECT_EQ(0u, spdy_stream2
->stream_id());
1976 // Ensure we don't crash while closing the session.
1977 session
->CloseSessionOnError(ERR_ABORTED
, std::string());
1979 EXPECT_EQ(NULL
, spdy_stream1
.get());
1980 EXPECT_EQ(NULL
, spdy_stream2
.get());
1982 EXPECT_TRUE(delegate1
.StreamIsClosed());
1983 EXPECT_TRUE(delegate2
.StreamIsClosed());
1985 base::MessageLoop::current()->RunUntilIdle();
1986 EXPECT_TRUE(session
== NULL
);
1989 // Create two streams that are set to close each other on close, and
1990 // then close the session. Nothing should blow up.
1991 TEST_P(SpdySessionTest
, CloseSessionWithTwoCreatedMutuallyClosingStreams
) {
1992 session_deps_
.host_resolver
->set_synchronous_mode(true);
1994 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1996 // No actual data will be sent.
1997 MockWrite writes
[] = {
1998 MockWrite(ASYNC
, 0, 1) // EOF
2001 MockRead reads
[] = {
2002 MockRead(ASYNC
, 0, 0) // EOF
2004 DeterministicSocketData
data(reads
, arraysize(reads
),
2005 writes
, arraysize(writes
));
2006 data
.set_connect_data(connect_data
);
2007 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2009 CreateDeterministicNetworkSession();
2011 base::WeakPtr
<SpdySession
> session
=
2012 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2014 GURL
url1(kDefaultURL
);
2015 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2016 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
2017 session
, url1
, HIGHEST
, BoundNetLog());
2018 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2019 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2021 GURL
url2(kDefaultURL
);
2022 base::WeakPtr
<SpdyStream
> spdy_stream2
=
2023 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
2024 session
, url2
, LOWEST
, BoundNetLog());
2025 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
2026 EXPECT_EQ(0u, spdy_stream2
->stream_id());
2028 // Make |spdy_stream1| close |spdy_stream2|.
2029 test::ClosingDelegate
delegate1(spdy_stream2
);
2030 spdy_stream1
->SetDelegate(&delegate1
);
2032 // Make |spdy_stream2| close |spdy_stream1|.
2033 test::ClosingDelegate
delegate2(spdy_stream1
);
2034 spdy_stream2
->SetDelegate(&delegate2
);
2036 scoped_ptr
<SpdyHeaderBlock
> headers(
2037 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2038 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
2039 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2041 scoped_ptr
<SpdyHeaderBlock
> headers2(
2042 spdy_util_
.ConstructGetHeaderBlock(url2
.spec()));
2043 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
2044 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
2046 // Ensure that the streams have not yet been activated and assigned an id.
2047 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2048 EXPECT_EQ(0u, spdy_stream2
->stream_id());
2050 // Ensure we don't crash while closing the session.
2051 session
->CloseSessionOnError(ERR_ABORTED
, std::string());
2053 EXPECT_EQ(NULL
, spdy_stream1
.get());
2054 EXPECT_EQ(NULL
, spdy_stream2
.get());
2056 EXPECT_TRUE(delegate1
.StreamIsClosed());
2057 EXPECT_TRUE(delegate2
.StreamIsClosed());
2059 base::MessageLoop::current()->RunUntilIdle();
2060 EXPECT_TRUE(session
== NULL
);
2063 // Create two streams that are set to re-close themselves on close,
2064 // activate them, and then close the session. Nothing should blow up.
2065 TEST_P(SpdySessionTest
, CloseSessionWithTwoActivatedSelfClosingStreams
) {
2066 session_deps_
.host_resolver
->set_synchronous_mode(true);
2068 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2070 scoped_ptr
<SpdyFrame
> req1(
2071 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
2072 scoped_ptr
<SpdyFrame
> req2(
2073 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, MEDIUM
, true));
2074 MockWrite writes
[] = {
2075 CreateMockWrite(*req1
, 0),
2076 CreateMockWrite(*req2
, 1),
2079 MockRead reads
[] = {
2080 MockRead(ASYNC
, 0, 2) // EOF
2083 DeterministicSocketData
data(reads
, arraysize(reads
),
2084 writes
, arraysize(writes
));
2085 data
.set_connect_data(connect_data
);
2086 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2088 CreateDeterministicNetworkSession();
2090 base::WeakPtr
<SpdySession
> session
=
2091 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2093 GURL
url1(kDefaultURL
);
2094 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2095 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2096 session
, url1
, MEDIUM
, BoundNetLog());
2097 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2098 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2100 GURL
url2(kDefaultURL
);
2101 base::WeakPtr
<SpdyStream
> spdy_stream2
=
2102 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2103 session
, url2
, MEDIUM
, BoundNetLog());
2104 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
2105 EXPECT_EQ(0u, spdy_stream2
->stream_id());
2107 test::ClosingDelegate
delegate1(spdy_stream1
);
2108 spdy_stream1
->SetDelegate(&delegate1
);
2110 test::ClosingDelegate
delegate2(spdy_stream2
);
2111 spdy_stream2
->SetDelegate(&delegate2
);
2113 scoped_ptr
<SpdyHeaderBlock
> headers(
2114 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2115 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
2116 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2118 scoped_ptr
<SpdyHeaderBlock
> headers2(
2119 spdy_util_
.ConstructGetHeaderBlock(url2
.spec()));
2120 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
2121 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
2123 // Ensure that the streams have not yet been activated and assigned an id.
2124 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2125 EXPECT_EQ(0u, spdy_stream2
->stream_id());
2129 EXPECT_EQ(1u, spdy_stream1
->stream_id());
2130 EXPECT_EQ(3u, spdy_stream2
->stream_id());
2132 // Ensure we don't crash while closing the session.
2133 session
->CloseSessionOnError(ERR_ABORTED
, std::string());
2135 EXPECT_EQ(NULL
, spdy_stream1
.get());
2136 EXPECT_EQ(NULL
, spdy_stream2
.get());
2138 EXPECT_TRUE(delegate1
.StreamIsClosed());
2139 EXPECT_TRUE(delegate2
.StreamIsClosed());
2141 base::MessageLoop::current()->RunUntilIdle();
2142 EXPECT_TRUE(session
== NULL
);
2145 // Create two streams that are set to close each other on close,
2146 // activate them, and then close the session. Nothing should blow up.
2147 TEST_P(SpdySessionTest
, CloseSessionWithTwoActivatedMutuallyClosingStreams
) {
2148 session_deps_
.host_resolver
->set_synchronous_mode(true);
2150 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2152 scoped_ptr
<SpdyFrame
> req1(
2153 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
2154 scoped_ptr
<SpdyFrame
> req2(
2155 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, MEDIUM
, true));
2156 MockWrite writes
[] = {
2157 CreateMockWrite(*req1
, 0),
2158 CreateMockWrite(*req2
, 1),
2161 MockRead reads
[] = {
2162 MockRead(ASYNC
, 0, 2) // EOF
2165 DeterministicSocketData
data(reads
, arraysize(reads
),
2166 writes
, arraysize(writes
));
2167 data
.set_connect_data(connect_data
);
2168 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2170 CreateDeterministicNetworkSession();
2172 base::WeakPtr
<SpdySession
> session
=
2173 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2175 GURL
url1(kDefaultURL
);
2176 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2177 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2178 session
, url1
, MEDIUM
, BoundNetLog());
2179 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2180 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2182 GURL
url2(kDefaultURL
);
2183 base::WeakPtr
<SpdyStream
> spdy_stream2
=
2184 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2185 session
, url2
, MEDIUM
, BoundNetLog());
2186 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
2187 EXPECT_EQ(0u, spdy_stream2
->stream_id());
2189 // Make |spdy_stream1| close |spdy_stream2|.
2190 test::ClosingDelegate
delegate1(spdy_stream2
);
2191 spdy_stream1
->SetDelegate(&delegate1
);
2193 // Make |spdy_stream2| close |spdy_stream1|.
2194 test::ClosingDelegate
delegate2(spdy_stream1
);
2195 spdy_stream2
->SetDelegate(&delegate2
);
2197 scoped_ptr
<SpdyHeaderBlock
> headers(
2198 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2199 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
2200 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2202 scoped_ptr
<SpdyHeaderBlock
> headers2(
2203 spdy_util_
.ConstructGetHeaderBlock(url2
.spec()));
2204 spdy_stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
2205 EXPECT_TRUE(spdy_stream2
->HasUrlFromHeaders());
2207 // Ensure that the streams have not yet been activated and assigned an id.
2208 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2209 EXPECT_EQ(0u, spdy_stream2
->stream_id());
2213 EXPECT_EQ(1u, spdy_stream1
->stream_id());
2214 EXPECT_EQ(3u, spdy_stream2
->stream_id());
2216 // Ensure we don't crash while closing the session.
2217 session
->CloseSessionOnError(ERR_ABORTED
, std::string());
2219 EXPECT_EQ(NULL
, spdy_stream1
.get());
2220 EXPECT_EQ(NULL
, spdy_stream2
.get());
2222 EXPECT_TRUE(delegate1
.StreamIsClosed());
2223 EXPECT_TRUE(delegate2
.StreamIsClosed());
2225 base::MessageLoop::current()->RunUntilIdle();
2226 EXPECT_TRUE(session
== NULL
);
2229 // Delegate that closes a given session when the stream is closed.
2230 class SessionClosingDelegate
: public test::StreamDelegateDoNothing
{
2232 SessionClosingDelegate(const base::WeakPtr
<SpdyStream
>& stream
,
2233 const base::WeakPtr
<SpdySession
>& session_to_close
)
2234 : StreamDelegateDoNothing(stream
),
2235 session_to_close_(session_to_close
) {}
2237 virtual ~SessionClosingDelegate() {}
2239 virtual void OnClose(int status
) OVERRIDE
{
2240 session_to_close_
->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR
, "Error");
2244 base::WeakPtr
<SpdySession
> session_to_close_
;
2247 // Close an activated stream that closes its session. Nothing should
2248 // blow up. This is a regression test for http://crbug.com/263691 .
2249 TEST_P(SpdySessionTest
, CloseActivatedStreamThatClosesSession
) {
2250 session_deps_
.host_resolver
->set_synchronous_mode(true);
2252 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2254 scoped_ptr
<SpdyFrame
> req(
2255 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
2256 scoped_ptr
<SpdyFrame
> rst(
2257 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
2258 scoped_ptr
<SpdyFrame
> goaway(
2259 spdy_util_
.ConstructSpdyGoAway(0, GOAWAY_PROTOCOL_ERROR
, "Error"));
2260 // The GOAWAY has higher-priority than the RST_STREAM, and is written first
2261 // despite being queued second.
2262 MockWrite writes
[] = {
2263 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 1),
2264 CreateMockWrite(*rst
, 2),
2267 MockRead reads
[] = {
2268 MockRead(ASYNC
, 0, 3) // EOF
2270 DeterministicSocketData
data(reads
, arraysize(reads
),
2271 writes
, arraysize(writes
));
2272 data
.set_connect_data(connect_data
);
2273 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2275 CreateDeterministicNetworkSession();
2277 base::WeakPtr
<SpdySession
> session
=
2278 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2280 GURL
url(kDefaultURL
);
2281 base::WeakPtr
<SpdyStream
> spdy_stream
=
2282 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2283 session
, url
, MEDIUM
, BoundNetLog());
2284 ASSERT_TRUE(spdy_stream
.get() != NULL
);
2285 EXPECT_EQ(0u, spdy_stream
->stream_id());
2287 SessionClosingDelegate
delegate(spdy_stream
, session
);
2288 spdy_stream
->SetDelegate(&delegate
);
2290 scoped_ptr
<SpdyHeaderBlock
> headers(
2291 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
2292 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
2293 EXPECT_TRUE(spdy_stream
->HasUrlFromHeaders());
2295 EXPECT_EQ(0u, spdy_stream
->stream_id());
2299 EXPECT_EQ(1u, spdy_stream
->stream_id());
2301 // Ensure we don't crash while closing the stream (which closes the
2303 spdy_stream
->Cancel();
2305 EXPECT_EQ(NULL
, spdy_stream
.get());
2306 EXPECT_TRUE(delegate
.StreamIsClosed());
2308 data
.RunFor(2); // Write the RST_STREAM & GOAWAY.
2309 base::MessageLoop::current()->RunUntilIdle();
2310 EXPECT_TRUE(session
== NULL
);
2313 TEST_P(SpdySessionTest
, VerifyDomainAuthentication
) {
2314 session_deps_
.host_resolver
->set_synchronous_mode(true);
2316 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2318 // No actual data will be sent.
2319 MockWrite writes
[] = {
2320 MockWrite(ASYNC
, 0, 1) // EOF
2323 MockRead reads
[] = {
2324 MockRead(ASYNC
, 0, 0) // EOF
2326 DeterministicSocketData
data(reads
, arraysize(reads
),
2327 writes
, arraysize(writes
));
2328 data
.set_connect_data(connect_data
);
2329 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2331 // Load a cert that is valid for:
2335 base::FilePath certs_dir
= GetTestCertsDirectory();
2336 scoped_refptr
<X509Certificate
> test_cert(
2337 ImportCertFromFile(certs_dir
, "spdy_pooling.pem"));
2338 ASSERT_NE(static_cast<X509Certificate
*>(NULL
), test_cert
);
2340 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
2341 ssl
.cert
= test_cert
;
2342 session_deps_
.deterministic_socket_factory
->AddSSLSocketDataProvider(&ssl
);
2344 CreateDeterministicNetworkSession();
2346 base::WeakPtr
<SpdySession
> session
=
2347 CreateSecureSpdySession(http_session_
, key_
, BoundNetLog());
2349 EXPECT_TRUE(session
->VerifyDomainAuthentication("www.example.org"));
2350 EXPECT_TRUE(session
->VerifyDomainAuthentication("mail.example.org"));
2351 EXPECT_TRUE(session
->VerifyDomainAuthentication("mail.example.com"));
2352 EXPECT_FALSE(session
->VerifyDomainAuthentication("mail.google.com"));
2355 TEST_P(SpdySessionTest
, ConnectionPooledWithTlsChannelId
) {
2356 session_deps_
.host_resolver
->set_synchronous_mode(true);
2358 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2360 // No actual data will be sent.
2361 MockWrite writes
[] = {
2362 MockWrite(ASYNC
, 0, 1) // EOF
2365 MockRead reads
[] = {
2366 MockRead(ASYNC
, 0, 0) // EOF
2368 DeterministicSocketData
data(reads
, arraysize(reads
),
2369 writes
, arraysize(writes
));
2370 data
.set_connect_data(connect_data
);
2371 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2373 // Load a cert that is valid for:
2377 base::FilePath certs_dir
= GetTestCertsDirectory();
2378 scoped_refptr
<X509Certificate
> test_cert(
2379 ImportCertFromFile(certs_dir
, "spdy_pooling.pem"));
2380 ASSERT_NE(static_cast<X509Certificate
*>(NULL
), test_cert
);
2382 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
2383 ssl
.channel_id_sent
= true;
2384 ssl
.cert
= test_cert
;
2385 session_deps_
.deterministic_socket_factory
->AddSSLSocketDataProvider(&ssl
);
2387 CreateDeterministicNetworkSession();
2389 base::WeakPtr
<SpdySession
> session
=
2390 CreateSecureSpdySession(http_session_
, key_
, BoundNetLog());
2392 EXPECT_TRUE(session
->VerifyDomainAuthentication("www.example.org"));
2393 EXPECT_TRUE(session
->VerifyDomainAuthentication("mail.example.org"));
2394 EXPECT_FALSE(session
->VerifyDomainAuthentication("mail.example.com"));
2395 EXPECT_FALSE(session
->VerifyDomainAuthentication("mail.google.com"));
2398 TEST_P(SpdySessionTest
, CloseTwoStalledCreateStream
) {
2399 // TODO(rtenneti): Define a helper class/methods and move the common code in
2401 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2403 SettingsMap new_settings
;
2404 const SpdySettingsIds kSpdySettingsIds1
= SETTINGS_MAX_CONCURRENT_STREAMS
;
2405 const uint32 max_concurrent_streams
= 1;
2406 new_settings
[kSpdySettingsIds1
] =
2407 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, max_concurrent_streams
);
2409 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
2410 scoped_ptr
<SpdyFrame
> req1(
2411 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
2412 scoped_ptr
<SpdyFrame
> req2(
2413 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 3, LOWEST
, true));
2414 scoped_ptr
<SpdyFrame
> req3(
2415 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 5, LOWEST
, true));
2416 MockWrite writes
[] = {
2417 CreateMockWrite(*settings_ack
, 1),
2418 CreateMockWrite(*req1
, 2),
2419 CreateMockWrite(*req2
, 5),
2420 CreateMockWrite(*req3
, 8),
2423 // Set up the socket so we read a SETTINGS frame that sets max concurrent
2425 scoped_ptr
<SpdyFrame
> settings_frame(
2426 spdy_util_
.ConstructSpdySettings(new_settings
));
2428 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2429 scoped_ptr
<SpdyFrame
> body1(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2431 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
2432 scoped_ptr
<SpdyFrame
> body2(spdy_util_
.ConstructSpdyBodyFrame(3, true));
2434 scoped_ptr
<SpdyFrame
> resp3(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 5));
2435 scoped_ptr
<SpdyFrame
> body3(spdy_util_
.ConstructSpdyBodyFrame(5, true));
2437 MockRead reads
[] = {
2438 CreateMockRead(*settings_frame
),
2439 CreateMockRead(*resp1
, 3),
2440 CreateMockRead(*body1
, 4),
2441 CreateMockRead(*resp2
, 6),
2442 CreateMockRead(*body2
, 7),
2443 CreateMockRead(*resp3
, 9),
2444 CreateMockRead(*body3
, 10),
2445 MockRead(ASYNC
, 0, 11) // EOF
2448 DeterministicSocketData
data(reads
, arraysize(reads
),
2449 writes
, arraysize(writes
));
2450 data
.set_connect_data(connect_data
);
2451 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2453 CreateDeterministicNetworkSession();
2455 base::WeakPtr
<SpdySession
> session
=
2456 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2458 // Read the settings frame.
2461 GURL
url1(kDefaultURL
);
2462 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2463 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2464 session
, url1
, LOWEST
, BoundNetLog());
2465 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2466 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2467 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
2468 spdy_stream1
->SetDelegate(&delegate1
);
2470 TestCompletionCallback callback2
;
2471 GURL
url2(kDefaultURL
);
2472 SpdyStreamRequest request2
;
2473 ASSERT_EQ(ERR_IO_PENDING
,
2474 request2
.StartRequest(
2475 SPDY_REQUEST_RESPONSE_STREAM
,
2476 session
, url2
, LOWEST
, BoundNetLog(), callback2
.callback()));
2478 TestCompletionCallback callback3
;
2479 GURL
url3(kDefaultURL
);
2480 SpdyStreamRequest request3
;
2481 ASSERT_EQ(ERR_IO_PENDING
,
2482 request3
.StartRequest(
2483 SPDY_REQUEST_RESPONSE_STREAM
,
2484 session
, url3
, LOWEST
, BoundNetLog(), callback3
.callback()));
2486 EXPECT_EQ(0u, session
->num_active_streams());
2487 EXPECT_EQ(1u, session
->num_created_streams());
2488 EXPECT_EQ(2u, session
->pending_create_stream_queue_size(LOWEST
));
2490 scoped_ptr
<SpdyHeaderBlock
> headers(
2491 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2492 spdy_stream1
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
2493 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2495 // Run until 1st stream is activated and then closed.
2496 EXPECT_EQ(0u, delegate1
.stream_id());
2498 EXPECT_EQ(NULL
, spdy_stream1
.get());
2499 EXPECT_EQ(1u, delegate1
.stream_id());
2501 EXPECT_EQ(0u, session
->num_active_streams());
2502 EXPECT_EQ(0u, session
->num_created_streams());
2503 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(LOWEST
));
2505 // Pump loop for SpdySession::ProcessPendingStreamRequests() to
2506 // create the 2nd stream.
2507 base::MessageLoop::current()->RunUntilIdle();
2509 EXPECT_EQ(0u, session
->num_active_streams());
2510 EXPECT_EQ(1u, session
->num_created_streams());
2511 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(LOWEST
));
2513 base::WeakPtr
<SpdyStream
> stream2
= request2
.ReleaseStream();
2514 test::StreamDelegateDoNothing
delegate2(stream2
);
2515 stream2
->SetDelegate(&delegate2
);
2516 scoped_ptr
<SpdyHeaderBlock
> headers2(
2517 spdy_util_
.ConstructGetHeaderBlock(url2
.spec()));
2518 stream2
->SendRequestHeaders(headers2
.Pass(), NO_MORE_DATA_TO_SEND
);
2519 EXPECT_TRUE(stream2
->HasUrlFromHeaders());
2521 // Run until 2nd stream is activated and then closed.
2522 EXPECT_EQ(0u, delegate2
.stream_id());
2524 EXPECT_EQ(NULL
, stream2
.get());
2525 EXPECT_EQ(3u, delegate2
.stream_id());
2527 EXPECT_EQ(0u, session
->num_active_streams());
2528 EXPECT_EQ(0u, session
->num_created_streams());
2529 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(LOWEST
));
2531 // Pump loop for SpdySession::ProcessPendingStreamRequests() to
2532 // create the 3rd stream.
2533 base::MessageLoop::current()->RunUntilIdle();
2535 EXPECT_EQ(0u, session
->num_active_streams());
2536 EXPECT_EQ(1u, session
->num_created_streams());
2537 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(LOWEST
));
2539 base::WeakPtr
<SpdyStream
> stream3
= request3
.ReleaseStream();
2540 test::StreamDelegateDoNothing
delegate3(stream3
);
2541 stream3
->SetDelegate(&delegate3
);
2542 scoped_ptr
<SpdyHeaderBlock
> headers3(
2543 spdy_util_
.ConstructGetHeaderBlock(url3
.spec()));
2544 stream3
->SendRequestHeaders(headers3
.Pass(), NO_MORE_DATA_TO_SEND
);
2545 EXPECT_TRUE(stream3
->HasUrlFromHeaders());
2547 // Run until 2nd stream is activated and then closed.
2548 EXPECT_EQ(0u, delegate3
.stream_id());
2550 EXPECT_EQ(NULL
, stream3
.get());
2551 EXPECT_EQ(5u, delegate3
.stream_id());
2553 EXPECT_EQ(0u, session
->num_active_streams());
2554 EXPECT_EQ(0u, session
->num_created_streams());
2555 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(LOWEST
));
2560 TEST_P(SpdySessionTest
, CancelTwoStalledCreateStream
) {
2561 session_deps_
.host_resolver
->set_synchronous_mode(true);
2563 MockRead reads
[] = {
2564 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
2567 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
2568 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2570 data
.set_connect_data(connect_data
);
2571 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
2573 CreateNetworkSession();
2575 base::WeakPtr
<SpdySession
> session
=
2576 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2578 // Leave room for only one more stream to be created.
2579 for (size_t i
= 0; i
< kInitialMaxConcurrentStreams
- 1; ++i
) {
2580 base::WeakPtr
<SpdyStream
> spdy_stream
=
2581 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
2582 session
, test_url_
, MEDIUM
, BoundNetLog());
2583 ASSERT_TRUE(spdy_stream
!= NULL
);
2586 GURL
url1(kDefaultURL
);
2587 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2588 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
2589 session
, url1
, LOWEST
, BoundNetLog());
2590 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2591 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2593 TestCompletionCallback callback2
;
2594 GURL
url2(kDefaultURL
);
2595 SpdyStreamRequest request2
;
2596 ASSERT_EQ(ERR_IO_PENDING
,
2597 request2
.StartRequest(
2598 SPDY_BIDIRECTIONAL_STREAM
, session
, url2
, LOWEST
, BoundNetLog(),
2599 callback2
.callback()));
2601 TestCompletionCallback callback3
;
2602 GURL
url3(kDefaultURL
);
2603 SpdyStreamRequest request3
;
2604 ASSERT_EQ(ERR_IO_PENDING
,
2605 request3
.StartRequest(
2606 SPDY_BIDIRECTIONAL_STREAM
, session
, url3
, LOWEST
, BoundNetLog(),
2607 callback3
.callback()));
2609 EXPECT_EQ(0u, session
->num_active_streams());
2610 EXPECT_EQ(kInitialMaxConcurrentStreams
, session
->num_created_streams());
2611 EXPECT_EQ(2u, session
->pending_create_stream_queue_size(LOWEST
));
2613 // Cancel the first stream; this will allow the second stream to be created.
2614 EXPECT_TRUE(spdy_stream1
.get() != NULL
);
2615 spdy_stream1
->Cancel();
2616 EXPECT_EQ(NULL
, spdy_stream1
.get());
2618 EXPECT_EQ(OK
, callback2
.WaitForResult());
2619 EXPECT_EQ(0u, session
->num_active_streams());
2620 EXPECT_EQ(kInitialMaxConcurrentStreams
, session
->num_created_streams());
2621 EXPECT_EQ(1u, session
->pending_create_stream_queue_size(LOWEST
));
2623 // Cancel the second stream; this will allow the third stream to be created.
2624 base::WeakPtr
<SpdyStream
> spdy_stream2
= request2
.ReleaseStream();
2625 spdy_stream2
->Cancel();
2626 EXPECT_EQ(NULL
, spdy_stream2
.get());
2628 EXPECT_EQ(OK
, callback3
.WaitForResult());
2629 EXPECT_EQ(0u, session
->num_active_streams());
2630 EXPECT_EQ(kInitialMaxConcurrentStreams
, session
->num_created_streams());
2631 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(LOWEST
));
2633 // Cancel the third stream.
2634 base::WeakPtr
<SpdyStream
> spdy_stream3
= request3
.ReleaseStream();
2635 spdy_stream3
->Cancel();
2636 EXPECT_EQ(NULL
, spdy_stream3
.get());
2637 EXPECT_EQ(0u, session
->num_active_streams());
2638 EXPECT_EQ(kInitialMaxConcurrentStreams
- 1, session
->num_created_streams());
2639 EXPECT_EQ(0u, session
->pending_create_stream_queue_size(LOWEST
));
2642 // Test that SpdySession::DoReadLoop reads data from the socket
2643 // without yielding. This test makes 32k - 1 bytes of data available
2644 // on the socket for reading. It then verifies that it has read all
2645 // the available data without yielding.
2646 TEST_P(SpdySessionTest
, ReadDataWithoutYielding
) {
2647 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2648 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
2650 scoped_ptr
<SpdyFrame
> req1(
2651 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
2652 MockWrite writes
[] = {
2653 CreateMockWrite(*req1
, 0),
2656 // Build buffer of size kMaxReadBytesWithoutYielding / 4
2657 // (-spdy_data_frame_size).
2658 ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding
);
2659 const int kPayloadSize
=
2660 kMaxReadBytesWithoutYielding
/ 4 - framer
.GetControlFrameHeaderSize();
2661 TestDataStream test_stream
;
2662 scoped_refptr
<net::IOBuffer
> payload(new net::IOBuffer(kPayloadSize
));
2663 char* payload_data
= payload
->data();
2664 test_stream
.GetBytes(payload_data
, kPayloadSize
);
2666 scoped_ptr
<SpdyFrame
> partial_data_frame(
2667 framer
.CreateDataFrame(1, payload_data
, kPayloadSize
, DATA_FLAG_NONE
));
2668 scoped_ptr
<SpdyFrame
> finish_data_frame(
2669 framer
.CreateDataFrame(1, payload_data
, kPayloadSize
- 1, DATA_FLAG_FIN
));
2671 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2673 // Write 1 byte less than kMaxReadBytes to check that DoRead reads up to 32k
2675 MockRead reads
[] = {
2676 CreateMockRead(*resp1
, 1),
2677 CreateMockRead(*partial_data_frame
, 2),
2678 CreateMockRead(*partial_data_frame
, 3, SYNCHRONOUS
),
2679 CreateMockRead(*partial_data_frame
, 4, SYNCHRONOUS
),
2680 CreateMockRead(*finish_data_frame
, 5, SYNCHRONOUS
),
2681 MockRead(ASYNC
, 0, 6) // EOF
2684 // Create SpdySession and SpdyStream and send the request.
2685 DeterministicSocketData
data(reads
, arraysize(reads
),
2686 writes
, arraysize(writes
));
2687 data
.set_connect_data(connect_data
);
2688 session_deps_
.host_resolver
->set_synchronous_mode(true);
2689 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2691 CreateDeterministicNetworkSession();
2693 base::WeakPtr
<SpdySession
> session
=
2694 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2696 GURL
url1(kDefaultURL
);
2697 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2698 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2699 session
, url1
, MEDIUM
, BoundNetLog());
2700 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2701 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2702 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
2703 spdy_stream1
->SetDelegate(&delegate1
);
2705 scoped_ptr
<SpdyHeaderBlock
> headers1(
2706 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2707 spdy_stream1
->SendRequestHeaders(headers1
.Pass(), NO_MORE_DATA_TO_SEND
);
2708 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2710 // Set up the TaskObserver to verify SpdySession::DoReadLoop doesn't
2712 SpdySessionTestTaskObserver
observer("spdy_session.cc", "DoReadLoop");
2714 // Run until 1st read.
2715 EXPECT_EQ(0u, delegate1
.stream_id());
2717 EXPECT_EQ(1u, delegate1
.stream_id());
2718 EXPECT_EQ(0u, observer
.executed_count());
2720 // Read all the data and verify SpdySession::DoReadLoop has not
2723 EXPECT_EQ(NULL
, spdy_stream1
.get());
2725 // Verify task observer's executed_count is zero, which indicates DoRead read
2726 // all the available data.
2727 EXPECT_EQ(0u, observer
.executed_count());
2728 EXPECT_TRUE(data
.at_write_eof());
2729 EXPECT_TRUE(data
.at_read_eof());
2732 // Test that SpdySession::DoReadLoop yields while reading the
2733 // data. This test makes 32k + 1 bytes of data available on the socket
2734 // for reading. It then verifies that DoRead has yielded even though
2735 // there is data available for it to read (i.e, socket()->Read didn't
2736 // return ERR_IO_PENDING during socket reads).
2737 TEST_P(SpdySessionTest
, TestYieldingDuringReadData
) {
2738 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2739 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
2741 scoped_ptr
<SpdyFrame
> req1(
2742 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
2743 MockWrite writes
[] = {
2744 CreateMockWrite(*req1
, 0),
2747 // Build buffer of size kMaxReadBytesWithoutYielding / 4
2748 // (-spdy_data_frame_size).
2749 ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding
);
2750 const int kPayloadSize
=
2751 kMaxReadBytesWithoutYielding
/ 4 - framer
.GetControlFrameHeaderSize();
2752 TestDataStream test_stream
;
2753 scoped_refptr
<net::IOBuffer
> payload(new net::IOBuffer(kPayloadSize
));
2754 char* payload_data
= payload
->data();
2755 test_stream
.GetBytes(payload_data
, kPayloadSize
);
2757 scoped_ptr
<SpdyFrame
> partial_data_frame(
2758 framer
.CreateDataFrame(1, payload_data
, kPayloadSize
, DATA_FLAG_NONE
));
2759 scoped_ptr
<SpdyFrame
> finish_data_frame(
2760 framer
.CreateDataFrame(1, "h", 1, DATA_FLAG_FIN
));
2762 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2764 // Write 1 byte more than kMaxReadBytes to check that DoRead yields.
2765 MockRead reads
[] = {
2766 CreateMockRead(*resp1
, 1),
2767 CreateMockRead(*partial_data_frame
, 2),
2768 CreateMockRead(*partial_data_frame
, 3, SYNCHRONOUS
),
2769 CreateMockRead(*partial_data_frame
, 4, SYNCHRONOUS
),
2770 CreateMockRead(*partial_data_frame
, 5, SYNCHRONOUS
),
2771 CreateMockRead(*finish_data_frame
, 6, SYNCHRONOUS
),
2772 MockRead(ASYNC
, 0, 7) // EOF
2775 // Create SpdySession and SpdyStream and send the request.
2776 DeterministicSocketData
data(reads
, arraysize(reads
),
2777 writes
, arraysize(writes
));
2778 data
.set_connect_data(connect_data
);
2779 session_deps_
.host_resolver
->set_synchronous_mode(true);
2780 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2782 CreateDeterministicNetworkSession();
2784 base::WeakPtr
<SpdySession
> session
=
2785 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2787 GURL
url1(kDefaultURL
);
2788 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2789 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2790 session
, url1
, MEDIUM
, BoundNetLog());
2791 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2792 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2793 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
2794 spdy_stream1
->SetDelegate(&delegate1
);
2796 scoped_ptr
<SpdyHeaderBlock
> headers1(
2797 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2798 spdy_stream1
->SendRequestHeaders(headers1
.Pass(), NO_MORE_DATA_TO_SEND
);
2799 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2801 // Set up the TaskObserver to verify SpdySession::DoReadLoop posts a
2803 SpdySessionTestTaskObserver
observer("spdy_session.cc", "DoReadLoop");
2805 // Run until 1st read.
2806 EXPECT_EQ(0u, delegate1
.stream_id());
2808 EXPECT_EQ(1u, delegate1
.stream_id());
2809 EXPECT_EQ(0u, observer
.executed_count());
2811 // Read all the data and verify SpdySession::DoReadLoop has posted a
2814 EXPECT_EQ(NULL
, spdy_stream1
.get());
2816 // Verify task observer's executed_count is 1, which indicates DoRead has
2817 // posted only one task and thus yielded though there is data available for it
2819 EXPECT_EQ(1u, observer
.executed_count());
2820 EXPECT_TRUE(data
.at_write_eof());
2821 EXPECT_TRUE(data
.at_read_eof());
2824 // Test that SpdySession::DoReadLoop() tests interactions of yielding
2825 // + async, by doing the following MockReads.
2827 // MockRead of SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K
2828 // ASYNC 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K.
2830 // The above reads 26K synchronously. Since that is less that 32K, we
2831 // will attempt to read again. However, that DoRead() will return
2832 // ERR_IO_PENDING (because of async read), so DoReadLoop() will
2833 // yield. When we come back, DoRead() will read the results from the
2834 // async read, and rest of the data synchronously.
2835 TEST_P(SpdySessionTest
, TestYieldingDuringAsyncReadData
) {
2836 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2837 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
2839 scoped_ptr
<SpdyFrame
> req1(
2840 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
2841 MockWrite writes
[] = {
2842 CreateMockWrite(*req1
, 0),
2845 // Build buffer of size kMaxReadBytesWithoutYielding / 4
2846 // (-spdy_data_frame_size).
2847 ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding
);
2848 TestDataStream test_stream
;
2849 const int kEightKPayloadSize
=
2850 kMaxReadBytesWithoutYielding
/ 4 - framer
.GetControlFrameHeaderSize();
2851 scoped_refptr
<net::IOBuffer
> eightk_payload(
2852 new net::IOBuffer(kEightKPayloadSize
));
2853 char* eightk_payload_data
= eightk_payload
->data();
2854 test_stream
.GetBytes(eightk_payload_data
, kEightKPayloadSize
);
2856 // Build buffer of 2k size.
2857 TestDataStream test_stream2
;
2858 const int kTwoKPayloadSize
= kEightKPayloadSize
- 6 * 1024;
2859 scoped_refptr
<net::IOBuffer
> twok_payload(
2860 new net::IOBuffer(kTwoKPayloadSize
));
2861 char* twok_payload_data
= twok_payload
->data();
2862 test_stream2
.GetBytes(twok_payload_data
, kTwoKPayloadSize
);
2864 scoped_ptr
<SpdyFrame
> eightk_data_frame(framer
.CreateDataFrame(
2865 1, eightk_payload_data
, kEightKPayloadSize
, DATA_FLAG_NONE
));
2866 scoped_ptr
<SpdyFrame
> twok_data_frame(framer
.CreateDataFrame(
2867 1, twok_payload_data
, kTwoKPayloadSize
, DATA_FLAG_NONE
));
2868 scoped_ptr
<SpdyFrame
> finish_data_frame(framer
.CreateDataFrame(
2869 1, "h", 1, DATA_FLAG_FIN
));
2871 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2873 MockRead reads
[] = {
2874 CreateMockRead(*resp1
, 1),
2875 CreateMockRead(*eightk_data_frame
, 2),
2876 CreateMockRead(*eightk_data_frame
, 3, SYNCHRONOUS
),
2877 CreateMockRead(*eightk_data_frame
, 4, SYNCHRONOUS
),
2878 CreateMockRead(*twok_data_frame
, 5, SYNCHRONOUS
),
2879 CreateMockRead(*eightk_data_frame
, 6, ASYNC
),
2880 CreateMockRead(*eightk_data_frame
, 7, SYNCHRONOUS
),
2881 CreateMockRead(*eightk_data_frame
, 8, SYNCHRONOUS
),
2882 CreateMockRead(*eightk_data_frame
, 9, SYNCHRONOUS
),
2883 CreateMockRead(*twok_data_frame
, 10, SYNCHRONOUS
),
2884 CreateMockRead(*finish_data_frame
, 11, SYNCHRONOUS
),
2885 MockRead(ASYNC
, 0, 12) // EOF
2888 // Create SpdySession and SpdyStream and send the request.
2889 DeterministicSocketData
data(reads
, arraysize(reads
),
2890 writes
, arraysize(writes
));
2891 data
.set_connect_data(connect_data
);
2892 session_deps_
.host_resolver
->set_synchronous_mode(true);
2893 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2895 CreateDeterministicNetworkSession();
2897 base::WeakPtr
<SpdySession
> session
=
2898 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2900 GURL
url1(kDefaultURL
);
2901 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2902 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2903 session
, url1
, MEDIUM
, BoundNetLog());
2904 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2905 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2906 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
2907 spdy_stream1
->SetDelegate(&delegate1
);
2909 scoped_ptr
<SpdyHeaderBlock
> headers1(
2910 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2911 spdy_stream1
->SendRequestHeaders(headers1
.Pass(), NO_MORE_DATA_TO_SEND
);
2912 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2914 // Set up the TaskObserver to monitor SpdySession::DoReadLoop
2915 // posting of tasks.
2916 SpdySessionTestTaskObserver
observer("spdy_session.cc", "DoReadLoop");
2918 // Run until 1st read.
2919 EXPECT_EQ(0u, delegate1
.stream_id());
2921 EXPECT_EQ(1u, delegate1
.stream_id());
2922 EXPECT_EQ(0u, observer
.executed_count());
2924 // Read all the data and verify SpdySession::DoReadLoop has posted a
2927 EXPECT_EQ(NULL
, spdy_stream1
.get());
2929 // Verify task observer's executed_count is 1, which indicates DoRead has
2930 // posted only one task and thus yielded though there is data available for
2932 EXPECT_EQ(1u, observer
.executed_count());
2933 EXPECT_TRUE(data
.at_write_eof());
2934 EXPECT_TRUE(data
.at_read_eof());
2937 // Send a GoAway frame when SpdySession is in DoReadLoop. Make sure
2938 // nothing blows up.
2939 TEST_P(SpdySessionTest
, GoAwayWhileInDoReadLoop
) {
2940 MockConnect
connect_data(SYNCHRONOUS
, OK
);
2941 BufferedSpdyFramer
framer(spdy_util_
.spdy_version(), false);
2943 scoped_ptr
<SpdyFrame
> req1(
2944 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
2945 MockWrite writes
[] = {
2946 CreateMockWrite(*req1
, 0),
2949 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
2950 scoped_ptr
<SpdyFrame
> body1(spdy_util_
.ConstructSpdyBodyFrame(1, true));
2951 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway());
2953 MockRead reads
[] = {
2954 CreateMockRead(*resp1
, 1),
2955 CreateMockRead(*body1
, 2),
2956 CreateMockRead(*goaway
, 3),
2959 // Create SpdySession and SpdyStream and send the request.
2960 DeterministicSocketData
data(reads
, arraysize(reads
),
2961 writes
, arraysize(writes
));
2962 data
.set_connect_data(connect_data
);
2963 session_deps_
.host_resolver
->set_synchronous_mode(true);
2964 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
2966 CreateDeterministicNetworkSession();
2968 base::WeakPtr
<SpdySession
> session
=
2969 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
2971 GURL
url1(kDefaultURL
);
2972 base::WeakPtr
<SpdyStream
> spdy_stream1
=
2973 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
2974 session
, url1
, MEDIUM
, BoundNetLog());
2975 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
2976 spdy_stream1
->SetDelegate(&delegate1
);
2977 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
2978 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2980 scoped_ptr
<SpdyHeaderBlock
> headers1(
2981 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
2982 spdy_stream1
->SendRequestHeaders(headers1
.Pass(), NO_MORE_DATA_TO_SEND
);
2983 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
2985 // Run until 1st read.
2986 EXPECT_EQ(0u, spdy_stream1
->stream_id());
2988 EXPECT_EQ(1u, spdy_stream1
->stream_id());
2990 // Run until GoAway.
2992 EXPECT_EQ(NULL
, spdy_stream1
.get());
2993 EXPECT_TRUE(data
.at_write_eof());
2994 EXPECT_TRUE(data
.at_read_eof());
2995 EXPECT_TRUE(session
== NULL
);
2998 // Within this framework, a SpdySession should be initialized with
2999 // flow control disabled for protocol version 2, with flow control
3000 // enabled only for streams for protocol version 3, and with flow
3001 // control enabled for streams and sessions for higher versions.
3002 TEST_P(SpdySessionTest
, ProtocolNegotiation
) {
3003 session_deps_
.host_resolver
->set_synchronous_mode(true);
3005 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3006 MockRead reads
[] = {
3007 MockRead(SYNCHRONOUS
, 0, 0) // EOF
3009 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
3010 data
.set_connect_data(connect_data
);
3011 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
3013 CreateNetworkSession();
3014 base::WeakPtr
<SpdySession
> session
=
3015 CreateFakeSpdySession(spdy_session_pool_
, key_
);
3017 EXPECT_EQ(spdy_util_
.spdy_version(),
3018 session
->buffered_spdy_framer_
->protocol_version());
3019 if (GetParam() == kProtoDeprecatedSPDY2
) {
3020 EXPECT_EQ(SpdySession::FLOW_CONTROL_NONE
, session
->flow_control_state());
3021 EXPECT_EQ(0, session
->session_send_window_size_
);
3022 EXPECT_EQ(0, session
->session_recv_window_size_
);
3023 } else if (GetParam() == kProtoSPDY3
) {
3024 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM
, session
->flow_control_state());
3025 EXPECT_EQ(0, session
->session_send_window_size_
);
3026 EXPECT_EQ(0, session
->session_recv_window_size_
);
3028 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
3029 session
->flow_control_state());
3030 EXPECT_EQ(kSpdySessionInitialWindowSize
,
3031 session
->session_send_window_size_
);
3032 EXPECT_EQ(kSpdySessionInitialWindowSize
,
3033 session
->session_recv_window_size_
);
3035 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3038 // Tests the case of a non-SPDY request closing an idle SPDY session when no
3039 // pointers to the idle session are currently held.
3040 TEST_P(SpdySessionTest
, CloseOneIdleConnection
) {
3041 ClientSocketPoolManager::set_max_sockets_per_group(
3042 HttpNetworkSession::NORMAL_SOCKET_POOL
, 1);
3043 ClientSocketPoolManager::set_max_sockets_per_pool(
3044 HttpNetworkSession::NORMAL_SOCKET_POOL
, 1);
3046 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3047 MockRead reads
[] = {
3048 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
3050 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
3051 data
.set_connect_data(connect_data
);
3052 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
3053 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
3055 CreateNetworkSession();
3057 TransportClientSocketPool
* pool
=
3058 http_session_
->GetTransportSocketPool(
3059 HttpNetworkSession::NORMAL_SOCKET_POOL
);
3061 // Create an idle SPDY session.
3062 SpdySessionKey
key1(HostPortPair("1.com", 80), ProxyServer::Direct(),
3063 PRIVACY_MODE_DISABLED
);
3064 base::WeakPtr
<SpdySession
> session1
=
3065 CreateInsecureSpdySession(http_session_
, key1
, BoundNetLog());
3066 EXPECT_FALSE(pool
->IsStalled());
3068 // Trying to create a new connection should cause the pool to be stalled, and
3069 // post a task asynchronously to try and close the session.
3070 TestCompletionCallback callback2
;
3071 HostPortPair
host_port2("2.com", 80);
3072 scoped_refptr
<TransportSocketParams
> params2(
3073 new TransportSocketParams(host_port2
, false, false,
3074 OnHostResolutionCallback()));
3075 scoped_ptr
<ClientSocketHandle
> connection2(new ClientSocketHandle
);
3076 EXPECT_EQ(ERR_IO_PENDING
,
3077 connection2
->Init(host_port2
.ToString(), params2
, DEFAULT_PRIORITY
,
3078 callback2
.callback(), pool
, BoundNetLog()));
3079 EXPECT_TRUE(pool
->IsStalled());
3081 // The socket pool should close the connection asynchronously and establish a
3083 EXPECT_EQ(OK
, callback2
.WaitForResult());
3084 EXPECT_FALSE(pool
->IsStalled());
3085 EXPECT_TRUE(session1
== NULL
);
3088 // Tests the case of a non-SPDY request closing an idle SPDY session when no
3089 // pointers to the idle session are currently held, in the case the SPDY session
3091 TEST_P(SpdySessionTest
, CloseOneIdleConnectionWithAlias
) {
3092 ClientSocketPoolManager::set_max_sockets_per_group(
3093 HttpNetworkSession::NORMAL_SOCKET_POOL
, 1);
3094 ClientSocketPoolManager::set_max_sockets_per_pool(
3095 HttpNetworkSession::NORMAL_SOCKET_POOL
, 1);
3097 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3098 MockRead reads
[] = {
3099 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
3101 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
3102 data
.set_connect_data(connect_data
);
3103 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
3104 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
3106 session_deps_
.host_resolver
->set_synchronous_mode(true);
3107 session_deps_
.host_resolver
->rules()->AddIPLiteralRule(
3108 "1.com", "192.168.0.2", std::string());
3109 session_deps_
.host_resolver
->rules()->AddIPLiteralRule(
3110 "2.com", "192.168.0.2", std::string());
3111 // Not strictly needed.
3112 session_deps_
.host_resolver
->rules()->AddIPLiteralRule(
3113 "3.com", "192.168.0.3", std::string());
3115 CreateNetworkSession();
3117 TransportClientSocketPool
* pool
=
3118 http_session_
->GetTransportSocketPool(
3119 HttpNetworkSession::NORMAL_SOCKET_POOL
);
3121 // Create an idle SPDY session.
3122 SpdySessionKey
key1(HostPortPair("1.com", 80), ProxyServer::Direct(),
3123 PRIVACY_MODE_DISABLED
);
3124 base::WeakPtr
<SpdySession
> session1
=
3125 CreateInsecureSpdySession(http_session_
, key1
, BoundNetLog());
3126 EXPECT_FALSE(pool
->IsStalled());
3128 // Set up an alias for the idle SPDY session, increasing its ref count to 2.
3129 SpdySessionKey
key2(HostPortPair("2.com", 80), ProxyServer::Direct(),
3130 PRIVACY_MODE_DISABLED
);
3131 HostResolver::RequestInfo
info(key2
.host_port_pair());
3132 AddressList addresses
;
3133 // Pre-populate the DNS cache, since a synchronous resolution is required in
3134 // order to create the alias.
3135 session_deps_
.host_resolver
->Resolve(info
,
3138 CompletionCallback(),
3141 // Get a session for |key2|, which should return the session created earlier.
3142 base::WeakPtr
<SpdySession
> session2
=
3143 spdy_session_pool_
->FindAvailableSession(key2
, BoundNetLog());
3144 ASSERT_EQ(session1
.get(), session2
.get());
3145 EXPECT_FALSE(pool
->IsStalled());
3147 // Trying to create a new connection should cause the pool to be stalled, and
3148 // post a task asynchronously to try and close the session.
3149 TestCompletionCallback callback3
;
3150 HostPortPair
host_port3("3.com", 80);
3151 scoped_refptr
<TransportSocketParams
> params3(
3152 new TransportSocketParams(host_port3
, false, false,
3153 OnHostResolutionCallback()));
3154 scoped_ptr
<ClientSocketHandle
> connection3(new ClientSocketHandle
);
3155 EXPECT_EQ(ERR_IO_PENDING
,
3156 connection3
->Init(host_port3
.ToString(), params3
, DEFAULT_PRIORITY
,
3157 callback3
.callback(), pool
, BoundNetLog()));
3158 EXPECT_TRUE(pool
->IsStalled());
3160 // The socket pool should close the connection asynchronously and establish a
3162 EXPECT_EQ(OK
, callback3
.WaitForResult());
3163 EXPECT_FALSE(pool
->IsStalled());
3164 EXPECT_TRUE(session1
== NULL
);
3165 EXPECT_TRUE(session2
== NULL
);
3168 // Tests that when a SPDY session becomes idle, it closes itself if there is
3169 // a lower layer pool stalled on the per-pool socket limit.
3170 TEST_P(SpdySessionTest
, CloseSessionOnIdleWhenPoolStalled
) {
3171 ClientSocketPoolManager::set_max_sockets_per_group(
3172 HttpNetworkSession::NORMAL_SOCKET_POOL
, 1);
3173 ClientSocketPoolManager::set_max_sockets_per_pool(
3174 HttpNetworkSession::NORMAL_SOCKET_POOL
, 1);
3176 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3177 MockRead reads
[] = {
3178 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
3180 scoped_ptr
<SpdyFrame
> req1(
3181 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
3182 scoped_ptr
<SpdyFrame
> cancel1(
3183 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_CANCEL
));
3184 MockWrite writes
[] = {
3185 CreateMockWrite(*req1
, 1),
3186 CreateMockWrite(*cancel1
, 1),
3188 StaticSocketDataProvider
data(reads
, arraysize(reads
),
3189 writes
, arraysize(writes
));
3190 data
.set_connect_data(connect_data
);
3191 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
3193 MockRead http_reads
[] = {
3194 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
) // Stall forever.
3196 StaticSocketDataProvider
http_data(http_reads
, arraysize(http_reads
),
3198 http_data
.set_connect_data(connect_data
);
3199 session_deps_
.socket_factory
->AddSocketDataProvider(&http_data
);
3202 CreateNetworkSession();
3204 TransportClientSocketPool
* pool
=
3205 http_session_
->GetTransportSocketPool(
3206 HttpNetworkSession::NORMAL_SOCKET_POOL
);
3208 // Create a SPDY session.
3209 GURL
url1(kDefaultURL
);
3210 SpdySessionKey
key1(HostPortPair(url1
.host(), 80),
3211 ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
3212 base::WeakPtr
<SpdySession
> session1
=
3213 CreateInsecureSpdySession(http_session_
, key1
, BoundNetLog());
3214 EXPECT_FALSE(pool
->IsStalled());
3216 // Create a stream using the session, and send a request.
3218 TestCompletionCallback callback1
;
3219 base::WeakPtr
<SpdyStream
> spdy_stream1
=
3220 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
3221 session1
, url1
, DEFAULT_PRIORITY
,
3223 ASSERT_TRUE(spdy_stream1
.get());
3224 test::StreamDelegateDoNothing
delegate1(spdy_stream1
);
3225 spdy_stream1
->SetDelegate(&delegate1
);
3227 scoped_ptr
<SpdyHeaderBlock
> headers1(
3228 spdy_util_
.ConstructGetHeaderBlock(url1
.spec()));
3229 EXPECT_EQ(ERR_IO_PENDING
,
3230 spdy_stream1
->SendRequestHeaders(
3231 headers1
.Pass(), NO_MORE_DATA_TO_SEND
));
3232 EXPECT_TRUE(spdy_stream1
->HasUrlFromHeaders());
3234 base::MessageLoop::current()->RunUntilIdle();
3236 // Trying to create a new connection should cause the pool to be stalled, and
3237 // post a task asynchronously to try and close the session.
3238 TestCompletionCallback callback2
;
3239 HostPortPair
host_port2("2.com", 80);
3240 scoped_refptr
<TransportSocketParams
> params2(
3241 new TransportSocketParams(host_port2
, false, false,
3242 OnHostResolutionCallback()));
3243 scoped_ptr
<ClientSocketHandle
> connection2(new ClientSocketHandle
);
3244 EXPECT_EQ(ERR_IO_PENDING
,
3245 connection2
->Init(host_port2
.ToString(), params2
, DEFAULT_PRIORITY
,
3246 callback2
.callback(), pool
, BoundNetLog()));
3247 EXPECT_TRUE(pool
->IsStalled());
3249 // Running the message loop should cause the socket pool to ask the SPDY
3250 // session to close an idle socket, but since the socket is in use, nothing
3252 base::RunLoop().RunUntilIdle();
3253 EXPECT_TRUE(pool
->IsStalled());
3254 EXPECT_FALSE(callback2
.have_result());
3256 // Cancelling the request should result in the session's socket being
3257 // closed, since the pool is stalled.
3258 ASSERT_TRUE(spdy_stream1
.get());
3259 spdy_stream1
->Cancel();
3260 base::RunLoop().RunUntilIdle();
3261 ASSERT_FALSE(pool
->IsStalled());
3262 EXPECT_EQ(OK
, callback2
.WaitForResult());
3265 // Verify that SpdySessionKey and therefore SpdySession is different when
3266 // privacy mode is enabled or disabled.
3267 TEST_P(SpdySessionTest
, SpdySessionKeyPrivacyMode
) {
3268 CreateDeterministicNetworkSession();
3270 HostPortPair
host_port_pair("www.google.com", 443);
3271 SpdySessionKey
key_privacy_enabled(host_port_pair
, ProxyServer::Direct(),
3272 PRIVACY_MODE_ENABLED
);
3273 SpdySessionKey
key_privacy_disabled(host_port_pair
, ProxyServer::Direct(),
3274 PRIVACY_MODE_DISABLED
);
3276 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_privacy_enabled
));
3277 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_privacy_disabled
));
3279 // Add SpdySession with PrivacyMode Enabled to the pool.
3280 base::WeakPtr
<SpdySession
> session_privacy_enabled
=
3281 CreateFakeSpdySession(spdy_session_pool_
, key_privacy_enabled
);
3283 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_privacy_enabled
));
3284 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_privacy_disabled
));
3286 // Add SpdySession with PrivacyMode Disabled to the pool.
3287 base::WeakPtr
<SpdySession
> session_privacy_disabled
=
3288 CreateFakeSpdySession(spdy_session_pool_
, key_privacy_disabled
);
3290 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_privacy_enabled
));
3291 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_privacy_disabled
));
3293 session_privacy_enabled
->CloseSessionOnError(ERR_ABORTED
, std::string());
3294 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_privacy_enabled
));
3295 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_privacy_disabled
));
3297 session_privacy_disabled
->CloseSessionOnError(ERR_ABORTED
, std::string());
3298 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_privacy_enabled
));
3299 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_privacy_disabled
));
3302 // Delegate that creates another stream when its stream is closed.
3303 class StreamCreatingDelegate
: public test::StreamDelegateDoNothing
{
3305 StreamCreatingDelegate(const base::WeakPtr
<SpdyStream
>& stream
,
3306 const base::WeakPtr
<SpdySession
>& session
)
3307 : StreamDelegateDoNothing(stream
),
3308 session_(session
) {}
3310 virtual ~StreamCreatingDelegate() {}
3312 virtual void OnClose(int status
) OVERRIDE
{
3313 GURL
url(kDefaultURL
);
3315 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
3316 session_
, url
, MEDIUM
, BoundNetLog()));
3320 const base::WeakPtr
<SpdySession
> session_
;
3323 // Create another stream in response to a stream being reset. Nothing
3324 // should blow up. This is a regression test for
3325 // http://crbug.com/263690 .
3326 TEST_P(SpdySessionTest
, CreateStreamOnStreamReset
) {
3327 session_deps_
.host_resolver
->set_synchronous_mode(true);
3329 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3331 scoped_ptr
<SpdyFrame
> req(
3332 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, MEDIUM
, true));
3333 MockWrite writes
[] = {
3334 CreateMockWrite(*req
, 0),
3337 scoped_ptr
<SpdyFrame
> rst(
3338 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM
));
3339 MockRead reads
[] = {
3340 CreateMockRead(*rst
, 1),
3341 MockRead(ASYNC
, 0, 2) // EOF
3343 DeterministicSocketData
data(reads
, arraysize(reads
),
3344 writes
, arraysize(writes
));
3345 data
.set_connect_data(connect_data
);
3346 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3348 CreateDeterministicNetworkSession();
3350 base::WeakPtr
<SpdySession
> session
=
3351 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3353 GURL
url(kDefaultURL
);
3354 base::WeakPtr
<SpdyStream
> spdy_stream
=
3355 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
3356 session
, url
, MEDIUM
, BoundNetLog());
3357 ASSERT_TRUE(spdy_stream
.get() != NULL
);
3358 EXPECT_EQ(0u, spdy_stream
->stream_id());
3360 StreamCreatingDelegate
delegate(spdy_stream
, session
);
3361 spdy_stream
->SetDelegate(&delegate
);
3363 scoped_ptr
<SpdyHeaderBlock
> headers(
3364 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
3365 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
3366 EXPECT_TRUE(spdy_stream
->HasUrlFromHeaders());
3368 EXPECT_EQ(0u, spdy_stream
->stream_id());
3372 EXPECT_EQ(1u, spdy_stream
->stream_id());
3374 // Cause the stream to be reset, which should cause another stream
3378 EXPECT_EQ(NULL
, spdy_stream
.get());
3379 EXPECT_TRUE(delegate
.StreamIsClosed());
3380 EXPECT_EQ(0u, session
->num_active_streams());
3381 EXPECT_EQ(1u, session
->num_created_streams());
3384 // The tests below are only for SPDY/3 and above.
3386 TEST_P(SpdySessionTest
, UpdateStreamsSendWindowSize
) {
3387 if (GetParam() < kProtoSPDY3
)
3390 // Set SETTINGS_INITIAL_WINDOW_SIZE to a small number so that WINDOW_UPDATE
3392 SettingsMap new_settings
;
3393 int32 window_size
= 1;
3394 new_settings
[SETTINGS_INITIAL_WINDOW_SIZE
] =
3395 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, window_size
);
3397 // Set up the socket so we read a SETTINGS frame that sets
3398 // INITIAL_WINDOW_SIZE.
3399 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3400 scoped_ptr
<SpdyFrame
> settings_frame(
3401 spdy_util_
.ConstructSpdySettings(new_settings
));
3402 MockRead reads
[] = {
3403 CreateMockRead(*settings_frame
, 0),
3404 MockRead(ASYNC
, 0, 1) // EOF
3407 scoped_ptr
<SpdyFrame
> settings_ack(spdy_util_
.ConstructSpdySettingsAck());
3408 MockWrite writes
[] = {
3409 CreateMockWrite(*settings_ack
, 2),
3412 session_deps_
.host_resolver
->set_synchronous_mode(true);
3414 DeterministicSocketData
data(reads
, arraysize(reads
),
3415 writes
, arraysize(writes
));
3416 data
.set_connect_data(connect_data
);
3417 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3419 CreateDeterministicNetworkSession();
3421 base::WeakPtr
<SpdySession
> session
=
3422 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3423 base::WeakPtr
<SpdyStream
> spdy_stream1
=
3424 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
3425 session
, test_url_
, MEDIUM
, BoundNetLog());
3426 ASSERT_TRUE(spdy_stream1
.get() != NULL
);
3427 TestCompletionCallback callback1
;
3428 EXPECT_NE(spdy_stream1
->send_window_size(), window_size
);
3430 data
.RunFor(1); // Process the SETTINGS frame, but not the EOF
3431 base::MessageLoop::current()->RunUntilIdle();
3432 EXPECT_EQ(session
->stream_initial_send_window_size(), window_size
);
3433 EXPECT_EQ(spdy_stream1
->send_window_size(), window_size
);
3435 // Release the first one, this will allow the second to be created.
3436 spdy_stream1
->Cancel();
3437 EXPECT_EQ(NULL
, spdy_stream1
.get());
3439 base::WeakPtr
<SpdyStream
> spdy_stream2
=
3440 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
3441 session
, test_url_
, MEDIUM
, BoundNetLog());
3442 ASSERT_TRUE(spdy_stream2
.get() != NULL
);
3443 EXPECT_EQ(spdy_stream2
->send_window_size(), window_size
);
3444 spdy_stream2
->Cancel();
3445 EXPECT_EQ(NULL
, spdy_stream2
.get());
3448 // The tests below are only for SPDY/3.1 and above.
3450 // SpdySession::{Increase,Decrease}RecvWindowSize should properly
3451 // adjust the session receive window size for SPDY 3.1 and higher. In
3452 // addition, SpdySession::IncreaseRecvWindowSize should trigger
3453 // sending a WINDOW_UPDATE frame for a large enough delta.
3454 TEST_P(SpdySessionTest
, AdjustRecvWindowSize
) {
3455 if (GetParam() < kProtoSPDY31
)
3458 session_deps_
.host_resolver
->set_synchronous_mode(true);
3460 const int32 delta_window_size
= 100;
3462 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3463 MockRead reads
[] = {
3464 MockRead(ASYNC
, 0, 1) // EOF
3466 scoped_ptr
<SpdyFrame
> window_update(
3467 spdy_util_
.ConstructSpdyWindowUpdate(
3468 kSessionFlowControlStreamId
,
3469 kSpdySessionInitialWindowSize
+ delta_window_size
));
3470 MockWrite writes
[] = {
3471 CreateMockWrite(*window_update
, 0),
3473 DeterministicSocketData
data(reads
, arraysize(reads
),
3474 writes
, arraysize(writes
));
3475 data
.set_connect_data(connect_data
);
3476 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3478 CreateDeterministicNetworkSession();
3479 base::WeakPtr
<SpdySession
> session
=
3480 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3481 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
3482 session
->flow_control_state());
3484 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3485 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3487 session
->IncreaseRecvWindowSize(delta_window_size
);
3488 EXPECT_EQ(kSpdySessionInitialWindowSize
+ delta_window_size
,
3489 session
->session_recv_window_size_
);
3490 EXPECT_EQ(delta_window_size
, session
->session_unacked_recv_window_bytes_
);
3492 // Should trigger sending a WINDOW_UPDATE frame.
3493 session
->IncreaseRecvWindowSize(kSpdySessionInitialWindowSize
);
3494 EXPECT_EQ(kSpdySessionInitialWindowSize
+ delta_window_size
+
3495 kSpdySessionInitialWindowSize
,
3496 session
->session_recv_window_size_
);
3497 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3501 // DecreaseRecvWindowSize() expects |in_io_loop_| to be true.
3502 session
->in_io_loop_
= true;
3503 session
->DecreaseRecvWindowSize(
3504 kSpdySessionInitialWindowSize
+ delta_window_size
+
3505 kSpdySessionInitialWindowSize
);
3506 session
->in_io_loop_
= false;
3507 EXPECT_EQ(0, session
->session_recv_window_size_
);
3508 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3511 // SpdySession::{Increase,Decrease}SendWindowSize should properly
3512 // adjust the session send window size when the "enable_spdy_31" flag
3514 TEST_P(SpdySessionTest
, AdjustSendWindowSize
) {
3515 if (GetParam() < kProtoSPDY31
)
3518 session_deps_
.host_resolver
->set_synchronous_mode(true);
3520 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3521 MockRead reads
[] = {
3522 MockRead(SYNCHRONOUS
, 0, 0) // EOF
3524 StaticSocketDataProvider
data(reads
, arraysize(reads
), NULL
, 0);
3525 data
.set_connect_data(connect_data
);
3526 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
3528 CreateNetworkSession();
3529 base::WeakPtr
<SpdySession
> session
=
3530 CreateFakeSpdySession(spdy_session_pool_
, key_
);
3531 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
3532 session
->flow_control_state());
3534 const int32 delta_window_size
= 100;
3536 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3538 session
->IncreaseSendWindowSize(delta_window_size
);
3539 EXPECT_EQ(kSpdySessionInitialWindowSize
+ delta_window_size
,
3540 session
->session_send_window_size_
);
3542 session
->DecreaseSendWindowSize(delta_window_size
);
3543 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3546 // Incoming data for an inactive stream should not cause the session
3547 // receive window size to decrease, but it should cause the unacked
3548 // bytes to increase.
3549 TEST_P(SpdySessionTest
, SessionFlowControlInactiveStream
) {
3550 if (GetParam() < kProtoSPDY31
)
3553 session_deps_
.host_resolver
->set_synchronous_mode(true);
3555 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3556 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyBodyFrame(1, false));
3557 MockRead reads
[] = {
3558 CreateMockRead(*resp
, 0),
3559 MockRead(ASYNC
, 0, 1) // EOF
3561 DeterministicSocketData
data(reads
, arraysize(reads
), NULL
, 0);
3562 data
.set_connect_data(connect_data
);
3563 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3565 CreateDeterministicNetworkSession();
3566 base::WeakPtr
<SpdySession
> session
=
3567 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3568 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
3569 session
->flow_control_state());
3571 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3572 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3576 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3577 EXPECT_EQ(kUploadDataSize
, session
->session_unacked_recv_window_bytes_
);
3582 // A delegate that drops any received data.
3583 class DropReceivedDataDelegate
: public test::StreamDelegateSendImmediate
{
3585 DropReceivedDataDelegate(const base::WeakPtr
<SpdyStream
>& stream
,
3586 base::StringPiece data
)
3587 : StreamDelegateSendImmediate(stream
, data
) {}
3589 virtual ~DropReceivedDataDelegate() {}
3591 // Drop any received data.
3592 virtual void OnDataReceived(scoped_ptr
<SpdyBuffer
> buffer
) OVERRIDE
{}
3595 // Send data back and forth but use a delegate that drops its received
3596 // data. The receive window should still increase to its original
3597 // value, i.e. we shouldn't "leak" receive window bytes.
3598 TEST_P(SpdySessionTest
, SessionFlowControlNoReceiveLeaks
) {
3599 if (GetParam() < kProtoSPDY31
)
3602 const char kStreamUrl
[] = "http://www.google.com/";
3604 const int32 msg_data_size
= 100;
3605 const std::string
msg_data(msg_data_size
, 'a');
3607 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3609 scoped_ptr
<SpdyFrame
> req(
3610 spdy_util_
.ConstructSpdyPost(
3611 kStreamUrl
, 1, msg_data_size
, MEDIUM
, NULL
, 0));
3612 scoped_ptr
<SpdyFrame
> msg(
3613 spdy_util_
.ConstructSpdyBodyFrame(
3614 1, msg_data
.data(), msg_data_size
, false));
3615 MockWrite writes
[] = {
3616 CreateMockWrite(*req
, 0),
3617 CreateMockWrite(*msg
, 2),
3620 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3621 scoped_ptr
<SpdyFrame
> echo(
3622 spdy_util_
.ConstructSpdyBodyFrame(
3623 1, msg_data
.data(), msg_data_size
, false));
3624 scoped_ptr
<SpdyFrame
> window_update(
3625 spdy_util_
.ConstructSpdyWindowUpdate(
3626 kSessionFlowControlStreamId
, msg_data_size
));
3627 MockRead reads
[] = {
3628 CreateMockRead(*resp
, 1),
3629 CreateMockRead(*echo
, 3),
3630 MockRead(ASYNC
, 0, 4) // EOF
3633 // Create SpdySession and SpdyStream and send the request.
3634 DeterministicSocketData
data(reads
, arraysize(reads
),
3635 writes
, arraysize(writes
));
3636 data
.set_connect_data(connect_data
);
3637 session_deps_
.host_resolver
->set_synchronous_mode(true);
3638 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3640 CreateDeterministicNetworkSession();
3642 base::WeakPtr
<SpdySession
> session
=
3643 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3645 GURL
url(kStreamUrl
);
3646 base::WeakPtr
<SpdyStream
> stream
=
3647 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
3648 session
, url
, MEDIUM
, BoundNetLog());
3649 ASSERT_TRUE(stream
.get() != NULL
);
3650 EXPECT_EQ(0u, stream
->stream_id());
3652 DropReceivedDataDelegate
delegate(stream
, msg_data
);
3653 stream
->SetDelegate(&delegate
);
3655 scoped_ptr
<SpdyHeaderBlock
> headers(
3656 spdy_util_
.ConstructPostHeaderBlock(url
.spec(), msg_data_size
));
3657 EXPECT_EQ(ERR_IO_PENDING
,
3658 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
3659 EXPECT_TRUE(stream
->HasUrlFromHeaders());
3661 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3662 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3666 EXPECT_TRUE(data
.at_write_eof());
3667 EXPECT_TRUE(data
.at_read_eof());
3669 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3670 EXPECT_EQ(msg_data_size
, session
->session_unacked_recv_window_bytes_
);
3673 EXPECT_EQ(NULL
, stream
.get());
3675 EXPECT_EQ(OK
, delegate
.WaitForClose());
3677 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3678 EXPECT_EQ(msg_data_size
, session
->session_unacked_recv_window_bytes_
);
3681 // Send data back and forth but close the stream before its data frame
3682 // can be written to the socket. The send window should then increase
3683 // to its original value, i.e. we shouldn't "leak" send window bytes.
3684 TEST_P(SpdySessionTest
, SessionFlowControlNoSendLeaks
) {
3685 if (GetParam() < kProtoSPDY31
)
3688 const char kStreamUrl
[] = "http://www.google.com/";
3690 const int32 msg_data_size
= 100;
3691 const std::string
msg_data(msg_data_size
, 'a');
3693 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3695 scoped_ptr
<SpdyFrame
> req(
3696 spdy_util_
.ConstructSpdyPost(
3697 kStreamUrl
, 1, msg_data_size
, MEDIUM
, NULL
, 0));
3698 MockWrite writes
[] = {
3699 CreateMockWrite(*req
, 0),
3702 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3703 MockRead reads
[] = {
3704 CreateMockRead(*resp
, 1),
3705 MockRead(ASYNC
, 0, 2) // EOF
3708 // Create SpdySession and SpdyStream and send the request.
3709 DeterministicSocketData
data(reads
, arraysize(reads
),
3710 writes
, arraysize(writes
));
3711 data
.set_connect_data(connect_data
);
3712 session_deps_
.host_resolver
->set_synchronous_mode(true);
3713 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3715 CreateDeterministicNetworkSession();
3717 base::WeakPtr
<SpdySession
> session
=
3718 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3720 GURL
url(kStreamUrl
);
3721 base::WeakPtr
<SpdyStream
> stream
=
3722 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
3723 session
, url
, MEDIUM
, BoundNetLog());
3724 ASSERT_TRUE(stream
.get() != NULL
);
3725 EXPECT_EQ(0u, stream
->stream_id());
3727 test::StreamDelegateSendImmediate
delegate(stream
, msg_data
);
3728 stream
->SetDelegate(&delegate
);
3730 scoped_ptr
<SpdyHeaderBlock
> headers(
3731 spdy_util_
.ConstructPostHeaderBlock(url
.spec(), msg_data_size
));
3732 EXPECT_EQ(ERR_IO_PENDING
,
3733 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
3734 EXPECT_TRUE(stream
->HasUrlFromHeaders());
3736 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3740 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3744 EXPECT_TRUE(data
.at_write_eof());
3745 EXPECT_TRUE(data
.at_read_eof());
3747 EXPECT_EQ(kSpdySessionInitialWindowSize
- msg_data_size
,
3748 session
->session_send_window_size_
);
3750 // Closing the stream should increase the session's send window.
3752 EXPECT_EQ(NULL
, stream
.get());
3754 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3756 EXPECT_EQ(OK
, delegate
.WaitForClose());
3759 // Send data back and forth; the send and receive windows should
3760 // change appropriately.
3761 TEST_P(SpdySessionTest
, SessionFlowControlEndToEnd
) {
3762 if (GetParam() < kProtoSPDY31
)
3765 const char kStreamUrl
[] = "http://www.google.com/";
3767 const int32 msg_data_size
= 100;
3768 const std::string
msg_data(msg_data_size
, 'a');
3770 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3772 scoped_ptr
<SpdyFrame
> req(
3773 spdy_util_
.ConstructSpdyPost(
3774 kStreamUrl
, 1, msg_data_size
, MEDIUM
, NULL
, 0));
3775 scoped_ptr
<SpdyFrame
> msg(
3776 spdy_util_
.ConstructSpdyBodyFrame(
3777 1, msg_data
.data(), msg_data_size
, false));
3778 MockWrite writes
[] = {
3779 CreateMockWrite(*req
, 0),
3780 CreateMockWrite(*msg
, 2),
3783 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3784 scoped_ptr
<SpdyFrame
> echo(
3785 spdy_util_
.ConstructSpdyBodyFrame(
3786 1, msg_data
.data(), msg_data_size
, false));
3787 scoped_ptr
<SpdyFrame
> window_update(
3788 spdy_util_
.ConstructSpdyWindowUpdate(
3789 kSessionFlowControlStreamId
, msg_data_size
));
3790 MockRead reads
[] = {
3791 CreateMockRead(*resp
, 1),
3792 CreateMockRead(*echo
, 3),
3793 CreateMockRead(*window_update
, 4),
3794 MockRead(ASYNC
, 0, 5) // EOF
3797 // Create SpdySession and SpdyStream and send the request.
3798 DeterministicSocketData
data(reads
, arraysize(reads
),
3799 writes
, arraysize(writes
));
3800 data
.set_connect_data(connect_data
);
3801 session_deps_
.host_resolver
->set_synchronous_mode(true);
3802 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3804 CreateDeterministicNetworkSession();
3806 base::WeakPtr
<SpdySession
> session
=
3807 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3809 GURL
url(kStreamUrl
);
3810 base::WeakPtr
<SpdyStream
> stream
=
3811 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM
,
3812 session
, url
, MEDIUM
, BoundNetLog());
3813 ASSERT_TRUE(stream
.get() != NULL
);
3814 EXPECT_EQ(0u, stream
->stream_id());
3816 test::StreamDelegateSendImmediate
delegate(stream
, msg_data
);
3817 stream
->SetDelegate(&delegate
);
3819 scoped_ptr
<SpdyHeaderBlock
> headers(
3820 spdy_util_
.ConstructPostHeaderBlock(url
.spec(), msg_data_size
));
3821 EXPECT_EQ(ERR_IO_PENDING
,
3822 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
3823 EXPECT_TRUE(stream
->HasUrlFromHeaders());
3825 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3826 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3827 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3831 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3832 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3833 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3837 EXPECT_EQ(kSpdySessionInitialWindowSize
- msg_data_size
,
3838 session
->session_send_window_size_
);
3839 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3840 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3844 EXPECT_EQ(kSpdySessionInitialWindowSize
- msg_data_size
,
3845 session
->session_send_window_size_
);
3846 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3847 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3851 EXPECT_EQ(kSpdySessionInitialWindowSize
- msg_data_size
,
3852 session
->session_send_window_size_
);
3853 EXPECT_EQ(kSpdySessionInitialWindowSize
- msg_data_size
,
3854 session
->session_recv_window_size_
);
3855 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3859 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3860 EXPECT_EQ(kSpdySessionInitialWindowSize
- msg_data_size
,
3861 session
->session_recv_window_size_
);
3862 EXPECT_EQ(0, session
->session_unacked_recv_window_bytes_
);
3864 EXPECT_TRUE(data
.at_write_eof());
3865 EXPECT_TRUE(data
.at_read_eof());
3867 EXPECT_EQ(msg_data
, delegate
.TakeReceivedData());
3869 // Draining the delegate's read queue should increase the session's
3871 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3872 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3873 EXPECT_EQ(msg_data_size
, session
->session_unacked_recv_window_bytes_
);
3876 EXPECT_EQ(NULL
, stream
.get());
3878 EXPECT_EQ(OK
, delegate
.WaitForClose());
3880 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_send_window_size_
);
3881 EXPECT_EQ(kSpdySessionInitialWindowSize
, session
->session_recv_window_size_
);
3882 EXPECT_EQ(msg_data_size
, session
->session_unacked_recv_window_bytes_
);
3885 // Given a stall function and an unstall function, runs a test to make
3886 // sure that a stream resumes after unstall.
3887 void SpdySessionTest::RunResumeAfterUnstallTest(
3888 const base::Callback
<void(SpdySession
*, SpdyStream
*)>& stall_function
,
3889 const base::Callback
<void(SpdySession
*, SpdyStream
*, int32
)>&
3891 const char kStreamUrl
[] = "http://www.google.com/";
3892 GURL
url(kStreamUrl
);
3894 session_deps_
.host_resolver
->set_synchronous_mode(true);
3896 scoped_ptr
<SpdyFrame
> req(
3897 spdy_util_
.ConstructSpdyPost(
3898 kStreamUrl
, 1, kBodyDataSize
, LOWEST
, NULL
, 0));
3899 scoped_ptr
<SpdyFrame
> body(
3900 spdy_util_
.ConstructSpdyBodyFrame(1, kBodyData
, kBodyDataSize
, true));
3901 MockWrite writes
[] = {
3902 CreateMockWrite(*req
, 0),
3903 CreateMockWrite(*body
, 1),
3906 scoped_ptr
<SpdyFrame
> resp(
3907 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
3908 scoped_ptr
<SpdyFrame
> echo(
3909 spdy_util_
.ConstructSpdyBodyFrame(1, kBodyData
, kBodyDataSize
, false));
3910 MockRead reads
[] = {
3911 CreateMockRead(*resp
, 2),
3912 MockRead(ASYNC
, 0, 0, 3), // EOF
3915 DeterministicSocketData
data(reads
, arraysize(reads
),
3916 writes
, arraysize(writes
));
3917 MockConnect
connect_data(SYNCHRONOUS
, OK
);
3918 data
.set_connect_data(connect_data
);
3920 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
3922 CreateDeterministicNetworkSession();
3923 base::WeakPtr
<SpdySession
> session
=
3924 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
3925 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
3926 session
->flow_control_state());
3928 base::WeakPtr
<SpdyStream
> stream
=
3929 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
3930 session
, url
, LOWEST
, BoundNetLog());
3931 ASSERT_TRUE(stream
.get() != NULL
);
3933 test::StreamDelegateWithBody
delegate(stream
, kBodyDataStringPiece
);
3934 stream
->SetDelegate(&delegate
);
3936 EXPECT_FALSE(stream
->HasUrlFromHeaders());
3937 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
3939 scoped_ptr
<SpdyHeaderBlock
> headers(
3940 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
3941 EXPECT_EQ(ERR_IO_PENDING
,
3942 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
3943 EXPECT_TRUE(stream
->HasUrlFromHeaders());
3944 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
3946 stall_function
.Run(session
.get(), stream
.get());
3950 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
3952 unstall_function
.Run(session
.get(), stream
.get(), kBodyDataSize
);
3954 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
3958 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
3960 EXPECT_TRUE(delegate
.send_headers_completed());
3961 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
3962 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
3963 EXPECT_TRUE(data
.at_write_eof());
3966 // Run the resume-after-unstall test with all possible stall and
3967 // unstall sequences.
3969 TEST_P(SpdySessionTest
, ResumeAfterUnstallSession
) {
3970 if (GetParam() < kProtoSPDY31
)
3973 RunResumeAfterUnstallTest(
3974 base::Bind(&SpdySessionTest::StallSessionOnly
,
3975 base::Unretained(this)),
3976 base::Bind(&SpdySessionTest::UnstallSessionOnly
,
3977 base::Unretained(this)));
3981 // SpdyStreamTest.ResumeAfterSendWindowSizeIncrease.
3982 TEST_P(SpdySessionTest
, ResumeAfterUnstallStream
) {
3983 if (GetParam() < kProtoSPDY31
)
3986 RunResumeAfterUnstallTest(
3987 base::Bind(&SpdySessionTest::StallStreamOnly
,
3988 base::Unretained(this)),
3989 base::Bind(&SpdySessionTest::UnstallStreamOnly
,
3990 base::Unretained(this)));
3993 TEST_P(SpdySessionTest
, StallSessionStreamResumeAfterUnstallSessionStream
) {
3994 if (GetParam() < kProtoSPDY31
)
3997 RunResumeAfterUnstallTest(
3998 base::Bind(&SpdySessionTest::StallSessionStream
,
3999 base::Unretained(this)),
4000 base::Bind(&SpdySessionTest::UnstallSessionStream
,
4001 base::Unretained(this)));
4004 TEST_P(SpdySessionTest
, StallStreamSessionResumeAfterUnstallSessionStream
) {
4005 if (GetParam() < kProtoSPDY31
)
4008 RunResumeAfterUnstallTest(
4009 base::Bind(&SpdySessionTest::StallStreamSession
,
4010 base::Unretained(this)),
4011 base::Bind(&SpdySessionTest::UnstallSessionStream
,
4012 base::Unretained(this)));
4015 TEST_P(SpdySessionTest
, StallStreamSessionResumeAfterUnstallStreamSession
) {
4016 if (GetParam() < kProtoSPDY31
)
4019 RunResumeAfterUnstallTest(
4020 base::Bind(&SpdySessionTest::StallStreamSession
,
4021 base::Unretained(this)),
4022 base::Bind(&SpdySessionTest::UnstallStreamSession
,
4023 base::Unretained(this)));
4026 TEST_P(SpdySessionTest
, StallSessionStreamResumeAfterUnstallStreamSession
) {
4027 if (GetParam() < kProtoSPDY31
)
4030 RunResumeAfterUnstallTest(
4031 base::Bind(&SpdySessionTest::StallSessionStream
,
4032 base::Unretained(this)),
4033 base::Bind(&SpdySessionTest::UnstallStreamSession
,
4034 base::Unretained(this)));
4037 // Cause a stall by reducing the flow control send window to 0. The
4038 // streams should resume in priority order when that window is then
4040 TEST_P(SpdySessionTest
, ResumeByPriorityAfterSendWindowSizeIncrease
) {
4041 if (GetParam() < kProtoSPDY31
)
4044 const char kStreamUrl
[] = "http://www.google.com/";
4045 GURL
url(kStreamUrl
);
4047 session_deps_
.host_resolver
->set_synchronous_mode(true);
4049 scoped_ptr
<SpdyFrame
> req1(
4050 spdy_util_
.ConstructSpdyPost(
4051 kStreamUrl
, 1, kBodyDataSize
, LOWEST
, NULL
, 0));
4052 scoped_ptr
<SpdyFrame
> req2(
4053 spdy_util_
.ConstructSpdyPost(
4054 kStreamUrl
, 3, kBodyDataSize
, MEDIUM
, NULL
, 0));
4055 scoped_ptr
<SpdyFrame
> body1(
4056 spdy_util_
.ConstructSpdyBodyFrame(1, kBodyData
, kBodyDataSize
, true));
4057 scoped_ptr
<SpdyFrame
> body2(
4058 spdy_util_
.ConstructSpdyBodyFrame(3, kBodyData
, kBodyDataSize
, true));
4059 MockWrite writes
[] = {
4060 CreateMockWrite(*req1
, 0),
4061 CreateMockWrite(*req2
, 1),
4062 CreateMockWrite(*body2
, 2),
4063 CreateMockWrite(*body1
, 3),
4066 scoped_ptr
<SpdyFrame
> resp1(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4067 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
4068 MockRead reads
[] = {
4069 CreateMockRead(*resp1
, 4),
4070 CreateMockRead(*resp2
, 5),
4071 MockRead(ASYNC
, 0, 0, 6), // EOF
4074 DeterministicSocketData
data(reads
, arraysize(reads
),
4075 writes
, arraysize(writes
));
4076 MockConnect
connect_data(SYNCHRONOUS
, OK
);
4077 data
.set_connect_data(connect_data
);
4079 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
4081 CreateDeterministicNetworkSession();
4082 base::WeakPtr
<SpdySession
> session
=
4083 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
4084 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
4085 session
->flow_control_state());
4087 base::WeakPtr
<SpdyStream
> stream1
=
4088 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
4089 session
, url
, LOWEST
, BoundNetLog());
4090 ASSERT_TRUE(stream1
.get() != NULL
);
4092 test::StreamDelegateWithBody
delegate1(stream1
, kBodyDataStringPiece
);
4093 stream1
->SetDelegate(&delegate1
);
4095 EXPECT_FALSE(stream1
->HasUrlFromHeaders());
4097 base::WeakPtr
<SpdyStream
> stream2
=
4098 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
4099 session
, url
, MEDIUM
, BoundNetLog());
4100 ASSERT_TRUE(stream2
.get() != NULL
);
4102 test::StreamDelegateWithBody
delegate2(stream2
, kBodyDataStringPiece
);
4103 stream2
->SetDelegate(&delegate2
);
4105 EXPECT_FALSE(stream2
->HasUrlFromHeaders());
4107 EXPECT_FALSE(stream1
->send_stalled_by_flow_control());
4108 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4110 StallSessionSend(session
.get());
4112 scoped_ptr
<SpdyHeaderBlock
> headers1(
4113 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
4114 EXPECT_EQ(ERR_IO_PENDING
,
4115 stream1
->SendRequestHeaders(headers1
.Pass(), MORE_DATA_TO_SEND
));
4116 EXPECT_TRUE(stream1
->HasUrlFromHeaders());
4117 EXPECT_EQ(kStreamUrl
, stream1
->GetUrlFromHeaders().spec());
4120 EXPECT_EQ(1u, stream1
->stream_id());
4121 EXPECT_TRUE(stream1
->send_stalled_by_flow_control());
4123 scoped_ptr
<SpdyHeaderBlock
> headers2(
4124 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
4125 EXPECT_EQ(ERR_IO_PENDING
,
4126 stream2
->SendRequestHeaders(headers2
.Pass(), MORE_DATA_TO_SEND
));
4127 EXPECT_TRUE(stream2
->HasUrlFromHeaders());
4128 EXPECT_EQ(kStreamUrl
, stream2
->GetUrlFromHeaders().spec());
4131 EXPECT_EQ(3u, stream2
->stream_id());
4132 EXPECT_TRUE(stream2
->send_stalled_by_flow_control());
4134 // This should unstall only stream2.
4135 UnstallSessionSend(session
.get(), kBodyDataSize
);
4137 EXPECT_TRUE(stream1
->send_stalled_by_flow_control());
4138 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4142 EXPECT_TRUE(stream1
->send_stalled_by_flow_control());
4143 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4145 // This should then unstall stream1.
4146 UnstallSessionSend(session
.get(), kBodyDataSize
);
4148 EXPECT_FALSE(stream1
->send_stalled_by_flow_control());
4149 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4153 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate1
.WaitForClose());
4154 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate2
.WaitForClose());
4156 EXPECT_TRUE(delegate1
.send_headers_completed());
4157 EXPECT_EQ("200", delegate1
.GetResponseHeaderValue(":status"));
4158 EXPECT_EQ(std::string(), delegate1
.TakeReceivedData());
4160 EXPECT_TRUE(delegate2
.send_headers_completed());
4161 EXPECT_EQ("200", delegate2
.GetResponseHeaderValue(":status"));
4162 EXPECT_EQ(std::string(), delegate2
.TakeReceivedData());
4164 EXPECT_TRUE(data
.at_write_eof());
4167 // Delegate that closes a given stream after sending its body.
4168 class StreamClosingDelegate
: public test::StreamDelegateWithBody
{
4170 StreamClosingDelegate(const base::WeakPtr
<SpdyStream
>& stream
,
4171 base::StringPiece data
)
4172 : StreamDelegateWithBody(stream
, data
) {}
4174 virtual ~StreamClosingDelegate() {}
4176 void set_stream_to_close(const base::WeakPtr
<SpdyStream
>& stream_to_close
) {
4177 stream_to_close_
= stream_to_close
;
4180 virtual void OnDataSent() OVERRIDE
{
4181 test::StreamDelegateWithBody::OnDataSent();
4182 if (stream_to_close_
.get()) {
4183 stream_to_close_
->Close();
4184 EXPECT_EQ(NULL
, stream_to_close_
.get());
4189 base::WeakPtr
<SpdyStream
> stream_to_close_
;
4192 // Cause a stall by reducing the flow control send window to
4193 // 0. Unstalling the session should properly handle deleted streams.
4194 TEST_P(SpdySessionTest
, SendWindowSizeIncreaseWithDeletedStreams
) {
4195 if (GetParam() < kProtoSPDY31
)
4198 const char kStreamUrl
[] = "http://www.google.com/";
4199 GURL
url(kStreamUrl
);
4201 session_deps_
.host_resolver
->set_synchronous_mode(true);
4203 scoped_ptr
<SpdyFrame
> req1(
4204 spdy_util_
.ConstructSpdyPost(
4205 kStreamUrl
, 1, kBodyDataSize
, LOWEST
, NULL
, 0));
4206 scoped_ptr
<SpdyFrame
> req2(
4207 spdy_util_
.ConstructSpdyPost(
4208 kStreamUrl
, 3, kBodyDataSize
, LOWEST
, NULL
, 0));
4209 scoped_ptr
<SpdyFrame
> req3(
4210 spdy_util_
.ConstructSpdyPost(
4211 kStreamUrl
, 5, kBodyDataSize
, LOWEST
, NULL
, 0));
4212 scoped_ptr
<SpdyFrame
> body2(
4213 spdy_util_
.ConstructSpdyBodyFrame(3, kBodyData
, kBodyDataSize
, true));
4214 MockWrite writes
[] = {
4215 CreateMockWrite(*req1
, 0),
4216 CreateMockWrite(*req2
, 1),
4217 CreateMockWrite(*req3
, 2),
4218 CreateMockWrite(*body2
, 3),
4221 scoped_ptr
<SpdyFrame
> resp2(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 3));
4222 MockRead reads
[] = {
4223 CreateMockRead(*resp2
, 4),
4224 MockRead(ASYNC
, 0, 0, 5), // EOF
4227 DeterministicSocketData
data(reads
, arraysize(reads
),
4228 writes
, arraysize(writes
));
4229 MockConnect
connect_data(SYNCHRONOUS
, OK
);
4230 data
.set_connect_data(connect_data
);
4232 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
4234 CreateDeterministicNetworkSession();
4235 base::WeakPtr
<SpdySession
> session
=
4236 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
4237 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
4238 session
->flow_control_state());
4240 base::WeakPtr
<SpdyStream
> stream1
=
4241 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
4242 session
, url
, LOWEST
, BoundNetLog());
4243 ASSERT_TRUE(stream1
.get() != NULL
);
4245 test::StreamDelegateWithBody
delegate1(stream1
, kBodyDataStringPiece
);
4246 stream1
->SetDelegate(&delegate1
);
4248 EXPECT_FALSE(stream1
->HasUrlFromHeaders());
4250 base::WeakPtr
<SpdyStream
> stream2
=
4251 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
4252 session
, url
, LOWEST
, BoundNetLog());
4253 ASSERT_TRUE(stream2
.get() != NULL
);
4255 StreamClosingDelegate
delegate2(stream2
, kBodyDataStringPiece
);
4256 stream2
->SetDelegate(&delegate2
);
4258 EXPECT_FALSE(stream2
->HasUrlFromHeaders());
4260 base::WeakPtr
<SpdyStream
> stream3
=
4261 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
4262 session
, url
, LOWEST
, BoundNetLog());
4263 ASSERT_TRUE(stream3
.get() != NULL
);
4265 test::StreamDelegateWithBody
delegate3(stream3
, kBodyDataStringPiece
);
4266 stream3
->SetDelegate(&delegate3
);
4268 EXPECT_FALSE(stream3
->HasUrlFromHeaders());
4270 EXPECT_FALSE(stream1
->send_stalled_by_flow_control());
4271 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4272 EXPECT_FALSE(stream3
->send_stalled_by_flow_control());
4274 StallSessionSend(session
.get());
4276 scoped_ptr
<SpdyHeaderBlock
> headers1(
4277 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
4278 EXPECT_EQ(ERR_IO_PENDING
,
4279 stream1
->SendRequestHeaders(headers1
.Pass(), MORE_DATA_TO_SEND
));
4280 EXPECT_TRUE(stream1
->HasUrlFromHeaders());
4281 EXPECT_EQ(kStreamUrl
, stream1
->GetUrlFromHeaders().spec());
4284 EXPECT_EQ(1u, stream1
->stream_id());
4285 EXPECT_TRUE(stream1
->send_stalled_by_flow_control());
4287 scoped_ptr
<SpdyHeaderBlock
> headers2(
4288 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
4289 EXPECT_EQ(ERR_IO_PENDING
,
4290 stream2
->SendRequestHeaders(headers2
.Pass(), MORE_DATA_TO_SEND
));
4291 EXPECT_TRUE(stream2
->HasUrlFromHeaders());
4292 EXPECT_EQ(kStreamUrl
, stream2
->GetUrlFromHeaders().spec());
4295 EXPECT_EQ(3u, stream2
->stream_id());
4296 EXPECT_TRUE(stream2
->send_stalled_by_flow_control());
4298 scoped_ptr
<SpdyHeaderBlock
> headers3(
4299 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
4300 EXPECT_EQ(ERR_IO_PENDING
,
4301 stream3
->SendRequestHeaders(headers3
.Pass(), MORE_DATA_TO_SEND
));
4302 EXPECT_TRUE(stream3
->HasUrlFromHeaders());
4303 EXPECT_EQ(kStreamUrl
, stream3
->GetUrlFromHeaders().spec());
4306 EXPECT_EQ(5u, stream3
->stream_id());
4307 EXPECT_TRUE(stream3
->send_stalled_by_flow_control());
4309 SpdyStreamId stream_id1
= stream1
->stream_id();
4310 SpdyStreamId stream_id2
= stream2
->stream_id();
4311 SpdyStreamId stream_id3
= stream3
->stream_id();
4313 // Close stream1 preemptively.
4314 session
->CloseActiveStream(stream_id1
, ERR_CONNECTION_CLOSED
);
4315 EXPECT_EQ(NULL
, stream1
.get());
4317 EXPECT_FALSE(session
->IsStreamActive(stream_id1
));
4318 EXPECT_TRUE(session
->IsStreamActive(stream_id2
));
4319 EXPECT_TRUE(session
->IsStreamActive(stream_id3
));
4321 // Unstall stream2, which should then close stream3.
4322 delegate2
.set_stream_to_close(stream3
);
4323 UnstallSessionSend(session
.get(), kBodyDataSize
);
4326 EXPECT_EQ(NULL
, stream3
.get());
4328 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4329 EXPECT_FALSE(session
->IsStreamActive(stream_id1
));
4330 EXPECT_TRUE(session
->IsStreamActive(stream_id2
));
4331 EXPECT_FALSE(session
->IsStreamActive(stream_id3
));
4334 EXPECT_EQ(NULL
, stream2
.get());
4336 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate1
.WaitForClose());
4337 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate2
.WaitForClose());
4338 EXPECT_EQ(OK
, delegate3
.WaitForClose());
4340 EXPECT_TRUE(delegate1
.send_headers_completed());
4341 EXPECT_EQ(std::string(), delegate1
.TakeReceivedData());
4343 EXPECT_TRUE(delegate2
.send_headers_completed());
4344 EXPECT_EQ("200", delegate2
.GetResponseHeaderValue(":status"));
4345 EXPECT_EQ(std::string(), delegate2
.TakeReceivedData());
4347 EXPECT_TRUE(delegate3
.send_headers_completed());
4348 EXPECT_EQ(std::string(), delegate3
.TakeReceivedData());
4350 EXPECT_TRUE(data
.at_write_eof());
4353 // Cause a stall by reducing the flow control send window to
4354 // 0. Unstalling the session should properly handle the session itself
4356 TEST_P(SpdySessionTest
, SendWindowSizeIncreaseWithDeletedSession
) {
4357 if (GetParam() < kProtoSPDY31
)
4360 const char kStreamUrl
[] = "http://www.google.com/";
4361 GURL
url(kStreamUrl
);
4363 session_deps_
.host_resolver
->set_synchronous_mode(true);
4365 scoped_ptr
<SpdyFrame
> req1(
4366 spdy_util_
.ConstructSpdyPost(
4367 kStreamUrl
, 1, kBodyDataSize
, LOWEST
, NULL
, 0));
4368 scoped_ptr
<SpdyFrame
> req2(
4369 spdy_util_
.ConstructSpdyPost(
4370 kStreamUrl
, 3, kBodyDataSize
, LOWEST
, NULL
, 0));
4371 scoped_ptr
<SpdyFrame
> body1(
4372 spdy_util_
.ConstructSpdyBodyFrame(1, kBodyData
, kBodyDataSize
, false));
4373 MockWrite writes
[] = {
4374 CreateMockWrite(*req1
, 0),
4375 CreateMockWrite(*req2
, 1),
4378 MockRead reads
[] = {
4379 MockRead(ASYNC
, 0, 0, 2), // EOF
4382 DeterministicSocketData
data(reads
, arraysize(reads
),
4383 writes
, arraysize(writes
));
4384 MockConnect
connect_data(SYNCHRONOUS
, OK
);
4385 data
.set_connect_data(connect_data
);
4387 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
4389 CreateDeterministicNetworkSession();
4390 base::WeakPtr
<SpdySession
> session
=
4391 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
4392 EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION
,
4393 session
->flow_control_state());
4395 base::WeakPtr
<SpdyStream
> stream1
=
4396 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
4397 session
, url
, LOWEST
, BoundNetLog());
4398 ASSERT_TRUE(stream1
.get() != NULL
);
4400 test::StreamDelegateWithBody
delegate1(stream1
, kBodyDataStringPiece
);
4401 stream1
->SetDelegate(&delegate1
);
4403 EXPECT_FALSE(stream1
->HasUrlFromHeaders());
4405 base::WeakPtr
<SpdyStream
> stream2
=
4406 CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM
,
4407 session
, url
, LOWEST
, BoundNetLog());
4408 ASSERT_TRUE(stream2
.get() != NULL
);
4410 test::StreamDelegateWithBody
delegate2(stream2
, kBodyDataStringPiece
);
4411 stream2
->SetDelegate(&delegate2
);
4413 EXPECT_FALSE(stream2
->HasUrlFromHeaders());
4415 EXPECT_FALSE(stream1
->send_stalled_by_flow_control());
4416 EXPECT_FALSE(stream2
->send_stalled_by_flow_control());
4418 StallSessionSend(session
.get());
4420 scoped_ptr
<SpdyHeaderBlock
> headers1(
4421 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
4422 EXPECT_EQ(ERR_IO_PENDING
,
4423 stream1
->SendRequestHeaders(headers1
.Pass(), MORE_DATA_TO_SEND
));
4424 EXPECT_TRUE(stream1
->HasUrlFromHeaders());
4425 EXPECT_EQ(kStreamUrl
, stream1
->GetUrlFromHeaders().spec());
4428 EXPECT_EQ(1u, stream1
->stream_id());
4429 EXPECT_TRUE(stream1
->send_stalled_by_flow_control());
4431 scoped_ptr
<SpdyHeaderBlock
> headers2(
4432 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kBodyDataSize
));
4433 EXPECT_EQ(ERR_IO_PENDING
,
4434 stream2
->SendRequestHeaders(headers2
.Pass(), MORE_DATA_TO_SEND
));
4435 EXPECT_TRUE(stream2
->HasUrlFromHeaders());
4436 EXPECT_EQ(kStreamUrl
, stream2
->GetUrlFromHeaders().spec());
4439 EXPECT_EQ(3u, stream2
->stream_id());
4440 EXPECT_TRUE(stream2
->send_stalled_by_flow_control());
4442 EXPECT_TRUE(HasSpdySession(spdy_session_pool_
, key_
));
4445 UnstallSessionSend(session
.get(), kBodyDataSize
);
4447 // Close the session (since we can't do it from within the delegate
4448 // method, since it's in the stream's loop).
4449 session
->CloseSessionOnError(ERR_CONNECTION_CLOSED
, "Closing session");
4450 base::RunLoop().RunUntilIdle();
4451 EXPECT_TRUE(session
== NULL
);
4453 EXPECT_FALSE(HasSpdySession(spdy_session_pool_
, key_
));
4455 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate1
.WaitForClose());
4456 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate2
.WaitForClose());
4458 EXPECT_TRUE(delegate1
.send_headers_completed());
4459 EXPECT_EQ(std::string(), delegate1
.TakeReceivedData());
4461 EXPECT_TRUE(delegate2
.send_headers_completed());
4462 EXPECT_EQ(std::string(), delegate2
.TakeReceivedData());
4464 EXPECT_TRUE(data
.at_write_eof());
4467 TEST_P(SpdySessionTest
, GoAwayOnSessionFlowControlError
) {
4468 if (GetParam() < kProtoSPDY31
)
4471 MockConnect
connect_data(SYNCHRONOUS
, OK
);
4473 scoped_ptr
<SpdyFrame
> req(
4474 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
4475 scoped_ptr
<SpdyFrame
> goaway(spdy_util_
.ConstructSpdyGoAway(
4477 GOAWAY_FLOW_CONTROL_ERROR
,
4478 "delta_window_size is 6 in DecreaseRecvWindowSize, which is larger than "
4479 "the receive window size of 1"));
4480 MockWrite writes
[] = {
4481 CreateMockWrite(*req
, 0), CreateMockWrite(*goaway
, 3),
4484 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
4485 scoped_ptr
<SpdyFrame
> body(spdy_util_
.ConstructSpdyBodyFrame(1, true));
4486 MockRead reads
[] = {
4487 CreateMockRead(*resp
, 1), CreateMockRead(*body
, 2),
4490 DeterministicSocketData
data(
4491 reads
, arraysize(reads
), writes
, arraysize(writes
));
4492 data
.set_connect_data(connect_data
);
4493 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
4495 CreateDeterministicNetworkSession();
4497 base::WeakPtr
<SpdySession
> session
=
4498 CreateInsecureSpdySession(http_session_
, key_
, BoundNetLog());
4500 GURL
url(kDefaultURL
);
4501 base::WeakPtr
<SpdyStream
> spdy_stream
= CreateStreamSynchronously(
4502 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
4503 ASSERT_TRUE(spdy_stream
.get() != NULL
);
4504 test::StreamDelegateDoNothing
delegate(spdy_stream
);
4505 spdy_stream
->SetDelegate(&delegate
);
4507 scoped_ptr
<SpdyHeaderBlock
> headers(
4508 spdy_util_
.ConstructGetHeaderBlock(url
.spec()));
4509 spdy_stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
);
4511 data
.RunFor(1); // Write request.
4513 // Put session on the edge of overflowing it's recv window.
4514 session
->session_recv_window_size_
= 1;
4516 // Read response headers & body. Body overflows the session window, and a
4517 // goaway is written.
4519 base::MessageLoop::current()->RunUntilIdle();
4521 EXPECT_EQ(ERR_SPDY_FLOW_CONTROL_ERROR
, delegate
.WaitForClose());
4522 EXPECT_TRUE(session
== NULL
);
4525 TEST_P(SpdySessionTest
, SplitHeaders
) {
4526 GURL
kStreamUrl("http://www.google.com/foo.dat");
4527 SpdyHeaderBlock headers
;
4528 spdy_util_
.AddUrlToHeaderBlock(kStreamUrl
.spec(), &headers
);
4529 headers
["alpha"] = "beta";
4531 SpdyHeaderBlock request_headers
;
4532 SpdyHeaderBlock response_headers
;
4534 SplitPushedHeadersToRequestAndResponse(
4535 headers
, spdy_util_
.spdy_version(), &request_headers
, &response_headers
);
4537 SpdyHeaderBlock::const_iterator it
= response_headers
.find("alpha");
4538 std::string alpha_val
=
4539 (it
== response_headers
.end()) ? std::string() : it
->second
;
4540 EXPECT_EQ("beta", alpha_val
);
4543 GetUrlFromHeaderBlock(request_headers
, spdy_util_
.spdy_version(), true);
4544 EXPECT_EQ(kStreamUrl
, request_url
);
4547 TEST(MapFramerErrorToProtocolError
, MapsValues
) {
4549 SPDY_ERROR_INVALID_CONTROL_FRAME
,
4550 MapFramerErrorToProtocolError(SpdyFramer::SPDY_INVALID_CONTROL_FRAME
));
4552 SPDY_ERROR_INVALID_DATA_FRAME_FLAGS
,
4553 MapFramerErrorToProtocolError(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS
));
4555 SPDY_ERROR_GOAWAY_FRAME_CORRUPT
,
4556 MapFramerErrorToProtocolError(SpdyFramer::SPDY_GOAWAY_FRAME_CORRUPT
));
4557 CHECK_EQ(SPDY_ERROR_UNEXPECTED_FRAME
,
4558 MapFramerErrorToProtocolError(SpdyFramer::SPDY_UNEXPECTED_FRAME
));
4561 TEST(MapFramerErrorToNetError
, MapsValue
) {
4562 CHECK_EQ(ERR_SPDY_PROTOCOL_ERROR
,
4563 MapFramerErrorToNetError(SpdyFramer::SPDY_INVALID_CONTROL_FRAME
));
4564 CHECK_EQ(ERR_SPDY_COMPRESSION_ERROR
,
4565 MapFramerErrorToNetError(SpdyFramer::SPDY_COMPRESS_FAILURE
));
4566 CHECK_EQ(ERR_SPDY_COMPRESSION_ERROR
,
4567 MapFramerErrorToNetError(SpdyFramer::SPDY_DECOMPRESS_FAILURE
));
4569 ERR_SPDY_FRAME_SIZE_ERROR
,
4570 MapFramerErrorToNetError(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE
));
4573 TEST(MapRstStreamStatusToProtocolError
, MapsValues
) {
4574 CHECK_EQ(STATUS_CODE_PROTOCOL_ERROR
,
4575 MapRstStreamStatusToProtocolError(RST_STREAM_PROTOCOL_ERROR
));
4576 CHECK_EQ(STATUS_CODE_FRAME_SIZE_ERROR
,
4577 MapRstStreamStatusToProtocolError(RST_STREAM_FRAME_SIZE_ERROR
));
4578 CHECK_EQ(STATUS_CODE_ENHANCE_YOUR_CALM
,
4579 MapRstStreamStatusToProtocolError(RST_STREAM_ENHANCE_YOUR_CALM
));
4582 TEST(MapNetErrorToGoAwayStatus
, MapsValue
) {
4583 CHECK_EQ(GOAWAY_INADEQUATE_SECURITY
,
4584 MapNetErrorToGoAwayStatus(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY
));
4585 CHECK_EQ(GOAWAY_FLOW_CONTROL_ERROR
,
4586 MapNetErrorToGoAwayStatus(ERR_SPDY_FLOW_CONTROL_ERROR
));
4587 CHECK_EQ(GOAWAY_PROTOCOL_ERROR
,
4588 MapNetErrorToGoAwayStatus(ERR_SPDY_PROTOCOL_ERROR
));
4589 CHECK_EQ(GOAWAY_COMPRESSION_ERROR
,
4590 MapNetErrorToGoAwayStatus(ERR_SPDY_COMPRESSION_ERROR
));
4591 CHECK_EQ(GOAWAY_FRAME_SIZE_ERROR
,
4592 MapNetErrorToGoAwayStatus(ERR_SPDY_FRAME_SIZE_ERROR
));
4593 CHECK_EQ(GOAWAY_PROTOCOL_ERROR
, MapNetErrorToGoAwayStatus(ERR_UNEXPECTED
));