1 // Copyright 2013 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.
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_piece.h"
13 #include "net/base/completion_callback.h"
14 #include "net/base/net_log_unittest.h"
15 #include "net/base/request_priority.h"
16 #include "net/socket/next_proto.h"
17 #include "net/socket/socket_test_util.h"
18 #include "net/spdy/buffered_spdy_framer.h"
19 #include "net/spdy/spdy_http_utils.h"
20 #include "net/spdy/spdy_protocol.h"
21 #include "net/spdy/spdy_session.h"
22 #include "net/spdy/spdy_stream.h"
23 #include "net/spdy/spdy_stream_test_util.h"
24 #include "net/spdy/spdy_test_util_common.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
35 const char kStreamUrl
[] = "http://www.google.com/";
36 const char kPostBody
[] = "\0hello!\xff";
37 const size_t kPostBodyLength
= arraysize(kPostBody
);
38 const base::StringPiece
kPostBodyStringPiece(kPostBody
, kPostBodyLength
);
40 class SpdyStreamTest
: public ::testing::Test
,
41 public ::testing::WithParamInterface
<NextProto
> {
43 // A function that takes a SpdyStream and the number of bytes which
44 // will unstall the next frame completely.
45 typedef base::Callback
<void(const base::WeakPtr
<SpdyStream
>&, int32
)>
49 : spdy_util_(GetParam()),
50 session_deps_(GetParam()),
53 base::WeakPtr
<SpdySession
> CreateDefaultSpdySession() {
54 SpdySessionKey
key(HostPortPair("www.google.com", 80),
55 ProxyServer::Direct(),
56 PRIVACY_MODE_DISABLED
);
57 return CreateInsecureSpdySession(session_
, key
, BoundNetLog());
60 virtual void TearDown() {
61 base::MessageLoop::current()->RunUntilIdle();
64 void RunResumeAfterUnstallRequestResponseTest(
65 const UnstallFunction
& unstall_function
);
67 void RunResumeAfterUnstallBidirectionalTest(
68 const UnstallFunction
& unstall_function
);
70 // Add{Read,Write}() populates lists that are eventually passed to a
71 // SocketData class. |frame| must live for the whole test.
73 void AddRead(const SpdyFrame
& frame
) {
74 reads_
.push_back(CreateMockRead(frame
, offset_
++));
77 void AddWrite(const SpdyFrame
& frame
) {
78 writes_
.push_back(CreateMockWrite(frame
, offset_
++));
82 reads_
.push_back(MockRead(ASYNC
, 0, offset_
++));
85 MockRead
* GetReads() {
86 return vector_as_array(&reads_
);
89 size_t GetNumReads() const {
93 MockWrite
* GetWrites() {
94 return vector_as_array(&writes_
);
97 int GetNumWrites() const {
98 return writes_
.size();
101 SpdyTestUtil spdy_util_
;
102 SpdySessionDependencies session_deps_
;
103 scoped_refptr
<HttpNetworkSession
> session_
;
106 // Used by Add{Read,Write}() above.
107 std::vector
<MockWrite
> writes_
;
108 std::vector
<MockRead
> reads_
;
112 INSTANTIATE_TEST_CASE_P(
115 testing::Values(kProtoDeprecatedSPDY2
,
116 kProtoSPDY3
, kProtoSPDY31
, kProtoSPDY4
));
118 TEST_P(SpdyStreamTest
, SendDataAfterOpen
) {
119 GURL
url(kStreamUrl
);
121 session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
123 scoped_ptr
<SpdyFrame
> req(
124 spdy_util_
.ConstructSpdyPost(
125 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
128 scoped_ptr
<SpdyFrame
> resp(
129 spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
132 scoped_ptr
<SpdyFrame
> msg(
133 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
136 scoped_ptr
<SpdyFrame
> echo(
137 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
142 OrderedSocketData
data(GetReads(), GetNumReads(),
143 GetWrites(), GetNumWrites());
144 MockConnect
connect_data(SYNCHRONOUS
, OK
);
145 data
.set_connect_data(connect_data
);
147 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
149 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
151 base::WeakPtr
<SpdyStream
> stream
=
152 CreateStreamSynchronously(
153 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
154 ASSERT_TRUE(stream
.get() != NULL
);
156 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
157 stream
->SetDelegate(&delegate
);
159 EXPECT_FALSE(stream
->HasUrlFromHeaders());
161 scoped_ptr
<SpdyHeaderBlock
> headers(
162 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
163 EXPECT_EQ(ERR_IO_PENDING
,
164 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
165 EXPECT_TRUE(stream
->HasUrlFromHeaders());
166 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
168 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
170 EXPECT_TRUE(delegate
.send_headers_completed());
171 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
172 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
173 delegate
.TakeReceivedData());
174 EXPECT_TRUE(data
.at_write_eof());
177 TEST_P(SpdyStreamTest
, PushedStream
) {
178 session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
182 OrderedSocketData
data(GetReads(), GetNumReads(),
183 GetWrites(), GetNumWrites());
184 MockConnect
connect_data(SYNCHRONOUS
, OK
);
185 data
.set_connect_data(connect_data
);
187 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
189 base::WeakPtr
<SpdySession
> spdy_session(CreateDefaultSpdySession());
191 // Conjure up a stream.
192 SpdyStream
stream(SPDY_PUSH_STREAM
,
196 kSpdyStreamInitialWindowSize
,
197 kSpdyStreamInitialWindowSize
,
199 stream
.set_stream_id(2);
200 EXPECT_FALSE(stream
.HasUrlFromHeaders());
202 // Set required request headers.
203 SpdyHeaderBlock request_headers
;
204 spdy_util_
.AddUrlToHeaderBlock(kStreamUrl
, &request_headers
);
205 stream
.OnPushPromiseHeadersReceived(request_headers
);
207 // Send some basic response headers.
208 SpdyHeaderBlock response
;
209 response
[spdy_util_
.GetStatusKey()] = "200";
210 response
[spdy_util_
.GetVersionKey()] = "OK";
211 stream
.OnInitialResponseHeadersReceived(
212 response
, base::Time::Now(), base::TimeTicks::Now());
214 // And some more headers.
215 // TODO(baranovich): not valid for HTTP 2.
216 SpdyHeaderBlock headers
;
217 headers
["alpha"] = "beta";
218 stream
.OnAdditionalResponseHeadersReceived(headers
);
220 EXPECT_TRUE(stream
.HasUrlFromHeaders());
221 EXPECT_EQ(kStreamUrl
, stream
.GetUrlFromHeaders().spec());
223 StreamDelegateDoNothing
delegate(stream
.GetWeakPtr());
224 stream
.SetDelegate(&delegate
);
226 base::MessageLoop::current()->RunUntilIdle();
228 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
229 EXPECT_EQ("beta", delegate
.GetResponseHeaderValue("alpha"));
231 EXPECT_TRUE(spdy_session
== NULL
);
234 TEST_P(SpdyStreamTest
, StreamError
) {
235 GURL
url(kStreamUrl
);
237 session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
239 scoped_ptr
<SpdyFrame
> req(
240 spdy_util_
.ConstructSpdyPost(
241 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
244 scoped_ptr
<SpdyFrame
> resp(
245 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
248 scoped_ptr
<SpdyFrame
> msg(
249 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
252 scoped_ptr
<SpdyFrame
> echo(
253 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
258 CapturingBoundNetLog log
;
260 OrderedSocketData
data(GetReads(), GetNumReads(),
261 GetWrites(), GetNumWrites());
262 MockConnect
connect_data(SYNCHRONOUS
, OK
);
263 data
.set_connect_data(connect_data
);
265 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
267 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
269 base::WeakPtr
<SpdyStream
> stream
=
270 CreateStreamSynchronously(
271 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, log
.bound());
272 ASSERT_TRUE(stream
.get() != NULL
);
274 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
275 stream
->SetDelegate(&delegate
);
277 EXPECT_FALSE(stream
->HasUrlFromHeaders());
279 scoped_ptr
<SpdyHeaderBlock
> headers(
280 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
281 EXPECT_EQ(ERR_IO_PENDING
,
282 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
283 EXPECT_TRUE(stream
->HasUrlFromHeaders());
284 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
286 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
288 const SpdyStreamId stream_id
= delegate
.stream_id();
290 EXPECT_TRUE(delegate
.send_headers_completed());
291 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
292 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
293 delegate
.TakeReceivedData());
294 EXPECT_TRUE(data
.at_write_eof());
296 // Check that the NetLog was filled reasonably.
297 net::CapturingNetLog::CapturedEntryList entries
;
298 log
.GetEntries(&entries
);
299 EXPECT_LT(0u, entries
.size());
301 // Check that we logged SPDY_STREAM_ERROR correctly.
302 int pos
= net::ExpectLogContainsSomewhere(
304 net::NetLog::TYPE_SPDY_STREAM_ERROR
,
305 net::NetLog::PHASE_NONE
);
308 ASSERT_TRUE(entries
[pos
].GetIntegerValue("stream_id", &stream_id2
));
309 EXPECT_EQ(static_cast<int>(stream_id
), stream_id2
);
312 // Make sure that large blocks of data are properly split up into
313 // frame-sized chunks for a request/response (i.e., an HTTP-like)
315 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenRequestResponse
) {
316 GURL
url(kStreamUrl
);
318 session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
320 scoped_ptr
<SpdyFrame
> req(
321 spdy_util_
.ConstructSpdyPost(
322 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
325 std::string
chunk_data(kMaxSpdyFrameChunkSize
, 'x');
326 scoped_ptr
<SpdyFrame
> chunk(
327 spdy_util_
.ConstructSpdyBodyFrame(
328 1, chunk_data
.data(), chunk_data
.length(), false));
332 scoped_ptr
<SpdyFrame
> last_chunk(
333 spdy_util_
.ConstructSpdyBodyFrame(
334 1, chunk_data
.data(), chunk_data
.length(), true));
335 AddWrite(*last_chunk
);
337 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
342 OrderedSocketData
data(GetReads(), GetNumReads(),
343 GetWrites(), GetNumWrites());
344 MockConnect
connect_data(SYNCHRONOUS
, OK
);
345 data
.set_connect_data(connect_data
);
347 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
349 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
351 base::WeakPtr
<SpdyStream
> stream
=
352 CreateStreamSynchronously(
353 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
354 ASSERT_TRUE(stream
.get() != NULL
);
356 std::string
body_data(3 * kMaxSpdyFrameChunkSize
, 'x');
357 StreamDelegateWithBody
delegate(stream
, body_data
);
358 stream
->SetDelegate(&delegate
);
360 EXPECT_FALSE(stream
->HasUrlFromHeaders());
362 scoped_ptr
<SpdyHeaderBlock
> headers(
363 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
364 EXPECT_EQ(ERR_IO_PENDING
,
365 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
366 EXPECT_TRUE(stream
->HasUrlFromHeaders());
367 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
369 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
371 EXPECT_TRUE(delegate
.send_headers_completed());
372 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
373 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
374 EXPECT_TRUE(data
.at_write_eof());
377 // Make sure that large blocks of data are properly split up into
378 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
380 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenBidirectional
) {
381 GURL
url(kStreamUrl
);
383 session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
385 scoped_ptr
<SpdyFrame
> req(
386 spdy_util_
.ConstructSpdyPost(
387 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
390 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
393 std::string
chunk_data(kMaxSpdyFrameChunkSize
, 'x');
394 scoped_ptr
<SpdyFrame
> chunk(
395 spdy_util_
.ConstructSpdyBodyFrame(
396 1, chunk_data
.data(), chunk_data
.length(), false));
403 OrderedSocketData
data(GetReads(), GetNumReads(),
404 GetWrites(), GetNumWrites());
405 MockConnect
connect_data(SYNCHRONOUS
, OK
);
406 data
.set_connect_data(connect_data
);
408 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
410 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
412 base::WeakPtr
<SpdyStream
> stream
=
413 CreateStreamSynchronously(
414 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
415 ASSERT_TRUE(stream
.get() != NULL
);
417 std::string
body_data(3 * kMaxSpdyFrameChunkSize
, 'x');
418 StreamDelegateSendImmediate
delegate(stream
, body_data
);
419 stream
->SetDelegate(&delegate
);
421 EXPECT_FALSE(stream
->HasUrlFromHeaders());
423 scoped_ptr
<SpdyHeaderBlock
> headers(
424 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
425 EXPECT_EQ(ERR_IO_PENDING
,
426 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
427 EXPECT_TRUE(stream
->HasUrlFromHeaders());
428 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
430 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
432 EXPECT_TRUE(delegate
.send_headers_completed());
433 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
434 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
435 EXPECT_TRUE(data
.at_write_eof());
438 // Receiving a header with uppercase ASCII should result in a protocol
440 TEST_P(SpdyStreamTest
, UpperCaseHeaders
) {
441 GURL
url(kStreamUrl
);
444 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
446 scoped_ptr
<SpdyFrame
> syn(
447 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
450 const char* const kExtraHeaders
[] = {"X-UpperCase", "yes"};
451 scoped_ptr
<SpdyFrame
>
452 reply(spdy_util_
.ConstructSpdyGetSynReply(kExtraHeaders
, 1, 1));
455 scoped_ptr
<SpdyFrame
> rst(
456 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
461 DeterministicSocketData
data(GetReads(), GetNumReads(),
462 GetWrites(), GetNumWrites());
463 MockConnect
connect_data(SYNCHRONOUS
, OK
);
464 data
.set_connect_data(connect_data
);
466 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
468 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
470 base::WeakPtr
<SpdyStream
> stream
=
471 CreateStreamSynchronously(
472 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
473 ASSERT_TRUE(stream
.get() != NULL
);
475 StreamDelegateDoNothing
delegate(stream
);
476 stream
->SetDelegate(&delegate
);
478 EXPECT_FALSE(stream
->HasUrlFromHeaders());
480 scoped_ptr
<SpdyHeaderBlock
> headers(
481 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
482 EXPECT_EQ(ERR_IO_PENDING
,
483 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
484 EXPECT_TRUE(stream
->HasUrlFromHeaders());
485 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
489 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
492 // Receiving a header with uppercase ASCII should result in a protocol
493 // error even for a push stream.
494 TEST_P(SpdyStreamTest
, UpperCaseHeadersOnPush
) {
495 GURL
url(kStreamUrl
);
498 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
500 scoped_ptr
<SpdyFrame
> syn(
501 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
504 scoped_ptr
<SpdyFrame
>
505 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
508 const char* const extra_headers
[] = {"X-UpperCase", "yes"};
509 scoped_ptr
<SpdyFrame
>
510 push(spdy_util_
.ConstructSpdyPush(extra_headers
, 1, 2, 1, kStreamUrl
));
513 scoped_ptr
<SpdyFrame
> rst(
514 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
519 DeterministicSocketData
data(GetReads(), GetNumReads(),
520 GetWrites(), GetNumWrites());
521 MockConnect
connect_data(SYNCHRONOUS
, OK
);
522 data
.set_connect_data(connect_data
);
524 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
526 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
528 base::WeakPtr
<SpdyStream
> stream
=
529 CreateStreamSynchronously(
530 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
531 ASSERT_TRUE(stream
.get() != NULL
);
533 StreamDelegateDoNothing
delegate(stream
);
534 stream
->SetDelegate(&delegate
);
536 EXPECT_FALSE(stream
->HasUrlFromHeaders());
538 scoped_ptr
<SpdyHeaderBlock
> headers(
539 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
540 EXPECT_EQ(ERR_IO_PENDING
,
541 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
542 EXPECT_TRUE(stream
->HasUrlFromHeaders());
543 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
547 base::WeakPtr
<SpdyStream
> push_stream
;
548 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
549 EXPECT_FALSE(push_stream
);
553 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
556 // Receiving a header with uppercase ASCII in a HEADERS frame should
557 // result in a protocol error.
558 TEST_P(SpdyStreamTest
, UpperCaseHeadersInHeadersFrame
) {
559 GURL
url(kStreamUrl
);
562 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
564 scoped_ptr
<SpdyFrame
> syn(
565 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
568 scoped_ptr
<SpdyFrame
>
569 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
572 scoped_ptr
<SpdyFrame
>
573 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
576 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
577 (*late_headers
)["X-UpperCase"] = "yes";
578 scoped_ptr
<SpdyFrame
> headers_frame(
579 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
586 AddRead(*headers_frame
);
588 scoped_ptr
<SpdyFrame
> rst(
589 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
594 DeterministicSocketData
data(GetReads(), GetNumReads(),
595 GetWrites(), GetNumWrites());
596 MockConnect
connect_data(SYNCHRONOUS
, OK
);
597 data
.set_connect_data(connect_data
);
599 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
601 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
603 base::WeakPtr
<SpdyStream
> stream
=
604 CreateStreamSynchronously(
605 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
606 ASSERT_TRUE(stream
.get() != NULL
);
608 StreamDelegateDoNothing
delegate(stream
);
609 stream
->SetDelegate(&delegate
);
611 EXPECT_FALSE(stream
->HasUrlFromHeaders());
613 scoped_ptr
<SpdyHeaderBlock
> headers(
614 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
615 EXPECT_EQ(ERR_IO_PENDING
,
616 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
617 EXPECT_TRUE(stream
->HasUrlFromHeaders());
618 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
622 base::WeakPtr
<SpdyStream
> push_stream
;
623 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
624 EXPECT_TRUE(push_stream
);
628 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
629 EXPECT_FALSE(push_stream
);
633 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
636 // Receiving a duplicate header in a HEADERS frame should result in a
638 TEST_P(SpdyStreamTest
, DuplicateHeaders
) {
639 GURL
url(kStreamUrl
);
642 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
644 scoped_ptr
<SpdyFrame
> syn(
645 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
648 scoped_ptr
<SpdyFrame
>
649 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
652 scoped_ptr
<SpdyFrame
>
653 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
656 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
657 (*late_headers
)[spdy_util_
.GetStatusKey()] = "500 Server Error";
658 scoped_ptr
<SpdyFrame
> headers_frame(
659 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
666 AddRead(*headers_frame
);
668 scoped_ptr
<SpdyFrame
> rst(
669 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
674 DeterministicSocketData
data(GetReads(), GetNumReads(),
675 GetWrites(), GetNumWrites());
676 MockConnect
connect_data(SYNCHRONOUS
, OK
);
677 data
.set_connect_data(connect_data
);
679 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
681 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
683 base::WeakPtr
<SpdyStream
> stream
=
684 CreateStreamSynchronously(
685 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
686 ASSERT_TRUE(stream
.get() != NULL
);
688 StreamDelegateDoNothing
delegate(stream
);
689 stream
->SetDelegate(&delegate
);
691 EXPECT_FALSE(stream
->HasUrlFromHeaders());
693 scoped_ptr
<SpdyHeaderBlock
> headers(
694 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
695 EXPECT_EQ(ERR_IO_PENDING
,
696 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
697 EXPECT_TRUE(stream
->HasUrlFromHeaders());
698 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
702 base::WeakPtr
<SpdyStream
> push_stream
;
703 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
704 EXPECT_TRUE(push_stream
);
708 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
709 EXPECT_FALSE(push_stream
);
713 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
716 // The tests below are only for SPDY/3 and above.
718 // Call IncreaseSendWindowSize on a stream with a large enough delta
719 // to overflow an int32. The SpdyStream should handle that case
721 TEST_P(SpdyStreamTest
, IncreaseSendWindowSizeOverflow
) {
722 if (spdy_util_
.protocol() < kProtoSPDY3
)
726 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
728 scoped_ptr
<SpdyFrame
> req(
729 spdy_util_
.ConstructSpdyPost(
730 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
733 // Triggered by the overflowing call to IncreaseSendWindowSize
735 scoped_ptr
<SpdyFrame
> rst(
736 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR
));
741 CapturingBoundNetLog log
;
743 DeterministicSocketData
data(GetReads(), GetNumReads(),
744 GetWrites(), GetNumWrites());
745 MockConnect
connect_data(SYNCHRONOUS
, OK
);
746 data
.set_connect_data(connect_data
);
748 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
750 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
751 GURL
url(kStreamUrl
);
753 base::WeakPtr
<SpdyStream
> stream
=
754 CreateStreamSynchronously(
755 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, log
.bound());
756 ASSERT_TRUE(stream
.get() != NULL
);
757 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
758 stream
->SetDelegate(&delegate
);
760 scoped_ptr
<SpdyHeaderBlock
> headers(
761 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
762 EXPECT_EQ(ERR_IO_PENDING
,
763 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
764 EXPECT_TRUE(stream
->HasUrlFromHeaders());
765 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
769 int32 old_send_window_size
= stream
->send_window_size();
770 ASSERT_GT(old_send_window_size
, 0);
771 int32 delta_window_size
= kint32max
- old_send_window_size
+ 1;
772 stream
->IncreaseSendWindowSize(delta_window_size
);
773 EXPECT_EQ(NULL
, stream
.get());
777 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
780 // Functions used with
781 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
783 void StallStream(const base::WeakPtr
<SpdyStream
>& stream
) {
784 // Reduce the send window size to 0 to stall.
785 while (stream
->send_window_size() > 0) {
786 stream
->DecreaseSendWindowSize(
787 std::min(kMaxSpdyFrameChunkSize
, stream
->send_window_size()));
791 void IncreaseStreamSendWindowSize(const base::WeakPtr
<SpdyStream
>& stream
,
792 int32 delta_window_size
) {
793 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
794 stream
->IncreaseSendWindowSize(delta_window_size
);
795 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
798 void AdjustStreamSendWindowSize(const base::WeakPtr
<SpdyStream
>& stream
,
799 int32 delta_window_size
) {
800 // Make sure that negative adjustments are handled properly.
801 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
802 stream
->AdjustSendWindowSize(-delta_window_size
);
803 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
804 stream
->AdjustSendWindowSize(+delta_window_size
);
805 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
806 stream
->AdjustSendWindowSize(+delta_window_size
);
807 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
810 // Given an unstall function, runs a test to make sure that a
811 // request/response (i.e., an HTTP-like) stream resumes after a stall
813 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
814 const UnstallFunction
& unstall_function
) {
815 GURL
url(kStreamUrl
);
818 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
820 scoped_ptr
<SpdyFrame
> req(
821 spdy_util_
.ConstructSpdyPost(
822 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
825 scoped_ptr
<SpdyFrame
> body(
826 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, true));
829 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
834 DeterministicSocketData
data(GetReads(), GetNumReads(),
835 GetWrites(), GetNumWrites());
836 MockConnect
connect_data(SYNCHRONOUS
, OK
);
837 data
.set_connect_data(connect_data
);
839 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
841 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
843 base::WeakPtr
<SpdyStream
> stream
=
844 CreateStreamSynchronously(
845 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
846 ASSERT_TRUE(stream
.get() != NULL
);
848 StreamDelegateWithBody
delegate(stream
, kPostBodyStringPiece
);
849 stream
->SetDelegate(&delegate
);
851 EXPECT_FALSE(stream
->HasUrlFromHeaders());
852 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
854 scoped_ptr
<SpdyHeaderBlock
> headers(
855 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
856 EXPECT_EQ(ERR_IO_PENDING
,
857 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
858 EXPECT_TRUE(stream
->HasUrlFromHeaders());
859 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
865 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
867 unstall_function
.Run(stream
, kPostBodyLength
);
869 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
873 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
875 EXPECT_TRUE(delegate
.send_headers_completed());
876 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
877 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
878 EXPECT_TRUE(data
.at_write_eof());
881 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseRequestResponse
) {
882 if (spdy_util_
.protocol() < kProtoSPDY3
)
885 RunResumeAfterUnstallRequestResponseTest(
886 base::Bind(&IncreaseStreamSendWindowSize
));
889 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustRequestResponse
) {
890 if (spdy_util_
.protocol() < kProtoSPDY3
)
893 RunResumeAfterUnstallRequestResponseTest(
894 base::Bind(&AdjustStreamSendWindowSize
));
897 // Given an unstall function, runs a test to make sure that a
898 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
900 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
901 const UnstallFunction
& unstall_function
) {
902 GURL
url(kStreamUrl
);
905 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
907 scoped_ptr
<SpdyFrame
> req(
908 spdy_util_
.ConstructSpdyPost(
909 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
912 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
915 scoped_ptr
<SpdyFrame
> msg(
916 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
919 scoped_ptr
<SpdyFrame
> echo(
920 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
925 DeterministicSocketData
data(GetReads(), GetNumReads(),
926 GetWrites(), GetNumWrites());
927 MockConnect
connect_data(SYNCHRONOUS
, OK
);
928 data
.set_connect_data(connect_data
);
930 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
932 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
934 base::WeakPtr
<SpdyStream
> stream
=
935 CreateStreamSynchronously(
936 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
937 ASSERT_TRUE(stream
.get() != NULL
);
939 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
940 stream
->SetDelegate(&delegate
);
942 EXPECT_FALSE(stream
->HasUrlFromHeaders());
944 scoped_ptr
<SpdyHeaderBlock
> headers(
945 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
946 EXPECT_EQ(ERR_IO_PENDING
,
947 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
948 EXPECT_TRUE(stream
->HasUrlFromHeaders());
949 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
953 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
959 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
961 unstall_function
.Run(stream
, kPostBodyLength
);
963 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
967 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
969 EXPECT_TRUE(delegate
.send_headers_completed());
970 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
971 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
972 delegate
.TakeReceivedData());
973 EXPECT_TRUE(data
.at_write_eof());
976 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseBidirectional
) {
977 if (spdy_util_
.protocol() < kProtoSPDY3
)
980 RunResumeAfterUnstallBidirectionalTest(
981 base::Bind(&IncreaseStreamSendWindowSize
));
984 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustBidirectional
) {
985 if (spdy_util_
.protocol() < kProtoSPDY3
)
988 RunResumeAfterUnstallBidirectionalTest(
989 base::Bind(&AdjustStreamSendWindowSize
));
992 // Test calculation of amount of bytes received from network.
993 TEST_P(SpdyStreamTest
, ReceivedBytes
) {
994 GURL
url(kStreamUrl
);
997 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
999 scoped_ptr
<SpdyFrame
> syn(
1000 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1003 scoped_ptr
<SpdyFrame
>
1004 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1007 scoped_ptr
<SpdyFrame
> msg(
1008 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
1013 DeterministicSocketData
data(GetReads(), GetNumReads(),
1014 GetWrites(), GetNumWrites());
1015 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1016 data
.set_connect_data(connect_data
);
1018 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1020 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
1022 base::WeakPtr
<SpdyStream
> stream
=
1023 CreateStreamSynchronously(
1024 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
1025 ASSERT_TRUE(stream
.get() != NULL
);
1027 StreamDelegateDoNothing
delegate(stream
);
1028 stream
->SetDelegate(&delegate
);
1030 EXPECT_FALSE(stream
->HasUrlFromHeaders());
1032 scoped_ptr
<SpdyHeaderBlock
> headers(
1033 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
1034 EXPECT_EQ(ERR_IO_PENDING
,
1035 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
1036 EXPECT_TRUE(stream
->HasUrlFromHeaders());
1037 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
1039 int64 reply_frame_len
= reply
->size();
1040 int64 data_header_len
= spdy_util_
.CreateFramer(false)
1041 ->GetDataFrameMinimumSize();
1042 int64 data_frame_len
= data_header_len
+ kPostBodyLength
;
1043 int64 response_len
= reply_frame_len
+ data_frame_len
;
1045 EXPECT_EQ(0, stream
->raw_received_bytes());
1046 data
.RunFor(1); // SYN
1047 EXPECT_EQ(0, stream
->raw_received_bytes());
1048 data
.RunFor(1); // REPLY
1049 EXPECT_EQ(reply_frame_len
, stream
->raw_received_bytes());
1050 data
.RunFor(1); // DATA
1051 EXPECT_EQ(response_len
, stream
->raw_received_bytes());
1052 data
.RunFor(1); // FIN
1054 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());