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/request_priority.h"
15 #include "net/log/net_log_unittest.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.example.org/";
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.example.org", 80),
55 ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
56 return CreateInsecureSpdySession(session_
, key
, BoundNetLog());
59 void TearDown() override
{ base::MessageLoop::current()->RunUntilIdle(); }
61 void RunResumeAfterUnstallRequestResponseTest(
62 const UnstallFunction
& unstall_function
);
64 void RunResumeAfterUnstallBidirectionalTest(
65 const UnstallFunction
& unstall_function
);
67 // Add{Read,Write}() populates lists that are eventually passed to a
68 // SocketData class. |frame| must live for the whole test.
70 void AddRead(const SpdyFrame
& frame
) {
71 reads_
.push_back(CreateMockRead(frame
, offset_
++));
74 void AddWrite(const SpdyFrame
& frame
) {
75 writes_
.push_back(CreateMockWrite(frame
, offset_
++));
79 reads_
.push_back(MockRead(ASYNC
, 0, offset_
++));
82 MockRead
* GetReads() {
83 return vector_as_array(&reads_
);
86 size_t GetNumReads() const {
90 MockWrite
* GetWrites() {
91 return vector_as_array(&writes_
);
94 int GetNumWrites() const {
95 return writes_
.size();
98 SpdyTestUtil spdy_util_
;
99 SpdySessionDependencies session_deps_
;
100 scoped_refptr
<HttpNetworkSession
> session_
;
103 // Used by Add{Read,Write}() above.
104 std::vector
<MockWrite
> writes_
;
105 std::vector
<MockRead
> reads_
;
109 INSTANTIATE_TEST_CASE_P(NextProto
,
111 testing::Values(kProtoSPDY31
,
115 TEST_P(SpdyStreamTest
, SendDataAfterOpen
) {
116 GURL
url(kStreamUrl
);
119 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
121 scoped_ptr
<SpdyFrame
> req(
122 spdy_util_
.ConstructSpdyPost(
123 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
126 scoped_ptr
<SpdyFrame
> resp(
127 spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
130 scoped_ptr
<SpdyFrame
> msg(
131 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
134 scoped_ptr
<SpdyFrame
> echo(
135 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
140 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
142 MockConnect
connect_data(SYNCHRONOUS
, OK
);
143 data
.set_connect_data(connect_data
);
145 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
147 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
149 base::WeakPtr
<SpdyStream
> stream
=
150 CreateStreamSynchronously(
151 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
152 ASSERT_TRUE(stream
.get() != NULL
);
154 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
155 stream
->SetDelegate(&delegate
);
157 EXPECT_FALSE(stream
->HasUrlFromHeaders());
159 scoped_ptr
<SpdyHeaderBlock
> headers(
160 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
161 EXPECT_EQ(ERR_IO_PENDING
,
162 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
163 EXPECT_TRUE(stream
->HasUrlFromHeaders());
164 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
166 data
.RunFor(GetNumReads() + GetNumWrites());
167 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
169 EXPECT_TRUE(delegate
.send_headers_completed());
170 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
171 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
172 delegate
.TakeReceivedData());
173 EXPECT_TRUE(data
.at_write_eof());
176 TEST_P(SpdyStreamTest
, PushedStream
) {
178 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
182 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
184 MockConnect
connect_data(SYNCHRONOUS
, OK
);
185 data
.set_connect_data(connect_data
);
187 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
189 base::WeakPtr
<SpdySession
> spdy_session(CreateDefaultSpdySession());
191 // Conjure up a stream.
192 SpdyStream
stream(SPDY_PUSH_STREAM
, spdy_session
, GURL(), DEFAULT_PRIORITY
,
193 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31
),
194 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31
),
196 stream
.set_stream_id(2);
197 EXPECT_FALSE(stream
.HasUrlFromHeaders());
199 // Set required request headers.
200 SpdyHeaderBlock request_headers
;
201 spdy_util_
.AddUrlToHeaderBlock(kStreamUrl
, &request_headers
);
202 stream
.OnPushPromiseHeadersReceived(request_headers
);
204 // Send some basic response headers.
205 SpdyHeaderBlock response
;
206 response
[spdy_util_
.GetStatusKey()] = "200";
207 response
[spdy_util_
.GetVersionKey()] = "OK";
208 stream
.OnInitialResponseHeadersReceived(
209 response
, base::Time::Now(), base::TimeTicks::Now());
211 // And some more headers.
212 // TODO(baranovich): not valid for HTTP 2.
213 SpdyHeaderBlock headers
;
214 headers
["alpha"] = "beta";
215 stream
.OnAdditionalResponseHeadersReceived(headers
);
217 EXPECT_TRUE(stream
.HasUrlFromHeaders());
218 EXPECT_EQ(kStreamUrl
, stream
.GetUrlFromHeaders().spec());
220 StreamDelegateDoNothing
delegate(stream
.GetWeakPtr());
221 stream
.SetDelegate(&delegate
);
223 data
.RunFor(GetNumReads() + GetNumWrites());
225 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
226 EXPECT_EQ("beta", delegate
.GetResponseHeaderValue("alpha"));
228 EXPECT_TRUE(spdy_session
== NULL
);
231 TEST_P(SpdyStreamTest
, StreamError
) {
232 GURL
url(kStreamUrl
);
235 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
237 scoped_ptr
<SpdyFrame
> req(
238 spdy_util_
.ConstructSpdyPost(
239 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
242 scoped_ptr
<SpdyFrame
> resp(
243 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
246 scoped_ptr
<SpdyFrame
> msg(
247 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
250 scoped_ptr
<SpdyFrame
> echo(
251 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
258 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
260 MockConnect
connect_data(SYNCHRONOUS
, OK
);
261 data
.set_connect_data(connect_data
);
263 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
265 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
267 base::WeakPtr
<SpdyStream
> stream
=
268 CreateStreamSynchronously(
269 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, log
.bound());
270 ASSERT_TRUE(stream
.get() != NULL
);
272 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
273 stream
->SetDelegate(&delegate
);
275 EXPECT_FALSE(stream
->HasUrlFromHeaders());
277 scoped_ptr
<SpdyHeaderBlock
> headers(
278 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
279 EXPECT_EQ(ERR_IO_PENDING
,
280 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
281 EXPECT_TRUE(stream
->HasUrlFromHeaders());
282 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
284 data
.RunFor(GetNumReads() + GetNumWrites());
285 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
287 const SpdyStreamId stream_id
= delegate
.stream_id();
289 EXPECT_TRUE(delegate
.send_headers_completed());
290 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
291 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
292 delegate
.TakeReceivedData());
293 EXPECT_TRUE(data
.at_write_eof());
295 // Check that the NetLog was filled reasonably.
296 TestNetLog::CapturedEntryList entries
;
297 log
.GetEntries(&entries
);
298 EXPECT_LT(0u, entries
.size());
300 // Check that we logged SPDY_STREAM_ERROR correctly.
301 int pos
= ExpectLogContainsSomewhere(
302 entries
, 0, NetLog::TYPE_HTTP2_STREAM_ERROR
, NetLog::PHASE_NONE
);
305 ASSERT_TRUE(entries
[pos
].GetIntegerValue("stream_id", &stream_id2
));
306 EXPECT_EQ(static_cast<int>(stream_id
), stream_id2
);
309 // Make sure that large blocks of data are properly split up into
310 // frame-sized chunks for a request/response (i.e., an HTTP-like)
312 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenRequestResponse
) {
313 GURL
url(kStreamUrl
);
316 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
318 scoped_ptr
<SpdyFrame
> req(
319 spdy_util_
.ConstructSpdyPost(
320 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
323 std::string
chunk_data(kMaxSpdyFrameChunkSize
, 'x');
324 scoped_ptr
<SpdyFrame
> chunk(
325 spdy_util_
.ConstructSpdyBodyFrame(
326 1, chunk_data
.data(), chunk_data
.length(), false));
330 scoped_ptr
<SpdyFrame
> last_chunk(
331 spdy_util_
.ConstructSpdyBodyFrame(
332 1, chunk_data
.data(), chunk_data
.length(), true));
333 AddWrite(*last_chunk
);
335 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
340 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
342 MockConnect
connect_data(SYNCHRONOUS
, OK
);
343 data
.set_connect_data(connect_data
);
345 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
347 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
349 base::WeakPtr
<SpdyStream
> stream
=
350 CreateStreamSynchronously(
351 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
352 ASSERT_TRUE(stream
.get() != NULL
);
354 std::string
body_data(3 * kMaxSpdyFrameChunkSize
, 'x');
355 StreamDelegateWithBody
delegate(stream
, body_data
);
356 stream
->SetDelegate(&delegate
);
358 EXPECT_FALSE(stream
->HasUrlFromHeaders());
360 scoped_ptr
<SpdyHeaderBlock
> headers(
361 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
362 EXPECT_EQ(ERR_IO_PENDING
,
363 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
364 EXPECT_TRUE(stream
->HasUrlFromHeaders());
365 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
367 data
.RunFor(GetNumReads() + GetNumWrites());
368 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
370 EXPECT_TRUE(delegate
.send_headers_completed());
371 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
372 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
373 EXPECT_TRUE(data
.at_write_eof());
376 // Make sure that large blocks of data are properly split up into
377 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
379 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenBidirectional
) {
380 GURL
url(kStreamUrl
);
383 SpdySessionDependencies::SpdyCreateSessionDeterministic(&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 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
405 MockConnect
connect_data(SYNCHRONOUS
, OK
);
406 data
.set_connect_data(connect_data
);
408 session_deps_
.deterministic_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 data
.RunFor(GetNumReads() + GetNumWrites());
431 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
433 EXPECT_TRUE(delegate
.send_headers_completed());
434 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
435 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
436 EXPECT_TRUE(data
.at_write_eof());
439 // Receiving a header with uppercase ASCII should result in a protocol
441 TEST_P(SpdyStreamTest
, UpperCaseHeaders
) {
442 GURL
url(kStreamUrl
);
445 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
447 scoped_ptr
<SpdyFrame
> syn(
448 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
451 const char* const kExtraHeaders
[] = {"X-UpperCase", "yes"};
452 scoped_ptr
<SpdyFrame
>
453 reply(spdy_util_
.ConstructSpdyGetSynReply(kExtraHeaders
, 1, 1));
456 scoped_ptr
<SpdyFrame
> rst(
457 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
462 DeterministicSocketData
data(GetReads(), GetNumReads(),
463 GetWrites(), GetNumWrites());
464 MockConnect
connect_data(SYNCHRONOUS
, OK
);
465 data
.set_connect_data(connect_data
);
467 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
469 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
471 base::WeakPtr
<SpdyStream
> stream
=
472 CreateStreamSynchronously(
473 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
474 ASSERT_TRUE(stream
.get() != NULL
);
476 StreamDelegateDoNothing
delegate(stream
);
477 stream
->SetDelegate(&delegate
);
479 EXPECT_FALSE(stream
->HasUrlFromHeaders());
481 scoped_ptr
<SpdyHeaderBlock
> headers(
482 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
483 EXPECT_EQ(ERR_IO_PENDING
,
484 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
485 EXPECT_TRUE(stream
->HasUrlFromHeaders());
486 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
490 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
493 // Receiving a header with uppercase ASCII should result in a protocol
494 // error even for a push stream.
495 TEST_P(SpdyStreamTest
, UpperCaseHeadersOnPush
) {
496 GURL
url(kStreamUrl
);
499 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
501 scoped_ptr
<SpdyFrame
> syn(
502 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
505 scoped_ptr
<SpdyFrame
>
506 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
509 const char* const extra_headers
[] = {"X-UpperCase", "yes"};
510 scoped_ptr
<SpdyFrame
>
511 push(spdy_util_
.ConstructSpdyPush(extra_headers
, 1, 2, 1, kStreamUrl
));
514 scoped_ptr
<SpdyFrame
> rst(
515 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
520 DeterministicSocketData
data(GetReads(), GetNumReads(),
521 GetWrites(), GetNumWrites());
522 MockConnect
connect_data(SYNCHRONOUS
, OK
);
523 data
.set_connect_data(connect_data
);
525 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
527 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
529 base::WeakPtr
<SpdyStream
> stream
=
530 CreateStreamSynchronously(
531 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
532 ASSERT_TRUE(stream
.get() != NULL
);
534 StreamDelegateDoNothing
delegate(stream
);
535 stream
->SetDelegate(&delegate
);
537 EXPECT_FALSE(stream
->HasUrlFromHeaders());
539 scoped_ptr
<SpdyHeaderBlock
> headers(
540 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
541 EXPECT_EQ(ERR_IO_PENDING
,
542 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
543 EXPECT_TRUE(stream
->HasUrlFromHeaders());
544 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
548 base::WeakPtr
<SpdyStream
> push_stream
;
549 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
550 EXPECT_FALSE(push_stream
);
554 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
557 // Receiving a header with uppercase ASCII in a HEADERS frame should
558 // result in a protocol error.
559 TEST_P(SpdyStreamTest
, UpperCaseHeadersInHeadersFrame
) {
560 GURL
url(kStreamUrl
);
563 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
565 scoped_ptr
<SpdyFrame
> syn(
566 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
569 scoped_ptr
<SpdyFrame
>
570 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
573 scoped_ptr
<SpdyFrame
>
574 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
577 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
578 (*late_headers
)["X-UpperCase"] = "yes";
579 scoped_ptr
<SpdyFrame
> headers_frame(
580 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
587 AddRead(*headers_frame
);
589 scoped_ptr
<SpdyFrame
> rst(
590 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
595 DeterministicSocketData
data(GetReads(), GetNumReads(),
596 GetWrites(), GetNumWrites());
597 MockConnect
connect_data(SYNCHRONOUS
, OK
);
598 data
.set_connect_data(connect_data
);
600 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
602 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
604 base::WeakPtr
<SpdyStream
> stream
=
605 CreateStreamSynchronously(
606 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
607 ASSERT_TRUE(stream
.get() != NULL
);
609 StreamDelegateDoNothing
delegate(stream
);
610 stream
->SetDelegate(&delegate
);
612 EXPECT_FALSE(stream
->HasUrlFromHeaders());
614 scoped_ptr
<SpdyHeaderBlock
> headers(
615 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
616 EXPECT_EQ(ERR_IO_PENDING
,
617 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
618 EXPECT_TRUE(stream
->HasUrlFromHeaders());
619 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
623 base::WeakPtr
<SpdyStream
> push_stream
;
624 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
625 EXPECT_TRUE(push_stream
);
629 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
630 EXPECT_FALSE(push_stream
);
634 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
637 // Receiving a duplicate header in a HEADERS frame should result in a
639 TEST_P(SpdyStreamTest
, DuplicateHeaders
) {
640 GURL
url(kStreamUrl
);
643 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
645 scoped_ptr
<SpdyFrame
> syn(
646 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
649 scoped_ptr
<SpdyFrame
>
650 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
653 scoped_ptr
<SpdyFrame
>
654 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
657 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
658 (*late_headers
)[spdy_util_
.GetStatusKey()] = "500 Server Error";
659 scoped_ptr
<SpdyFrame
> headers_frame(
660 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
667 AddRead(*headers_frame
);
669 scoped_ptr
<SpdyFrame
> rst(
670 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
675 DeterministicSocketData
data(GetReads(), GetNumReads(),
676 GetWrites(), GetNumWrites());
677 MockConnect
connect_data(SYNCHRONOUS
, OK
);
678 data
.set_connect_data(connect_data
);
680 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
682 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
684 base::WeakPtr
<SpdyStream
> stream
=
685 CreateStreamSynchronously(
686 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
687 ASSERT_TRUE(stream
.get() != NULL
);
689 StreamDelegateDoNothing
delegate(stream
);
690 stream
->SetDelegate(&delegate
);
692 EXPECT_FALSE(stream
->HasUrlFromHeaders());
694 scoped_ptr
<SpdyHeaderBlock
> headers(
695 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
696 EXPECT_EQ(ERR_IO_PENDING
,
697 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
698 EXPECT_TRUE(stream
->HasUrlFromHeaders());
699 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
703 base::WeakPtr
<SpdyStream
> push_stream
;
704 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
705 EXPECT_TRUE(push_stream
);
709 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
710 EXPECT_FALSE(push_stream
);
714 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
717 // The tests below are only for SPDY/3 and above.
719 // Call IncreaseSendWindowSize on a stream with a large enough delta
720 // to overflow an int32. The SpdyStream should handle that case
722 TEST_P(SpdyStreamTest
, IncreaseSendWindowSizeOverflow
) {
724 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
726 scoped_ptr
<SpdyFrame
> req(
727 spdy_util_
.ConstructSpdyPost(
728 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
731 // Triggered by the overflowing call to IncreaseSendWindowSize
733 scoped_ptr
<SpdyFrame
> rst(
734 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR
));
741 DeterministicSocketData
data(GetReads(), GetNumReads(),
742 GetWrites(), GetNumWrites());
743 MockConnect
connect_data(SYNCHRONOUS
, OK
);
744 data
.set_connect_data(connect_data
);
746 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
748 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
749 GURL
url(kStreamUrl
);
751 base::WeakPtr
<SpdyStream
> stream
=
752 CreateStreamSynchronously(
753 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, log
.bound());
754 ASSERT_TRUE(stream
.get() != NULL
);
755 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
756 stream
->SetDelegate(&delegate
);
758 scoped_ptr
<SpdyHeaderBlock
> headers(
759 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
760 EXPECT_EQ(ERR_IO_PENDING
,
761 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
762 EXPECT_TRUE(stream
->HasUrlFromHeaders());
763 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
767 int32 old_send_window_size
= stream
->send_window_size();
768 ASSERT_GT(old_send_window_size
, 0);
769 int32 delta_window_size
= kint32max
- old_send_window_size
+ 1;
770 stream
->IncreaseSendWindowSize(delta_window_size
);
771 EXPECT_EQ(NULL
, stream
.get());
775 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
778 // Functions used with
779 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
781 void StallStream(const base::WeakPtr
<SpdyStream
>& stream
) {
782 // Reduce the send window size to 0 to stall.
783 while (stream
->send_window_size() > 0) {
784 stream
->DecreaseSendWindowSize(
785 std::min(kMaxSpdyFrameChunkSize
, stream
->send_window_size()));
789 void IncreaseStreamSendWindowSize(const base::WeakPtr
<SpdyStream
>& stream
,
790 int32 delta_window_size
) {
791 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
792 stream
->IncreaseSendWindowSize(delta_window_size
);
793 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
796 void AdjustStreamSendWindowSize(const base::WeakPtr
<SpdyStream
>& stream
,
797 int32 delta_window_size
) {
798 // Make sure that negative adjustments are handled properly.
799 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
800 stream
->AdjustSendWindowSize(-delta_window_size
);
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_FALSE(stream
->send_stalled_by_flow_control());
808 // Given an unstall function, runs a test to make sure that a
809 // request/response (i.e., an HTTP-like) stream resumes after a stall
811 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
812 const UnstallFunction
& unstall_function
) {
813 GURL
url(kStreamUrl
);
816 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
818 scoped_ptr
<SpdyFrame
> req(
819 spdy_util_
.ConstructSpdyPost(
820 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
823 scoped_ptr
<SpdyFrame
> body(
824 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, true));
827 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
832 DeterministicSocketData
data(GetReads(), GetNumReads(),
833 GetWrites(), GetNumWrites());
834 MockConnect
connect_data(SYNCHRONOUS
, OK
);
835 data
.set_connect_data(connect_data
);
837 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
839 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
841 base::WeakPtr
<SpdyStream
> stream
=
842 CreateStreamSynchronously(
843 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
844 ASSERT_TRUE(stream
.get() != NULL
);
846 StreamDelegateWithBody
delegate(stream
, kPostBodyStringPiece
);
847 stream
->SetDelegate(&delegate
);
849 EXPECT_FALSE(stream
->HasUrlFromHeaders());
850 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
852 scoped_ptr
<SpdyHeaderBlock
> headers(
853 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
854 EXPECT_EQ(ERR_IO_PENDING
,
855 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
856 EXPECT_TRUE(stream
->HasUrlFromHeaders());
857 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
863 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
865 unstall_function
.Run(stream
, kPostBodyLength
);
867 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
871 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
873 EXPECT_TRUE(delegate
.send_headers_completed());
874 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
875 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
876 EXPECT_TRUE(data
.at_write_eof());
879 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseRequestResponse
) {
880 RunResumeAfterUnstallRequestResponseTest(
881 base::Bind(&IncreaseStreamSendWindowSize
));
884 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustRequestResponse
) {
885 RunResumeAfterUnstallRequestResponseTest(
886 base::Bind(&AdjustStreamSendWindowSize
));
889 // Given an unstall function, runs a test to make sure that a
890 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
892 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
893 const UnstallFunction
& unstall_function
) {
894 GURL
url(kStreamUrl
);
897 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
899 scoped_ptr
<SpdyFrame
> req(
900 spdy_util_
.ConstructSpdyPost(
901 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
904 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
907 scoped_ptr
<SpdyFrame
> msg(
908 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
911 scoped_ptr
<SpdyFrame
> echo(
912 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
917 DeterministicSocketData
data(GetReads(), GetNumReads(),
918 GetWrites(), GetNumWrites());
919 MockConnect
connect_data(SYNCHRONOUS
, OK
);
920 data
.set_connect_data(connect_data
);
922 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
924 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
926 base::WeakPtr
<SpdyStream
> stream
=
927 CreateStreamSynchronously(
928 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
929 ASSERT_TRUE(stream
.get() != NULL
);
931 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
932 stream
->SetDelegate(&delegate
);
934 EXPECT_FALSE(stream
->HasUrlFromHeaders());
936 scoped_ptr
<SpdyHeaderBlock
> headers(
937 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
938 EXPECT_EQ(ERR_IO_PENDING
,
939 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
940 EXPECT_TRUE(stream
->HasUrlFromHeaders());
941 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
945 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
951 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
953 unstall_function
.Run(stream
, kPostBodyLength
);
955 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
959 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
961 EXPECT_TRUE(delegate
.send_headers_completed());
962 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
963 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
964 delegate
.TakeReceivedData());
965 EXPECT_TRUE(data
.at_write_eof());
968 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseBidirectional
) {
969 RunResumeAfterUnstallBidirectionalTest(
970 base::Bind(&IncreaseStreamSendWindowSize
));
973 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustBidirectional
) {
974 RunResumeAfterUnstallBidirectionalTest(
975 base::Bind(&AdjustStreamSendWindowSize
));
978 // Test calculation of amount of bytes received from network.
979 TEST_P(SpdyStreamTest
, ReceivedBytes
) {
980 GURL
url(kStreamUrl
);
983 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
985 scoped_ptr
<SpdyFrame
> syn(
986 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
989 scoped_ptr
<SpdyFrame
>
990 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
993 scoped_ptr
<SpdyFrame
> msg(
994 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
999 DeterministicSocketData
data(GetReads(), GetNumReads(),
1000 GetWrites(), GetNumWrites());
1001 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1002 data
.set_connect_data(connect_data
);
1004 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1006 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
1008 base::WeakPtr
<SpdyStream
> stream
=
1009 CreateStreamSynchronously(
1010 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
1011 ASSERT_TRUE(stream
.get() != NULL
);
1013 StreamDelegateDoNothing
delegate(stream
);
1014 stream
->SetDelegate(&delegate
);
1016 EXPECT_FALSE(stream
->HasUrlFromHeaders());
1018 scoped_ptr
<SpdyHeaderBlock
> headers(
1019 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
1020 EXPECT_EQ(ERR_IO_PENDING
,
1021 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
1022 EXPECT_TRUE(stream
->HasUrlFromHeaders());
1023 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
1025 int64 reply_frame_len
= reply
->size();
1026 int64 data_header_len
= spdy_util_
.CreateFramer(false)
1027 ->GetDataFrameMinimumSize();
1028 int64 data_frame_len
= data_header_len
+ kPostBodyLength
;
1029 int64 response_len
= reply_frame_len
+ data_frame_len
;
1031 EXPECT_EQ(0, stream
->raw_received_bytes());
1032 data
.RunFor(1); // SYN
1033 EXPECT_EQ(0, stream
->raw_received_bytes());
1034 data
.RunFor(1); // REPLY
1035 EXPECT_EQ(reply_frame_len
, stream
->raw_received_bytes());
1036 data
.RunFor(1); // DATA
1037 EXPECT_EQ(response_len
, stream
->raw_received_bytes());
1038 data
.RunFor(1); // FIN
1040 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());