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 // Delegate that receives trailers.
179 class StreamDelegateWithTrailers
: public test::StreamDelegateWithBody
{
181 StreamDelegateWithTrailers(const base::WeakPtr
<SpdyStream
>& stream
,
182 base::StringPiece data
)
183 : StreamDelegateWithBody(stream
, data
) {}
185 ~StreamDelegateWithTrailers() override
{}
187 void OnTrailers(const SpdyHeaderBlock
& trailers
) override
{
188 trailers_
= trailers
;
191 const SpdyHeaderBlock
& trailers() const { return trailers_
; }
194 SpdyHeaderBlock trailers_
;
197 // Regression test for crbug.com/481033.
198 TEST_P(SpdyStreamTest
, Trailers
) {
199 GURL
url(kStreamUrl
);
202 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
204 scoped_ptr
<SpdyFrame
> req(spdy_util_
.ConstructSpdyPost(
205 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
208 scoped_ptr
<SpdyFrame
> msg(
209 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, true));
212 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
215 scoped_ptr
<SpdyFrame
> echo(
216 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
219 const char* const kExtraHeaders
[] = {"foo", "bar"};
220 scoped_ptr
<SpdyFrame
> trailers(
221 spdy_util_
.ConstructSpdyHeaderFrame(1, kExtraHeaders
, 1));
226 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
228 MockConnect
connect_data(SYNCHRONOUS
, OK
);
229 data
.set_connect_data(connect_data
);
231 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
233 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
235 base::WeakPtr
<SpdyStream
> stream
= CreateStreamSynchronously(
236 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
237 ASSERT_TRUE(stream
.get() != NULL
);
239 StreamDelegateWithTrailers
delegate(stream
, kPostBodyStringPiece
);
240 stream
->SetDelegate(&delegate
);
242 EXPECT_FALSE(stream
->HasUrlFromHeaders());
244 scoped_ptr
<SpdyHeaderBlock
> headers(
245 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
246 EXPECT_EQ(ERR_IO_PENDING
,
247 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
248 EXPECT_TRUE(stream
->HasUrlFromHeaders());
249 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
251 data
.RunFor(GetNumReads() + GetNumWrites());
252 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
254 EXPECT_TRUE(delegate
.send_headers_completed());
255 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
256 const SpdyHeaderBlock
& received_trailers
= delegate
.trailers();
257 SpdyHeaderBlock::const_iterator it
= received_trailers
.find("foo");
258 EXPECT_EQ("bar", it
->second
);
259 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
260 delegate
.TakeReceivedData());
261 EXPECT_TRUE(data
.AllWriteDataConsumed());
264 TEST_P(SpdyStreamTest
, PushedStream
) {
266 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
270 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
272 MockConnect
connect_data(SYNCHRONOUS
, OK
);
273 data
.set_connect_data(connect_data
);
275 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
277 base::WeakPtr
<SpdySession
> spdy_session(CreateDefaultSpdySession());
279 // Conjure up a stream.
280 SpdyStream
stream(SPDY_PUSH_STREAM
, spdy_session
, GURL(), DEFAULT_PRIORITY
,
281 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31
),
282 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31
),
284 stream
.set_stream_id(2);
285 EXPECT_FALSE(stream
.HasUrlFromHeaders());
287 // Set required request headers.
288 SpdyHeaderBlock request_headers
;
289 spdy_util_
.AddUrlToHeaderBlock(kStreamUrl
, &request_headers
);
290 stream
.OnPushPromiseHeadersReceived(request_headers
);
292 // Send some basic response headers.
293 SpdyHeaderBlock response
;
294 response
[spdy_util_
.GetStatusKey()] = "200";
295 response
[spdy_util_
.GetVersionKey()] = "OK";
296 stream
.OnInitialResponseHeadersReceived(
297 response
, base::Time::Now(), base::TimeTicks::Now());
299 // And some more headers.
300 // TODO(baranovich): not valid for HTTP 2.
301 SpdyHeaderBlock headers
;
302 headers
["alpha"] = "beta";
303 stream
.OnAdditionalResponseHeadersReceived(headers
);
305 EXPECT_TRUE(stream
.HasUrlFromHeaders());
306 EXPECT_EQ(kStreamUrl
, stream
.GetUrlFromHeaders().spec());
308 StreamDelegateDoNothing
delegate(stream
.GetWeakPtr());
309 stream
.SetDelegate(&delegate
);
311 data
.RunFor(GetNumReads() + GetNumWrites());
313 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
314 EXPECT_EQ("beta", delegate
.GetResponseHeaderValue("alpha"));
316 EXPECT_TRUE(spdy_session
== NULL
);
319 TEST_P(SpdyStreamTest
, StreamError
) {
320 GURL
url(kStreamUrl
);
323 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
325 scoped_ptr
<SpdyFrame
> req(
326 spdy_util_
.ConstructSpdyPost(
327 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
330 scoped_ptr
<SpdyFrame
> resp(
331 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
334 scoped_ptr
<SpdyFrame
> msg(
335 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
338 scoped_ptr
<SpdyFrame
> echo(
339 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
346 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
348 MockConnect
connect_data(SYNCHRONOUS
, OK
);
349 data
.set_connect_data(connect_data
);
351 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
353 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
355 base::WeakPtr
<SpdyStream
> stream
=
356 CreateStreamSynchronously(
357 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, log
.bound());
358 ASSERT_TRUE(stream
.get() != NULL
);
360 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
361 stream
->SetDelegate(&delegate
);
363 EXPECT_FALSE(stream
->HasUrlFromHeaders());
365 scoped_ptr
<SpdyHeaderBlock
> headers(
366 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
367 EXPECT_EQ(ERR_IO_PENDING
,
368 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
369 EXPECT_TRUE(stream
->HasUrlFromHeaders());
370 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
372 data
.RunFor(GetNumReads() + GetNumWrites());
373 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
375 const SpdyStreamId stream_id
= delegate
.stream_id();
377 EXPECT_TRUE(delegate
.send_headers_completed());
378 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
379 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
380 delegate
.TakeReceivedData());
381 EXPECT_TRUE(data
.AllWriteDataConsumed());
383 // Check that the NetLog was filled reasonably.
384 TestNetLogEntry::List entries
;
385 log
.GetEntries(&entries
);
386 EXPECT_LT(0u, entries
.size());
388 // Check that we logged SPDY_STREAM_ERROR correctly.
389 int pos
= ExpectLogContainsSomewhere(
390 entries
, 0, NetLog::TYPE_HTTP2_STREAM_ERROR
, NetLog::PHASE_NONE
);
393 ASSERT_TRUE(entries
[pos
].GetIntegerValue("stream_id", &stream_id2
));
394 EXPECT_EQ(static_cast<int>(stream_id
), stream_id2
);
397 // Make sure that large blocks of data are properly split up into
398 // frame-sized chunks for a request/response (i.e., an HTTP-like)
400 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenRequestResponse
) {
401 GURL
url(kStreamUrl
);
404 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
406 scoped_ptr
<SpdyFrame
> req(
407 spdy_util_
.ConstructSpdyPost(
408 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
411 std::string
chunk_data(kMaxSpdyFrameChunkSize
, 'x');
412 scoped_ptr
<SpdyFrame
> chunk(
413 spdy_util_
.ConstructSpdyBodyFrame(
414 1, chunk_data
.data(), chunk_data
.length(), false));
418 scoped_ptr
<SpdyFrame
> last_chunk(
419 spdy_util_
.ConstructSpdyBodyFrame(
420 1, chunk_data
.data(), chunk_data
.length(), true));
421 AddWrite(*last_chunk
);
423 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
428 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
430 MockConnect
connect_data(SYNCHRONOUS
, OK
);
431 data
.set_connect_data(connect_data
);
433 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
435 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
437 base::WeakPtr
<SpdyStream
> stream
=
438 CreateStreamSynchronously(
439 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
440 ASSERT_TRUE(stream
.get() != NULL
);
442 std::string
body_data(3 * kMaxSpdyFrameChunkSize
, 'x');
443 StreamDelegateWithBody
delegate(stream
, body_data
);
444 stream
->SetDelegate(&delegate
);
446 EXPECT_FALSE(stream
->HasUrlFromHeaders());
448 scoped_ptr
<SpdyHeaderBlock
> headers(
449 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
450 EXPECT_EQ(ERR_IO_PENDING
,
451 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
452 EXPECT_TRUE(stream
->HasUrlFromHeaders());
453 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
455 data
.RunFor(GetNumReads() + GetNumWrites());
456 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
458 EXPECT_TRUE(delegate
.send_headers_completed());
459 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
460 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
461 EXPECT_TRUE(data
.AllWriteDataConsumed());
464 // Make sure that large blocks of data are properly split up into
465 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
467 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenBidirectional
) {
468 GURL
url(kStreamUrl
);
471 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
473 scoped_ptr
<SpdyFrame
> req(
474 spdy_util_
.ConstructSpdyPost(
475 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
478 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
481 std::string
chunk_data(kMaxSpdyFrameChunkSize
, 'x');
482 scoped_ptr
<SpdyFrame
> chunk(
483 spdy_util_
.ConstructSpdyBodyFrame(
484 1, chunk_data
.data(), chunk_data
.length(), false));
491 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
493 MockConnect
connect_data(SYNCHRONOUS
, OK
);
494 data
.set_connect_data(connect_data
);
496 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
498 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
500 base::WeakPtr
<SpdyStream
> stream
=
501 CreateStreamSynchronously(
502 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
503 ASSERT_TRUE(stream
.get() != NULL
);
505 std::string
body_data(3 * kMaxSpdyFrameChunkSize
, 'x');
506 StreamDelegateSendImmediate
delegate(stream
, body_data
);
507 stream
->SetDelegate(&delegate
);
509 EXPECT_FALSE(stream
->HasUrlFromHeaders());
511 scoped_ptr
<SpdyHeaderBlock
> headers(
512 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
513 EXPECT_EQ(ERR_IO_PENDING
,
514 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
515 EXPECT_TRUE(stream
->HasUrlFromHeaders());
516 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
518 data
.RunFor(GetNumReads() + GetNumWrites());
519 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
521 EXPECT_TRUE(delegate
.send_headers_completed());
522 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
523 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
524 EXPECT_TRUE(data
.AllWriteDataConsumed());
527 // Receiving a header with uppercase ASCII should result in a protocol
529 TEST_P(SpdyStreamTest
, UpperCaseHeaders
) {
530 GURL
url(kStreamUrl
);
533 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
535 scoped_ptr
<SpdyFrame
> syn(
536 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
539 const char* const kExtraHeaders
[] = {"X-UpperCase", "yes"};
540 scoped_ptr
<SpdyFrame
>
541 reply(spdy_util_
.ConstructSpdyGetSynReply(kExtraHeaders
, 1, 1));
544 scoped_ptr
<SpdyFrame
> rst(
545 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
550 DeterministicSocketData
data(GetReads(), GetNumReads(),
551 GetWrites(), GetNumWrites());
552 MockConnect
connect_data(SYNCHRONOUS
, OK
);
553 data
.set_connect_data(connect_data
);
555 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
557 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
559 base::WeakPtr
<SpdyStream
> stream
=
560 CreateStreamSynchronously(
561 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
562 ASSERT_TRUE(stream
.get() != NULL
);
564 StreamDelegateDoNothing
delegate(stream
);
565 stream
->SetDelegate(&delegate
);
567 EXPECT_FALSE(stream
->HasUrlFromHeaders());
569 scoped_ptr
<SpdyHeaderBlock
> headers(
570 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
571 EXPECT_EQ(ERR_IO_PENDING
,
572 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
573 EXPECT_TRUE(stream
->HasUrlFromHeaders());
574 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
578 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
581 // Receiving a header with uppercase ASCII should result in a protocol
582 // error even for a push stream.
583 TEST_P(SpdyStreamTest
, UpperCaseHeadersOnPush
) {
584 GURL
url(kStreamUrl
);
587 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
589 scoped_ptr
<SpdyFrame
> syn(
590 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
593 scoped_ptr
<SpdyFrame
>
594 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
597 const char* const extra_headers
[] = {"X-UpperCase", "yes"};
598 scoped_ptr
<SpdyFrame
>
599 push(spdy_util_
.ConstructSpdyPush(extra_headers
, 1, 2, 1, kStreamUrl
));
602 scoped_ptr
<SpdyFrame
> rst(
603 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
608 DeterministicSocketData
data(GetReads(), GetNumReads(),
609 GetWrites(), GetNumWrites());
610 MockConnect
connect_data(SYNCHRONOUS
, OK
);
611 data
.set_connect_data(connect_data
);
613 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
615 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
617 base::WeakPtr
<SpdyStream
> stream
=
618 CreateStreamSynchronously(
619 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
620 ASSERT_TRUE(stream
.get() != NULL
);
622 StreamDelegateDoNothing
delegate(stream
);
623 stream
->SetDelegate(&delegate
);
625 EXPECT_FALSE(stream
->HasUrlFromHeaders());
627 scoped_ptr
<SpdyHeaderBlock
> headers(
628 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
629 EXPECT_EQ(ERR_IO_PENDING
,
630 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
631 EXPECT_TRUE(stream
->HasUrlFromHeaders());
632 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
636 base::WeakPtr
<SpdyStream
> push_stream
;
637 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
638 EXPECT_FALSE(push_stream
);
642 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
645 // Receiving a header with uppercase ASCII in a HEADERS frame should
646 // result in a protocol error.
647 TEST_P(SpdyStreamTest
, UpperCaseHeadersInHeadersFrame
) {
648 GURL
url(kStreamUrl
);
651 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
653 scoped_ptr
<SpdyFrame
> syn(
654 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
657 scoped_ptr
<SpdyFrame
>
658 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
661 scoped_ptr
<SpdyFrame
>
662 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
665 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
666 (*late_headers
)["X-UpperCase"] = "yes";
667 scoped_ptr
<SpdyFrame
> headers_frame(
668 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
675 AddRead(*headers_frame
);
677 scoped_ptr
<SpdyFrame
> rst(
678 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
683 DeterministicSocketData
data(GetReads(), GetNumReads(),
684 GetWrites(), GetNumWrites());
685 MockConnect
connect_data(SYNCHRONOUS
, OK
);
686 data
.set_connect_data(connect_data
);
688 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
690 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
692 base::WeakPtr
<SpdyStream
> stream
=
693 CreateStreamSynchronously(
694 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
695 ASSERT_TRUE(stream
.get() != NULL
);
697 StreamDelegateDoNothing
delegate(stream
);
698 stream
->SetDelegate(&delegate
);
700 EXPECT_FALSE(stream
->HasUrlFromHeaders());
702 scoped_ptr
<SpdyHeaderBlock
> headers(
703 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
704 EXPECT_EQ(ERR_IO_PENDING
,
705 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
706 EXPECT_TRUE(stream
->HasUrlFromHeaders());
707 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
711 base::WeakPtr
<SpdyStream
> push_stream
;
712 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
713 EXPECT_TRUE(push_stream
);
717 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
718 EXPECT_FALSE(push_stream
);
722 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
725 // Receiving a duplicate header in a HEADERS frame should result in a
727 TEST_P(SpdyStreamTest
, DuplicateHeaders
) {
728 GURL
url(kStreamUrl
);
731 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
733 scoped_ptr
<SpdyFrame
> syn(
734 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
737 scoped_ptr
<SpdyFrame
>
738 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
741 scoped_ptr
<SpdyFrame
>
742 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
745 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
746 (*late_headers
)[spdy_util_
.GetStatusKey()] = "500 Server Error";
747 scoped_ptr
<SpdyFrame
> headers_frame(
748 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
755 AddRead(*headers_frame
);
757 scoped_ptr
<SpdyFrame
> rst(
758 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
763 DeterministicSocketData
data(GetReads(), GetNumReads(),
764 GetWrites(), GetNumWrites());
765 MockConnect
connect_data(SYNCHRONOUS
, OK
);
766 data
.set_connect_data(connect_data
);
768 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
770 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
772 base::WeakPtr
<SpdyStream
> stream
=
773 CreateStreamSynchronously(
774 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
775 ASSERT_TRUE(stream
.get() != NULL
);
777 StreamDelegateDoNothing
delegate(stream
);
778 stream
->SetDelegate(&delegate
);
780 EXPECT_FALSE(stream
->HasUrlFromHeaders());
782 scoped_ptr
<SpdyHeaderBlock
> headers(
783 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
784 EXPECT_EQ(ERR_IO_PENDING
,
785 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
786 EXPECT_TRUE(stream
->HasUrlFromHeaders());
787 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
791 base::WeakPtr
<SpdyStream
> push_stream
;
792 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
793 EXPECT_TRUE(push_stream
);
797 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
798 EXPECT_FALSE(push_stream
);
802 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
805 // The tests below are only for SPDY/3 and above.
807 // Call IncreaseSendWindowSize on a stream with a large enough delta
808 // to overflow an int32. The SpdyStream should handle that case
810 TEST_P(SpdyStreamTest
, IncreaseSendWindowSizeOverflow
) {
812 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
814 scoped_ptr
<SpdyFrame
> req(
815 spdy_util_
.ConstructSpdyPost(
816 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
819 // Triggered by the overflowing call to IncreaseSendWindowSize
821 scoped_ptr
<SpdyFrame
> rst(
822 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR
));
829 DeterministicSocketData
data(GetReads(), GetNumReads(),
830 GetWrites(), GetNumWrites());
831 MockConnect
connect_data(SYNCHRONOUS
, OK
);
832 data
.set_connect_data(connect_data
);
834 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
836 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
837 GURL
url(kStreamUrl
);
839 base::WeakPtr
<SpdyStream
> stream
=
840 CreateStreamSynchronously(
841 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, log
.bound());
842 ASSERT_TRUE(stream
.get() != NULL
);
843 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
844 stream
->SetDelegate(&delegate
);
846 scoped_ptr
<SpdyHeaderBlock
> headers(
847 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
848 EXPECT_EQ(ERR_IO_PENDING
,
849 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
850 EXPECT_TRUE(stream
->HasUrlFromHeaders());
851 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
855 int32 old_send_window_size
= stream
->send_window_size();
856 ASSERT_GT(old_send_window_size
, 0);
857 int32 delta_window_size
= kint32max
- old_send_window_size
+ 1;
858 stream
->IncreaseSendWindowSize(delta_window_size
);
859 EXPECT_EQ(NULL
, stream
.get());
863 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
866 // Functions used with
867 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
869 void StallStream(const base::WeakPtr
<SpdyStream
>& stream
) {
870 // Reduce the send window size to 0 to stall.
871 while (stream
->send_window_size() > 0) {
872 stream
->DecreaseSendWindowSize(
873 std::min(kMaxSpdyFrameChunkSize
, stream
->send_window_size()));
877 void IncreaseStreamSendWindowSize(const base::WeakPtr
<SpdyStream
>& stream
,
878 int32 delta_window_size
) {
879 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
880 stream
->IncreaseSendWindowSize(delta_window_size
);
881 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
884 void AdjustStreamSendWindowSize(const base::WeakPtr
<SpdyStream
>& stream
,
885 int32 delta_window_size
) {
886 // Make sure that negative adjustments are handled properly.
887 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
888 stream
->AdjustSendWindowSize(-delta_window_size
);
889 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
890 stream
->AdjustSendWindowSize(+delta_window_size
);
891 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
892 stream
->AdjustSendWindowSize(+delta_window_size
);
893 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
896 // Given an unstall function, runs a test to make sure that a
897 // request/response (i.e., an HTTP-like) stream resumes after a stall
899 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
900 const UnstallFunction
& unstall_function
) {
901 GURL
url(kStreamUrl
);
904 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
906 scoped_ptr
<SpdyFrame
> req(
907 spdy_util_
.ConstructSpdyPost(
908 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
911 scoped_ptr
<SpdyFrame
> body(
912 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, true));
915 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
920 DeterministicSocketData
data(GetReads(), GetNumReads(),
921 GetWrites(), GetNumWrites());
922 MockConnect
connect_data(SYNCHRONOUS
, OK
);
923 data
.set_connect_data(connect_data
);
925 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
927 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
929 base::WeakPtr
<SpdyStream
> stream
=
930 CreateStreamSynchronously(
931 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
932 ASSERT_TRUE(stream
.get() != NULL
);
934 StreamDelegateWithBody
delegate(stream
, kPostBodyStringPiece
);
935 stream
->SetDelegate(&delegate
);
937 EXPECT_FALSE(stream
->HasUrlFromHeaders());
938 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
940 scoped_ptr
<SpdyHeaderBlock
> headers(
941 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
942 EXPECT_EQ(ERR_IO_PENDING
,
943 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
944 EXPECT_TRUE(stream
->HasUrlFromHeaders());
945 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
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(), delegate
.TakeReceivedData());
964 EXPECT_TRUE(data
.AllWriteDataConsumed());
967 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseRequestResponse
) {
968 RunResumeAfterUnstallRequestResponseTest(
969 base::Bind(&IncreaseStreamSendWindowSize
));
972 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustRequestResponse
) {
973 RunResumeAfterUnstallRequestResponseTest(
974 base::Bind(&AdjustStreamSendWindowSize
));
977 // Given an unstall function, runs a test to make sure that a
978 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
980 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
981 const UnstallFunction
& unstall_function
) {
982 GURL
url(kStreamUrl
);
985 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
987 scoped_ptr
<SpdyFrame
> req(
988 spdy_util_
.ConstructSpdyPost(
989 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
992 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
995 scoped_ptr
<SpdyFrame
> msg(
996 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
999 scoped_ptr
<SpdyFrame
> echo(
1000 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
1005 DeterministicSocketData
data(GetReads(), GetNumReads(),
1006 GetWrites(), GetNumWrites());
1007 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1008 data
.set_connect_data(connect_data
);
1010 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1012 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
1014 base::WeakPtr
<SpdyStream
> stream
=
1015 CreateStreamSynchronously(
1016 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
1017 ASSERT_TRUE(stream
.get() != NULL
);
1019 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
1020 stream
->SetDelegate(&delegate
);
1022 EXPECT_FALSE(stream
->HasUrlFromHeaders());
1024 scoped_ptr
<SpdyHeaderBlock
> headers(
1025 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
1026 EXPECT_EQ(ERR_IO_PENDING
,
1027 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
1028 EXPECT_TRUE(stream
->HasUrlFromHeaders());
1029 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
1033 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
1035 StallStream(stream
);
1039 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
1041 unstall_function
.Run(stream
, kPostBodyLength
);
1043 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
1047 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
1049 EXPECT_TRUE(delegate
.send_headers_completed());
1050 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
1051 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
1052 delegate
.TakeReceivedData());
1053 EXPECT_TRUE(data
.AllWriteDataConsumed());
1056 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseBidirectional
) {
1057 RunResumeAfterUnstallBidirectionalTest(
1058 base::Bind(&IncreaseStreamSendWindowSize
));
1061 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustBidirectional
) {
1062 RunResumeAfterUnstallBidirectionalTest(
1063 base::Bind(&AdjustStreamSendWindowSize
));
1066 // Test calculation of amount of bytes received from network.
1067 TEST_P(SpdyStreamTest
, ReceivedBytes
) {
1068 GURL
url(kStreamUrl
);
1071 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
1073 scoped_ptr
<SpdyFrame
> syn(
1074 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
1077 scoped_ptr
<SpdyFrame
>
1078 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
1081 scoped_ptr
<SpdyFrame
> msg(
1082 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
1087 DeterministicSocketData
data(GetReads(), GetNumReads(),
1088 GetWrites(), GetNumWrites());
1089 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1090 data
.set_connect_data(connect_data
);
1092 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1094 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
1096 base::WeakPtr
<SpdyStream
> stream
=
1097 CreateStreamSynchronously(
1098 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
1099 ASSERT_TRUE(stream
.get() != NULL
);
1101 StreamDelegateDoNothing
delegate(stream
);
1102 stream
->SetDelegate(&delegate
);
1104 EXPECT_FALSE(stream
->HasUrlFromHeaders());
1106 scoped_ptr
<SpdyHeaderBlock
> headers(
1107 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
1108 EXPECT_EQ(ERR_IO_PENDING
,
1109 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
1110 EXPECT_TRUE(stream
->HasUrlFromHeaders());
1111 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
1113 int64 reply_frame_len
= reply
->size();
1114 int64 data_header_len
= spdy_util_
.CreateFramer(false)
1115 ->GetDataFrameMinimumSize();
1116 int64 data_frame_len
= data_header_len
+ kPostBodyLength
;
1117 int64 response_len
= reply_frame_len
+ data_frame_len
;
1119 EXPECT_EQ(0, stream
->raw_received_bytes());
1120 data
.RunFor(1); // SYN
1121 EXPECT_EQ(0, stream
->raw_received_bytes());
1122 data
.RunFor(1); // REPLY
1123 EXPECT_EQ(reply_frame_len
, stream
->raw_received_bytes());
1124 data
.RunFor(1); // DATA
1125 EXPECT_EQ(response_len
, stream
->raw_received_bytes());
1126 data
.RunFor(1); // FIN
1128 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());