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
,
116 TEST_P(SpdyStreamTest
, SendDataAfterOpen
) {
117 GURL
url(kStreamUrl
);
120 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
122 scoped_ptr
<SpdyFrame
> req(
123 spdy_util_
.ConstructSpdyPost(
124 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
127 scoped_ptr
<SpdyFrame
> resp(
128 spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
131 scoped_ptr
<SpdyFrame
> msg(
132 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
135 scoped_ptr
<SpdyFrame
> echo(
136 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
141 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
143 MockConnect
connect_data(SYNCHRONOUS
, OK
);
144 data
.set_connect_data(connect_data
);
146 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
148 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
150 base::WeakPtr
<SpdyStream
> stream
=
151 CreateStreamSynchronously(
152 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
153 ASSERT_TRUE(stream
.get() != NULL
);
155 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
156 stream
->SetDelegate(&delegate
);
158 EXPECT_FALSE(stream
->HasUrlFromHeaders());
160 scoped_ptr
<SpdyHeaderBlock
> headers(
161 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
162 EXPECT_EQ(ERR_IO_PENDING
,
163 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
164 EXPECT_TRUE(stream
->HasUrlFromHeaders());
165 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
167 data
.RunFor(GetNumReads() + GetNumWrites());
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
.AllWriteDataConsumed());
177 // Delegate that receives trailers.
178 class StreamDelegateWithTrailers
: public test::StreamDelegateWithBody
{
180 StreamDelegateWithTrailers(const base::WeakPtr
<SpdyStream
>& stream
,
181 base::StringPiece data
)
182 : StreamDelegateWithBody(stream
, data
) {}
184 ~StreamDelegateWithTrailers() override
{}
186 void OnTrailers(const SpdyHeaderBlock
& trailers
) override
{
187 trailers_
= trailers
;
190 const SpdyHeaderBlock
& trailers() const { return trailers_
; }
193 SpdyHeaderBlock trailers_
;
196 // Regression test for crbug.com/481033.
197 TEST_P(SpdyStreamTest
, Trailers
) {
198 GURL
url(kStreamUrl
);
201 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
203 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
204 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
207 scoped_ptr
<SpdyFrame
> msg(
208 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, true));
211 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
214 scoped_ptr
<SpdyFrame
> echo(
215 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
218 const char* const kExtraHeaders
[] = {"foo", "bar"};
219 scoped_ptr
<SpdyFrame
> trailers(
220 spdy_util_
.ConstructSpdyHeaderFrame(1, kExtraHeaders
, 1));
225 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
227 MockConnect
connect_data(SYNCHRONOUS
, OK
);
228 data
.set_connect_data(connect_data
);
230 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
232 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
234 base::WeakPtr
<SpdyStream
> stream
= CreateStreamSynchronously(
235 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
236 ASSERT_TRUE(stream
.get() != NULL
);
238 StreamDelegateWithTrailers
delegate(stream
, kPostBodyStringPiece
);
239 stream
->SetDelegate(&delegate
);
241 EXPECT_FALSE(stream
->HasUrlFromHeaders());
243 scoped_ptr
<SpdyHeaderBlock
> headers(
244 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
245 EXPECT_EQ(ERR_IO_PENDING
,
246 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
247 EXPECT_TRUE(stream
->HasUrlFromHeaders());
248 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
250 data
.RunFor(GetNumReads() + GetNumWrites());
251 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
253 EXPECT_TRUE(delegate
.send_headers_completed());
254 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
255 const SpdyHeaderBlock
& received_trailers
= delegate
.trailers();
256 SpdyHeaderBlock::const_iterator it
= received_trailers
.find("foo");
257 EXPECT_EQ("bar", it
->second
);
258 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
259 delegate
.TakeReceivedData());
260 EXPECT_TRUE(data
.AllWriteDataConsumed());
263 TEST_P(SpdyStreamTest
, PushedStream
) {
265 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
269 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
271 MockConnect
connect_data(SYNCHRONOUS
, OK
);
272 data
.set_connect_data(connect_data
);
274 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
276 base::WeakPtr
<SpdySession
> spdy_session(CreateDefaultSpdySession());
278 // Conjure up a stream.
279 SpdyStream
stream(SPDY_PUSH_STREAM
, spdy_session
, GURL(), DEFAULT_PRIORITY
,
280 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31
),
281 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31
),
283 stream
.set_stream_id(2);
284 EXPECT_FALSE(stream
.HasUrlFromHeaders());
286 // Set required request headers.
287 SpdyHeaderBlock request_headers
;
288 spdy_util_
.AddUrlToHeaderBlock(kStreamUrl
, &request_headers
);
289 stream
.OnPushPromiseHeadersReceived(request_headers
);
291 // Send some basic response headers.
292 SpdyHeaderBlock response
;
293 response
[spdy_util_
.GetStatusKey()] = "200";
294 response
[spdy_util_
.GetVersionKey()] = "OK";
295 stream
.OnInitialResponseHeadersReceived(
296 response
, base::Time::Now(), base::TimeTicks::Now());
298 // And some more headers.
299 // TODO(baranovich): not valid for HTTP 2.
300 SpdyHeaderBlock headers
;
301 headers
["alpha"] = "beta";
302 stream
.OnAdditionalResponseHeadersReceived(headers
);
304 EXPECT_TRUE(stream
.HasUrlFromHeaders());
305 EXPECT_EQ(kStreamUrl
, stream
.GetUrlFromHeaders().spec());
307 StreamDelegateDoNothing
delegate(stream
.GetWeakPtr());
308 stream
.SetDelegate(&delegate
);
310 data
.RunFor(GetNumReads() + GetNumWrites());
312 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
313 EXPECT_EQ("beta", delegate
.GetResponseHeaderValue("alpha"));
315 EXPECT_TRUE(spdy_session
== NULL
);
318 TEST_P(SpdyStreamTest
, StreamError
) {
319 GURL
url(kStreamUrl
);
322 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
324 scoped_ptr
<SpdyFrame
> req(
325 spdy_util_
.ConstructSpdyPost(
326 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
329 scoped_ptr
<SpdyFrame
> resp(
330 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
333 scoped_ptr
<SpdyFrame
> msg(
334 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
337 scoped_ptr
<SpdyFrame
> echo(
338 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
345 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
347 MockConnect
connect_data(SYNCHRONOUS
, OK
);
348 data
.set_connect_data(connect_data
);
350 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
352 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
354 base::WeakPtr
<SpdyStream
> stream
=
355 CreateStreamSynchronously(
356 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, log
.bound());
357 ASSERT_TRUE(stream
.get() != NULL
);
359 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
360 stream
->SetDelegate(&delegate
);
362 EXPECT_FALSE(stream
->HasUrlFromHeaders());
364 scoped_ptr
<SpdyHeaderBlock
> headers(
365 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
366 EXPECT_EQ(ERR_IO_PENDING
,
367 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
368 EXPECT_TRUE(stream
->HasUrlFromHeaders());
369 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
371 data
.RunFor(GetNumReads() + GetNumWrites());
372 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
374 const SpdyStreamId stream_id
= delegate
.stream_id();
376 EXPECT_TRUE(delegate
.send_headers_completed());
377 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
378 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
379 delegate
.TakeReceivedData());
380 EXPECT_TRUE(data
.AllWriteDataConsumed());
382 // Check that the NetLog was filled reasonably.
383 TestNetLogEntry::List entries
;
384 log
.GetEntries(&entries
);
385 EXPECT_LT(0u, entries
.size());
387 // Check that we logged SPDY_STREAM_ERROR correctly.
388 int pos
= ExpectLogContainsSomewhere(
389 entries
, 0, NetLog::TYPE_HTTP2_STREAM_ERROR
, NetLog::PHASE_NONE
);
392 ASSERT_TRUE(entries
[pos
].GetIntegerValue("stream_id", &stream_id2
));
393 EXPECT_EQ(static_cast<int>(stream_id
), stream_id2
);
396 // Make sure that large blocks of data are properly split up into
397 // frame-sized chunks for a request/response (i.e., an HTTP-like)
399 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenRequestResponse
) {
400 GURL
url(kStreamUrl
);
403 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
405 scoped_ptr
<SpdyFrame
> req(
406 spdy_util_
.ConstructSpdyPost(
407 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
410 std::string
chunk_data(kMaxSpdyFrameChunkSize
, 'x');
411 scoped_ptr
<SpdyFrame
> chunk(
412 spdy_util_
.ConstructSpdyBodyFrame(
413 1, chunk_data
.data(), chunk_data
.length(), false));
417 scoped_ptr
<SpdyFrame
> last_chunk(
418 spdy_util_
.ConstructSpdyBodyFrame(
419 1, chunk_data
.data(), chunk_data
.length(), true));
420 AddWrite(*last_chunk
);
422 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
427 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
429 MockConnect
connect_data(SYNCHRONOUS
, OK
);
430 data
.set_connect_data(connect_data
);
432 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
434 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
436 base::WeakPtr
<SpdyStream
> stream
=
437 CreateStreamSynchronously(
438 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
439 ASSERT_TRUE(stream
.get() != NULL
);
441 std::string
body_data(3 * kMaxSpdyFrameChunkSize
, 'x');
442 StreamDelegateWithBody
delegate(stream
, body_data
);
443 stream
->SetDelegate(&delegate
);
445 EXPECT_FALSE(stream
->HasUrlFromHeaders());
447 scoped_ptr
<SpdyHeaderBlock
> headers(
448 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
449 EXPECT_EQ(ERR_IO_PENDING
,
450 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
451 EXPECT_TRUE(stream
->HasUrlFromHeaders());
452 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
454 data
.RunFor(GetNumReads() + GetNumWrites());
455 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
457 EXPECT_TRUE(delegate
.send_headers_completed());
458 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
459 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
460 EXPECT_TRUE(data
.AllWriteDataConsumed());
463 // Make sure that large blocks of data are properly split up into
464 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
466 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenBidirectional
) {
467 GURL
url(kStreamUrl
);
470 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
472 scoped_ptr
<SpdyFrame
> req(
473 spdy_util_
.ConstructSpdyPost(
474 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
477 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
480 std::string
chunk_data(kMaxSpdyFrameChunkSize
, 'x');
481 scoped_ptr
<SpdyFrame
> chunk(
482 spdy_util_
.ConstructSpdyBodyFrame(
483 1, chunk_data
.data(), chunk_data
.length(), false));
490 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
492 MockConnect
connect_data(SYNCHRONOUS
, OK
);
493 data
.set_connect_data(connect_data
);
495 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
497 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
499 base::WeakPtr
<SpdyStream
> stream
=
500 CreateStreamSynchronously(
501 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
502 ASSERT_TRUE(stream
.get() != NULL
);
504 std::string
body_data(3 * kMaxSpdyFrameChunkSize
, 'x');
505 StreamDelegateSendImmediate
delegate(stream
, body_data
);
506 stream
->SetDelegate(&delegate
);
508 EXPECT_FALSE(stream
->HasUrlFromHeaders());
510 scoped_ptr
<SpdyHeaderBlock
> headers(
511 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
512 EXPECT_EQ(ERR_IO_PENDING
,
513 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
514 EXPECT_TRUE(stream
->HasUrlFromHeaders());
515 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
517 data
.RunFor(GetNumReads() + GetNumWrites());
518 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
520 EXPECT_TRUE(delegate
.send_headers_completed());
521 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
522 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
523 EXPECT_TRUE(data
.AllWriteDataConsumed());
526 // Receiving a header with uppercase ASCII should result in a protocol
528 TEST_P(SpdyStreamTest
, UpperCaseHeaders
) {
529 GURL
url(kStreamUrl
);
532 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
534 scoped_ptr
<SpdyFrame
> syn(
535 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
538 const char* const kExtraHeaders
[] = {"X-UpperCase", "yes"};
539 scoped_ptr
<SpdyFrame
>
540 reply(spdy_util_
.ConstructSpdyGetSynReply(kExtraHeaders
, 1, 1));
543 scoped_ptr
<SpdyFrame
> rst(
544 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
549 DeterministicSocketData
data(GetReads(), GetNumReads(),
550 GetWrites(), GetNumWrites());
551 MockConnect
connect_data(SYNCHRONOUS
, OK
);
552 data
.set_connect_data(connect_data
);
554 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
556 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
558 base::WeakPtr
<SpdyStream
> stream
=
559 CreateStreamSynchronously(
560 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
561 ASSERT_TRUE(stream
.get() != NULL
);
563 StreamDelegateDoNothing
delegate(stream
);
564 stream
->SetDelegate(&delegate
);
566 EXPECT_FALSE(stream
->HasUrlFromHeaders());
568 scoped_ptr
<SpdyHeaderBlock
> headers(
569 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
570 EXPECT_EQ(ERR_IO_PENDING
,
571 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
572 EXPECT_TRUE(stream
->HasUrlFromHeaders());
573 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
577 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
580 // Receiving a header with uppercase ASCII should result in a protocol
581 // error even for a push stream.
582 TEST_P(SpdyStreamTest
, UpperCaseHeadersOnPush
) {
583 GURL
url(kStreamUrl
);
586 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
588 scoped_ptr
<SpdyFrame
> syn(
589 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
592 scoped_ptr
<SpdyFrame
>
593 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
596 const char* const extra_headers
[] = {"X-UpperCase", "yes"};
597 scoped_ptr
<SpdyFrame
>
598 push(spdy_util_
.ConstructSpdyPush(extra_headers
, 1, 2, 1, kStreamUrl
));
601 scoped_ptr
<SpdyFrame
> rst(
602 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
607 DeterministicSocketData
data(GetReads(), GetNumReads(),
608 GetWrites(), GetNumWrites());
609 MockConnect
connect_data(SYNCHRONOUS
, OK
);
610 data
.set_connect_data(connect_data
);
612 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
614 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
616 base::WeakPtr
<SpdyStream
> stream
=
617 CreateStreamSynchronously(
618 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
619 ASSERT_TRUE(stream
.get() != NULL
);
621 StreamDelegateDoNothing
delegate(stream
);
622 stream
->SetDelegate(&delegate
);
624 EXPECT_FALSE(stream
->HasUrlFromHeaders());
626 scoped_ptr
<SpdyHeaderBlock
> headers(
627 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
628 EXPECT_EQ(ERR_IO_PENDING
,
629 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
630 EXPECT_TRUE(stream
->HasUrlFromHeaders());
631 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
635 base::WeakPtr
<SpdyStream
> push_stream
;
636 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
637 EXPECT_FALSE(push_stream
);
641 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
644 // Receiving a header with uppercase ASCII in a HEADERS frame should
645 // result in a protocol error.
646 TEST_P(SpdyStreamTest
, UpperCaseHeadersInHeadersFrame
) {
647 GURL
url(kStreamUrl
);
650 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
652 scoped_ptr
<SpdyFrame
> syn(
653 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
656 scoped_ptr
<SpdyFrame
>
657 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
660 scoped_ptr
<SpdyFrame
>
661 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
664 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
665 (*late_headers
)["X-UpperCase"] = "yes";
666 scoped_ptr
<SpdyFrame
> headers_frame(
667 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
674 AddRead(*headers_frame
);
676 scoped_ptr
<SpdyFrame
> rst(
677 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
682 DeterministicSocketData
data(GetReads(), GetNumReads(),
683 GetWrites(), GetNumWrites());
684 MockConnect
connect_data(SYNCHRONOUS
, OK
);
685 data
.set_connect_data(connect_data
);
687 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
689 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
691 base::WeakPtr
<SpdyStream
> stream
=
692 CreateStreamSynchronously(
693 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
694 ASSERT_TRUE(stream
.get() != NULL
);
696 StreamDelegateDoNothing
delegate(stream
);
697 stream
->SetDelegate(&delegate
);
699 EXPECT_FALSE(stream
->HasUrlFromHeaders());
701 scoped_ptr
<SpdyHeaderBlock
> headers(
702 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
703 EXPECT_EQ(ERR_IO_PENDING
,
704 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
705 EXPECT_TRUE(stream
->HasUrlFromHeaders());
706 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
710 base::WeakPtr
<SpdyStream
> push_stream
;
711 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
712 EXPECT_TRUE(push_stream
);
716 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
717 EXPECT_FALSE(push_stream
);
721 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
724 // Receiving a duplicate header in a HEADERS frame should result in a
726 TEST_P(SpdyStreamTest
, DuplicateHeaders
) {
727 GURL
url(kStreamUrl
);
730 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
732 scoped_ptr
<SpdyFrame
> syn(
733 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
736 scoped_ptr
<SpdyFrame
>
737 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
740 scoped_ptr
<SpdyFrame
>
741 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
744 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
745 (*late_headers
)[spdy_util_
.GetStatusKey()] = "500 Server Error";
746 scoped_ptr
<SpdyFrame
> headers_frame(
747 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
754 AddRead(*headers_frame
);
756 scoped_ptr
<SpdyFrame
> rst(
757 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
762 DeterministicSocketData
data(GetReads(), GetNumReads(),
763 GetWrites(), GetNumWrites());
764 MockConnect
connect_data(SYNCHRONOUS
, OK
);
765 data
.set_connect_data(connect_data
);
767 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
769 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
771 base::WeakPtr
<SpdyStream
> stream
=
772 CreateStreamSynchronously(
773 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
774 ASSERT_TRUE(stream
.get() != NULL
);
776 StreamDelegateDoNothing
delegate(stream
);
777 stream
->SetDelegate(&delegate
);
779 EXPECT_FALSE(stream
->HasUrlFromHeaders());
781 scoped_ptr
<SpdyHeaderBlock
> headers(
782 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
783 EXPECT_EQ(ERR_IO_PENDING
,
784 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
785 EXPECT_TRUE(stream
->HasUrlFromHeaders());
786 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
790 base::WeakPtr
<SpdyStream
> push_stream
;
791 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
792 EXPECT_TRUE(push_stream
);
796 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
797 EXPECT_FALSE(push_stream
);
801 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
804 // The tests below are only for SPDY/3 and above.
806 // Call IncreaseSendWindowSize on a stream with a large enough delta
807 // to overflow an int32. The SpdyStream should handle that case
809 TEST_P(SpdyStreamTest
, IncreaseSendWindowSizeOverflow
) {
811 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
813 scoped_ptr
<SpdyFrame
> req(
814 spdy_util_
.ConstructSpdyPost(
815 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
818 // Triggered by the overflowing call to IncreaseSendWindowSize
820 scoped_ptr
<SpdyFrame
> rst(
821 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR
));
828 DeterministicSocketData
data(GetReads(), GetNumReads(),
829 GetWrites(), GetNumWrites());
830 MockConnect
connect_data(SYNCHRONOUS
, OK
);
831 data
.set_connect_data(connect_data
);
833 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
835 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
836 GURL
url(kStreamUrl
);
838 base::WeakPtr
<SpdyStream
> stream
=
839 CreateStreamSynchronously(
840 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, log
.bound());
841 ASSERT_TRUE(stream
.get() != NULL
);
842 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
843 stream
->SetDelegate(&delegate
);
845 scoped_ptr
<SpdyHeaderBlock
> headers(
846 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
847 EXPECT_EQ(ERR_IO_PENDING
,
848 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
849 EXPECT_TRUE(stream
->HasUrlFromHeaders());
850 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
854 int32 old_send_window_size
= stream
->send_window_size();
855 ASSERT_GT(old_send_window_size
, 0);
856 int32 delta_window_size
= kint32max
- old_send_window_size
+ 1;
857 stream
->IncreaseSendWindowSize(delta_window_size
);
858 EXPECT_EQ(NULL
, stream
.get());
862 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
865 // Functions used with
866 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
868 void StallStream(const base::WeakPtr
<SpdyStream
>& stream
) {
869 // Reduce the send window size to 0 to stall.
870 while (stream
->send_window_size() > 0) {
871 stream
->DecreaseSendWindowSize(
872 std::min(kMaxSpdyFrameChunkSize
, stream
->send_window_size()));
876 void IncreaseStreamSendWindowSize(const base::WeakPtr
<SpdyStream
>& stream
,
877 int32 delta_window_size
) {
878 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
879 stream
->IncreaseSendWindowSize(delta_window_size
);
880 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
883 void AdjustStreamSendWindowSize(const base::WeakPtr
<SpdyStream
>& stream
,
884 int32 delta_window_size
) {
885 // Make sure that negative adjustments are handled properly.
886 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
887 stream
->AdjustSendWindowSize(-delta_window_size
);
888 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
889 stream
->AdjustSendWindowSize(+delta_window_size
);
890 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
891 stream
->AdjustSendWindowSize(+delta_window_size
);
892 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
895 // Given an unstall function, runs a test to make sure that a
896 // request/response (i.e., an HTTP-like) stream resumes after a stall
898 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
899 const UnstallFunction
& unstall_function
) {
900 GURL
url(kStreamUrl
);
903 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
905 scoped_ptr
<SpdyFrame
> req(
906 spdy_util_
.ConstructSpdyPost(
907 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
910 scoped_ptr
<SpdyFrame
> body(
911 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, true));
914 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
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_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
931 ASSERT_TRUE(stream
.get() != NULL
);
933 StreamDelegateWithBody
delegate(stream
, kPostBodyStringPiece
);
934 stream
->SetDelegate(&delegate
);
936 EXPECT_FALSE(stream
->HasUrlFromHeaders());
937 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
939 scoped_ptr
<SpdyHeaderBlock
> headers(
940 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
941 EXPECT_EQ(ERR_IO_PENDING
,
942 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
943 EXPECT_TRUE(stream
->HasUrlFromHeaders());
944 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
950 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
952 unstall_function
.Run(stream
, kPostBodyLength
);
954 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
958 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
960 EXPECT_TRUE(delegate
.send_headers_completed());
961 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
962 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
963 EXPECT_TRUE(data
.AllWriteDataConsumed());
966 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseRequestResponse
) {
967 RunResumeAfterUnstallRequestResponseTest(
968 base::Bind(&IncreaseStreamSendWindowSize
));
971 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustRequestResponse
) {
972 RunResumeAfterUnstallRequestResponseTest(
973 base::Bind(&AdjustStreamSendWindowSize
));
976 // Given an unstall function, runs a test to make sure that a
977 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
979 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
980 const UnstallFunction
& unstall_function
) {
981 GURL
url(kStreamUrl
);
984 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
986 scoped_ptr
<SpdyFrame
> req(
987 spdy_util_
.ConstructSpdyPost(
988 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
991 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
994 scoped_ptr
<SpdyFrame
> msg(
995 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
998 scoped_ptr
<SpdyFrame
> echo(
999 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
1004 DeterministicSocketData
data(GetReads(), GetNumReads(),
1005 GetWrites(), GetNumWrites());
1006 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1007 data
.set_connect_data(connect_data
);
1009 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1011 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
1013 base::WeakPtr
<SpdyStream
> stream
=
1014 CreateStreamSynchronously(
1015 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
1016 ASSERT_TRUE(stream
.get() != NULL
);
1018 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
1019 stream
->SetDelegate(&delegate
);
1021 EXPECT_FALSE(stream
->HasUrlFromHeaders());
1023 scoped_ptr
<SpdyHeaderBlock
> headers(
1024 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
1025 EXPECT_EQ(ERR_IO_PENDING
,
1026 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
1027 EXPECT_TRUE(stream
->HasUrlFromHeaders());
1028 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
1032 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
1034 StallStream(stream
);
1038 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
1040 unstall_function
.Run(stream
, kPostBodyLength
);
1042 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
1046 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
1048 EXPECT_TRUE(delegate
.send_headers_completed());
1049 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
1050 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
1051 delegate
.TakeReceivedData());
1052 EXPECT_TRUE(data
.AllWriteDataConsumed());
1055 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseBidirectional
) {
1056 RunResumeAfterUnstallBidirectionalTest(
1057 base::Bind(&IncreaseStreamSendWindowSize
));
1060 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustBidirectional
) {
1061 RunResumeAfterUnstallBidirectionalTest(
1062 base::Bind(&AdjustStreamSendWindowSize
));
1065 // Test calculation of amount of bytes received from network.
1066 TEST_P(SpdyStreamTest
, ReceivedBytes
) {
1067 GURL
url(kStreamUrl
);
1070 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
1072 scoped_ptr
<SpdyFrame
> syn(
1073 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1076 scoped_ptr
<SpdyFrame
>
1077 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1080 scoped_ptr
<SpdyFrame
> msg(
1081 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
1086 DeterministicSocketData
data(GetReads(), GetNumReads(),
1087 GetWrites(), GetNumWrites());
1088 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1089 data
.set_connect_data(connect_data
);
1091 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1093 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
1095 base::WeakPtr
<SpdyStream
> stream
=
1096 CreateStreamSynchronously(
1097 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
1098 ASSERT_TRUE(stream
.get() != NULL
);
1100 StreamDelegateDoNothing
delegate(stream
);
1101 stream
->SetDelegate(&delegate
);
1103 EXPECT_FALSE(stream
->HasUrlFromHeaders());
1105 scoped_ptr
<SpdyHeaderBlock
> headers(
1106 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
1107 EXPECT_EQ(ERR_IO_PENDING
,
1108 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
1109 EXPECT_TRUE(stream
->HasUrlFromHeaders());
1110 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
1112 int64 reply_frame_len
= reply
->size();
1113 int64 data_header_len
= spdy_util_
.CreateFramer(false)
1114 ->GetDataFrameMinimumSize();
1115 int64 data_frame_len
= data_header_len
+ kPostBodyLength
;
1116 int64 response_len
= reply_frame_len
+ data_frame_len
;
1118 EXPECT_EQ(0, stream
->raw_received_bytes());
1119 data
.RunFor(1); // SYN
1120 EXPECT_EQ(0, stream
->raw_received_bytes());
1121 data
.RunFor(1); // REPLY
1122 EXPECT_EQ(reply_frame_len
, stream
->raw_received_bytes());
1123 data
.RunFor(1); // DATA
1124 EXPECT_EQ(response_len
, stream
->raw_received_bytes());
1125 data
.RunFor(1); // FIN
1127 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());