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/test_net_log.h"
16 #include "net/log/test_net_log_entry.h"
17 #include "net/log/test_net_log_util.h"
18 #include "net/socket/next_proto.h"
19 #include "net/socket/socket_test_util.h"
20 #include "net/spdy/buffered_spdy_framer.h"
21 #include "net/spdy/spdy_http_utils.h"
22 #include "net/spdy/spdy_protocol.h"
23 #include "net/spdy/spdy_session.h"
24 #include "net/spdy/spdy_stream.h"
25 #include "net/spdy/spdy_stream_test_util.h"
26 #include "net/spdy/spdy_test_util_common.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
37 const char kStreamUrl
[] = "http://www.example.org/";
38 const char kPostBody
[] = "\0hello!\xff";
39 const size_t kPostBodyLength
= arraysize(kPostBody
);
40 const base::StringPiece
kPostBodyStringPiece(kPostBody
, kPostBodyLength
);
42 class SpdyStreamTest
: public ::testing::Test
,
43 public ::testing::WithParamInterface
<NextProto
> {
45 // A function that takes a SpdyStream and the number of bytes which
46 // will unstall the next frame completely.
47 typedef base::Callback
<void(const base::WeakPtr
<SpdyStream
>&, int32
)>
51 : spdy_util_(GetParam()),
52 session_deps_(GetParam()),
55 base::WeakPtr
<SpdySession
> CreateDefaultSpdySession() {
56 SpdySessionKey
key(HostPortPair("www.example.org", 80),
57 ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
58 return CreateInsecureSpdySession(session_
, key
, BoundNetLog());
61 void TearDown() override
{ base::MessageLoop::current()->RunUntilIdle(); }
63 void RunResumeAfterUnstallRequestResponseTest(
64 const UnstallFunction
& unstall_function
);
66 void RunResumeAfterUnstallBidirectionalTest(
67 const UnstallFunction
& unstall_function
);
69 // Add{Read,Write}() populates lists that are eventually passed to a
70 // SocketData class. |frame| must live for the whole test.
72 void AddRead(const SpdyFrame
& frame
) {
73 reads_
.push_back(CreateMockRead(frame
, offset_
++));
76 void AddWrite(const SpdyFrame
& frame
) {
77 writes_
.push_back(CreateMockWrite(frame
, offset_
++));
81 reads_
.push_back(MockRead(ASYNC
, 0, offset_
++));
84 MockRead
* GetReads() {
85 return vector_as_array(&reads_
);
88 size_t GetNumReads() const {
92 MockWrite
* GetWrites() {
93 return vector_as_array(&writes_
);
96 int GetNumWrites() const {
97 return writes_
.size();
100 SpdyTestUtil spdy_util_
;
101 SpdySessionDependencies session_deps_
;
102 scoped_refptr
<HttpNetworkSession
> session_
;
105 // Used by Add{Read,Write}() above.
106 std::vector
<MockWrite
> writes_
;
107 std::vector
<MockRead
> reads_
;
111 INSTANTIATE_TEST_CASE_P(NextProto
,
113 testing::Values(kProtoSPDY31
,
117 TEST_P(SpdyStreamTest
, SendDataAfterOpen
) {
118 GURL
url(kStreamUrl
);
121 SpdySessionDependencies::SpdyCreateSessionDeterministic(&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 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
144 MockConnect
connect_data(SYNCHRONOUS
, OK
);
145 data
.set_connect_data(connect_data
);
147 session_deps_
.deterministic_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 data
.RunFor(GetNumReads() + GetNumWrites());
169 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
171 EXPECT_TRUE(delegate
.send_headers_completed());
172 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
173 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
174 delegate
.TakeReceivedData());
175 EXPECT_TRUE(data
.AllWriteDataConsumed());
178 TEST_P(SpdyStreamTest
, PushedStream
) {
180 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
184 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
186 MockConnect
connect_data(SYNCHRONOUS
, OK
);
187 data
.set_connect_data(connect_data
);
189 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
191 base::WeakPtr
<SpdySession
> spdy_session(CreateDefaultSpdySession());
193 // Conjure up a stream.
194 SpdyStream
stream(SPDY_PUSH_STREAM
, spdy_session
, GURL(), DEFAULT_PRIORITY
,
195 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31
),
196 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31
),
198 stream
.set_stream_id(2);
199 EXPECT_FALSE(stream
.HasUrlFromHeaders());
201 // Set required request headers.
202 SpdyHeaderBlock request_headers
;
203 spdy_util_
.AddUrlToHeaderBlock(kStreamUrl
, &request_headers
);
204 stream
.OnPushPromiseHeadersReceived(request_headers
);
206 // Send some basic response headers.
207 SpdyHeaderBlock response
;
208 response
[spdy_util_
.GetStatusKey()] = "200";
209 response
[spdy_util_
.GetVersionKey()] = "OK";
210 stream
.OnInitialResponseHeadersReceived(
211 response
, base::Time::Now(), base::TimeTicks::Now());
213 // And some more headers.
214 // TODO(baranovich): not valid for HTTP 2.
215 SpdyHeaderBlock headers
;
216 headers
["alpha"] = "beta";
217 stream
.OnAdditionalResponseHeadersReceived(headers
);
219 EXPECT_TRUE(stream
.HasUrlFromHeaders());
220 EXPECT_EQ(kStreamUrl
, stream
.GetUrlFromHeaders().spec());
222 StreamDelegateDoNothing
delegate(stream
.GetWeakPtr());
223 stream
.SetDelegate(&delegate
);
225 data
.RunFor(GetNumReads() + GetNumWrites());
227 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
228 EXPECT_EQ("beta", delegate
.GetResponseHeaderValue("alpha"));
230 EXPECT_TRUE(spdy_session
== NULL
);
233 TEST_P(SpdyStreamTest
, StreamError
) {
234 GURL
url(kStreamUrl
);
237 SpdySessionDependencies::SpdyCreateSessionDeterministic(&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));
260 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
262 MockConnect
connect_data(SYNCHRONOUS
, OK
);
263 data
.set_connect_data(connect_data
);
265 session_deps_
.deterministic_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 data
.RunFor(GetNumReads() + GetNumWrites());
287 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
289 const SpdyStreamId stream_id
= delegate
.stream_id();
291 EXPECT_TRUE(delegate
.send_headers_completed());
292 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
293 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
294 delegate
.TakeReceivedData());
295 EXPECT_TRUE(data
.AllWriteDataConsumed());
297 // Check that the NetLog was filled reasonably.
298 TestNetLogEntry::List entries
;
299 log
.GetEntries(&entries
);
300 EXPECT_LT(0u, entries
.size());
302 // Check that we logged SPDY_STREAM_ERROR correctly.
303 int pos
= ExpectLogContainsSomewhere(
304 entries
, 0, NetLog::TYPE_HTTP2_STREAM_ERROR
, NetLog::PHASE_NONE
);
307 ASSERT_TRUE(entries
[pos
].GetIntegerValue("stream_id", &stream_id2
));
308 EXPECT_EQ(static_cast<int>(stream_id
), stream_id2
);
311 // Make sure that large blocks of data are properly split up into
312 // frame-sized chunks for a request/response (i.e., an HTTP-like)
314 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenRequestResponse
) {
315 GURL
url(kStreamUrl
);
318 SpdySessionDependencies::SpdyCreateSessionDeterministic(&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 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
344 MockConnect
connect_data(SYNCHRONOUS
, OK
);
345 data
.set_connect_data(connect_data
);
347 session_deps_
.deterministic_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 data
.RunFor(GetNumReads() + GetNumWrites());
370 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
372 EXPECT_TRUE(delegate
.send_headers_completed());
373 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
374 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
375 EXPECT_TRUE(data
.AllWriteDataConsumed());
378 // Make sure that large blocks of data are properly split up into
379 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
381 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenBidirectional
) {
382 GURL
url(kStreamUrl
);
385 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
387 scoped_ptr
<SpdyFrame
> req(
388 spdy_util_
.ConstructSpdyPost(
389 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
392 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
395 std::string
chunk_data(kMaxSpdyFrameChunkSize
, 'x');
396 scoped_ptr
<SpdyFrame
> chunk(
397 spdy_util_
.ConstructSpdyBodyFrame(
398 1, chunk_data
.data(), chunk_data
.length(), false));
405 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
407 MockConnect
connect_data(SYNCHRONOUS
, OK
);
408 data
.set_connect_data(connect_data
);
410 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
412 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
414 base::WeakPtr
<SpdyStream
> stream
=
415 CreateStreamSynchronously(
416 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
417 ASSERT_TRUE(stream
.get() != NULL
);
419 std::string
body_data(3 * kMaxSpdyFrameChunkSize
, 'x');
420 StreamDelegateSendImmediate
delegate(stream
, body_data
);
421 stream
->SetDelegate(&delegate
);
423 EXPECT_FALSE(stream
->HasUrlFromHeaders());
425 scoped_ptr
<SpdyHeaderBlock
> headers(
426 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
427 EXPECT_EQ(ERR_IO_PENDING
,
428 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
429 EXPECT_TRUE(stream
->HasUrlFromHeaders());
430 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
432 data
.RunFor(GetNumReads() + GetNumWrites());
433 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
435 EXPECT_TRUE(delegate
.send_headers_completed());
436 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
437 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
438 EXPECT_TRUE(data
.AllWriteDataConsumed());
441 // Receiving a header with uppercase ASCII should result in a protocol
443 TEST_P(SpdyStreamTest
, UpperCaseHeaders
) {
444 GURL
url(kStreamUrl
);
447 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
449 scoped_ptr
<SpdyFrame
> syn(
450 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
453 const char* const kExtraHeaders
[] = {"X-UpperCase", "yes"};
454 scoped_ptr
<SpdyFrame
>
455 reply(spdy_util_
.ConstructSpdyGetSynReply(kExtraHeaders
, 1, 1));
458 scoped_ptr
<SpdyFrame
> rst(
459 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
464 DeterministicSocketData
data(GetReads(), GetNumReads(),
465 GetWrites(), GetNumWrites());
466 MockConnect
connect_data(SYNCHRONOUS
, OK
);
467 data
.set_connect_data(connect_data
);
469 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
471 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
473 base::WeakPtr
<SpdyStream
> stream
=
474 CreateStreamSynchronously(
475 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
476 ASSERT_TRUE(stream
.get() != NULL
);
478 StreamDelegateDoNothing
delegate(stream
);
479 stream
->SetDelegate(&delegate
);
481 EXPECT_FALSE(stream
->HasUrlFromHeaders());
483 scoped_ptr
<SpdyHeaderBlock
> headers(
484 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
485 EXPECT_EQ(ERR_IO_PENDING
,
486 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
487 EXPECT_TRUE(stream
->HasUrlFromHeaders());
488 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
492 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
495 // Receiving a header with uppercase ASCII should result in a protocol
496 // error even for a push stream.
497 TEST_P(SpdyStreamTest
, UpperCaseHeadersOnPush
) {
498 GURL
url(kStreamUrl
);
501 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
503 scoped_ptr
<SpdyFrame
> syn(
504 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
507 scoped_ptr
<SpdyFrame
>
508 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
511 const char* const extra_headers
[] = {"X-UpperCase", "yes"};
512 scoped_ptr
<SpdyFrame
>
513 push(spdy_util_
.ConstructSpdyPush(extra_headers
, 1, 2, 1, kStreamUrl
));
516 scoped_ptr
<SpdyFrame
> rst(
517 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
522 DeterministicSocketData
data(GetReads(), GetNumReads(),
523 GetWrites(), GetNumWrites());
524 MockConnect
connect_data(SYNCHRONOUS
, OK
);
525 data
.set_connect_data(connect_data
);
527 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
529 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
531 base::WeakPtr
<SpdyStream
> stream
=
532 CreateStreamSynchronously(
533 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
534 ASSERT_TRUE(stream
.get() != NULL
);
536 StreamDelegateDoNothing
delegate(stream
);
537 stream
->SetDelegate(&delegate
);
539 EXPECT_FALSE(stream
->HasUrlFromHeaders());
541 scoped_ptr
<SpdyHeaderBlock
> headers(
542 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
543 EXPECT_EQ(ERR_IO_PENDING
,
544 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
545 EXPECT_TRUE(stream
->HasUrlFromHeaders());
546 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
550 base::WeakPtr
<SpdyStream
> push_stream
;
551 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
552 EXPECT_FALSE(push_stream
);
556 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
559 // Receiving a header with uppercase ASCII in a HEADERS frame should
560 // result in a protocol error.
561 TEST_P(SpdyStreamTest
, UpperCaseHeadersInHeadersFrame
) {
562 GURL
url(kStreamUrl
);
565 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
567 scoped_ptr
<SpdyFrame
> syn(
568 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
571 scoped_ptr
<SpdyFrame
>
572 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
575 scoped_ptr
<SpdyFrame
>
576 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
579 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
580 (*late_headers
)["X-UpperCase"] = "yes";
581 scoped_ptr
<SpdyFrame
> headers_frame(
582 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
589 AddRead(*headers_frame
);
591 scoped_ptr
<SpdyFrame
> rst(
592 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
597 DeterministicSocketData
data(GetReads(), GetNumReads(),
598 GetWrites(), GetNumWrites());
599 MockConnect
connect_data(SYNCHRONOUS
, OK
);
600 data
.set_connect_data(connect_data
);
602 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
604 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
606 base::WeakPtr
<SpdyStream
> stream
=
607 CreateStreamSynchronously(
608 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
609 ASSERT_TRUE(stream
.get() != NULL
);
611 StreamDelegateDoNothing
delegate(stream
);
612 stream
->SetDelegate(&delegate
);
614 EXPECT_FALSE(stream
->HasUrlFromHeaders());
616 scoped_ptr
<SpdyHeaderBlock
> headers(
617 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
618 EXPECT_EQ(ERR_IO_PENDING
,
619 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
620 EXPECT_TRUE(stream
->HasUrlFromHeaders());
621 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
625 base::WeakPtr
<SpdyStream
> push_stream
;
626 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
627 EXPECT_TRUE(push_stream
);
631 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
632 EXPECT_FALSE(push_stream
);
636 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
639 // Receiving a duplicate header in a HEADERS frame should result in a
641 TEST_P(SpdyStreamTest
, DuplicateHeaders
) {
642 GURL
url(kStreamUrl
);
645 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
647 scoped_ptr
<SpdyFrame
> syn(
648 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
651 scoped_ptr
<SpdyFrame
>
652 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
655 scoped_ptr
<SpdyFrame
>
656 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
659 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
660 (*late_headers
)[spdy_util_
.GetStatusKey()] = "500 Server Error";
661 scoped_ptr
<SpdyFrame
> headers_frame(
662 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
669 AddRead(*headers_frame
);
671 scoped_ptr
<SpdyFrame
> rst(
672 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
677 DeterministicSocketData
data(GetReads(), GetNumReads(),
678 GetWrites(), GetNumWrites());
679 MockConnect
connect_data(SYNCHRONOUS
, OK
);
680 data
.set_connect_data(connect_data
);
682 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
684 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
686 base::WeakPtr
<SpdyStream
> stream
=
687 CreateStreamSynchronously(
688 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
689 ASSERT_TRUE(stream
.get() != NULL
);
691 StreamDelegateDoNothing
delegate(stream
);
692 stream
->SetDelegate(&delegate
);
694 EXPECT_FALSE(stream
->HasUrlFromHeaders());
696 scoped_ptr
<SpdyHeaderBlock
> headers(
697 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
698 EXPECT_EQ(ERR_IO_PENDING
,
699 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
700 EXPECT_TRUE(stream
->HasUrlFromHeaders());
701 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
705 base::WeakPtr
<SpdyStream
> push_stream
;
706 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
707 EXPECT_TRUE(push_stream
);
711 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
712 EXPECT_FALSE(push_stream
);
716 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
719 // The tests below are only for SPDY/3 and above.
721 // Call IncreaseSendWindowSize on a stream with a large enough delta
722 // to overflow an int32. The SpdyStream should handle that case
724 TEST_P(SpdyStreamTest
, IncreaseSendWindowSizeOverflow
) {
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
));
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
.AllWriteDataConsumed());
881 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseRequestResponse
) {
882 RunResumeAfterUnstallRequestResponseTest(
883 base::Bind(&IncreaseStreamSendWindowSize
));
886 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustRequestResponse
) {
887 RunResumeAfterUnstallRequestResponseTest(
888 base::Bind(&AdjustStreamSendWindowSize
));
891 // Given an unstall function, runs a test to make sure that a
892 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
894 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
895 const UnstallFunction
& unstall_function
) {
896 GURL
url(kStreamUrl
);
899 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
901 scoped_ptr
<SpdyFrame
> req(
902 spdy_util_
.ConstructSpdyPost(
903 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
906 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
909 scoped_ptr
<SpdyFrame
> msg(
910 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
913 scoped_ptr
<SpdyFrame
> echo(
914 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
919 DeterministicSocketData
data(GetReads(), GetNumReads(),
920 GetWrites(), GetNumWrites());
921 MockConnect
connect_data(SYNCHRONOUS
, OK
);
922 data
.set_connect_data(connect_data
);
924 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
926 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
928 base::WeakPtr
<SpdyStream
> stream
=
929 CreateStreamSynchronously(
930 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
931 ASSERT_TRUE(stream
.get() != NULL
);
933 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
934 stream
->SetDelegate(&delegate
);
936 EXPECT_FALSE(stream
->HasUrlFromHeaders());
938 scoped_ptr
<SpdyHeaderBlock
> headers(
939 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
940 EXPECT_EQ(ERR_IO_PENDING
,
941 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
942 EXPECT_TRUE(stream
->HasUrlFromHeaders());
943 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
947 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
953 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
955 unstall_function
.Run(stream
, kPostBodyLength
);
957 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
961 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
963 EXPECT_TRUE(delegate
.send_headers_completed());
964 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
965 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
966 delegate
.TakeReceivedData());
967 EXPECT_TRUE(data
.AllWriteDataConsumed());
970 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseBidirectional
) {
971 RunResumeAfterUnstallBidirectionalTest(
972 base::Bind(&IncreaseStreamSendWindowSize
));
975 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustBidirectional
) {
976 RunResumeAfterUnstallBidirectionalTest(
977 base::Bind(&AdjustStreamSendWindowSize
));
980 // Test calculation of amount of bytes received from network.
981 TEST_P(SpdyStreamTest
, ReceivedBytes
) {
982 GURL
url(kStreamUrl
);
985 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
987 scoped_ptr
<SpdyFrame
> syn(
988 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
991 scoped_ptr
<SpdyFrame
>
992 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
995 scoped_ptr
<SpdyFrame
> msg(
996 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
1001 DeterministicSocketData
data(GetReads(), GetNumReads(),
1002 GetWrites(), GetNumWrites());
1003 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1004 data
.set_connect_data(connect_data
);
1006 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1008 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
1010 base::WeakPtr
<SpdyStream
> stream
=
1011 CreateStreamSynchronously(
1012 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
1013 ASSERT_TRUE(stream
.get() != NULL
);
1015 StreamDelegateDoNothing
delegate(stream
);
1016 stream
->SetDelegate(&delegate
);
1018 EXPECT_FALSE(stream
->HasUrlFromHeaders());
1020 scoped_ptr
<SpdyHeaderBlock
> headers(
1021 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
1022 EXPECT_EQ(ERR_IO_PENDING
,
1023 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
1024 EXPECT_TRUE(stream
->HasUrlFromHeaders());
1025 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
1027 int64 reply_frame_len
= reply
->size();
1028 int64 data_header_len
= spdy_util_
.CreateFramer(false)
1029 ->GetDataFrameMinimumSize();
1030 int64 data_frame_len
= data_header_len
+ kPostBodyLength
;
1031 int64 response_len
= reply_frame_len
+ data_frame_len
;
1033 EXPECT_EQ(0, stream
->raw_received_bytes());
1034 data
.RunFor(1); // SYN
1035 EXPECT_EQ(0, stream
->raw_received_bytes());
1036 data
.RunFor(1); // REPLY
1037 EXPECT_EQ(reply_frame_len
, stream
->raw_received_bytes());
1038 data
.RunFor(1); // DATA
1039 EXPECT_EQ(response_len
, stream
->raw_received_bytes());
1040 data
.RunFor(1); // FIN
1042 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());