1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_piece.h"
13 #include "net/base/completion_callback.h"
14 #include "net/base/net_log_unittest.h"
15 #include "net/base/request_priority.h"
16 #include "net/socket/next_proto.h"
17 #include "net/socket/socket_test_util.h"
18 #include "net/spdy/buffered_spdy_framer.h"
19 #include "net/spdy/spdy_http_utils.h"
20 #include "net/spdy/spdy_protocol.h"
21 #include "net/spdy/spdy_session.h"
22 #include "net/spdy/spdy_stream.h"
23 #include "net/spdy/spdy_stream_test_util.h"
24 #include "net/spdy/spdy_test_util_common.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
35 const char kStreamUrl
[] = "http://www.google.com/";
36 const char kPostBody
[] = "\0hello!\xff";
37 const size_t kPostBodyLength
= arraysize(kPostBody
);
38 const base::StringPiece
kPostBodyStringPiece(kPostBody
, kPostBodyLength
);
40 class SpdyStreamTest
: public ::testing::Test
,
41 public ::testing::WithParamInterface
<NextProto
> {
43 // A function that takes a SpdyStream and the number of bytes which
44 // will unstall the next frame completely.
45 typedef base::Callback
<void(const base::WeakPtr
<SpdyStream
>&, int32
)>
49 : spdy_util_(GetParam()),
50 session_deps_(GetParam()),
53 base::WeakPtr
<SpdySession
> CreateDefaultSpdySession() {
54 SpdySessionKey
key(HostPortPair("www.google.com", 80),
55 ProxyServer::Direct(),
56 PRIVACY_MODE_DISABLED
);
57 return CreateInsecureSpdySession(session_
, key
, BoundNetLog());
60 void TearDown() override
{ base::MessageLoop::current()->RunUntilIdle(); }
62 void RunResumeAfterUnstallRequestResponseTest(
63 const UnstallFunction
& unstall_function
);
65 void RunResumeAfterUnstallBidirectionalTest(
66 const UnstallFunction
& unstall_function
);
68 // Add{Read,Write}() populates lists that are eventually passed to a
69 // SocketData class. |frame| must live for the whole test.
71 void AddRead(const SpdyFrame
& frame
) {
72 reads_
.push_back(CreateMockRead(frame
, offset_
++));
75 void AddWrite(const SpdyFrame
& frame
) {
76 writes_
.push_back(CreateMockWrite(frame
, offset_
++));
80 reads_
.push_back(MockRead(ASYNC
, 0, offset_
++));
83 MockRead
* GetReads() {
84 return vector_as_array(&reads_
);
87 size_t GetNumReads() const {
91 MockWrite
* GetWrites() {
92 return vector_as_array(&writes_
);
95 int GetNumWrites() const {
96 return writes_
.size();
99 SpdyTestUtil spdy_util_
;
100 SpdySessionDependencies session_deps_
;
101 scoped_refptr
<HttpNetworkSession
> session_
;
104 // Used by Add{Read,Write}() above.
105 std::vector
<MockWrite
> writes_
;
106 std::vector
<MockRead
> reads_
;
110 INSTANTIATE_TEST_CASE_P(
113 testing::Values(kProtoSPDY31
, kProtoSPDY4_14
, kProtoSPDY4_15
));
115 TEST_P(SpdyStreamTest
, SendDataAfterOpen
) {
116 GURL
url(kStreamUrl
);
118 session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
120 scoped_ptr
<SpdyFrame
> req(
121 spdy_util_
.ConstructSpdyPost(
122 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
125 scoped_ptr
<SpdyFrame
> resp(
126 spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
129 scoped_ptr
<SpdyFrame
> msg(
130 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
133 scoped_ptr
<SpdyFrame
> echo(
134 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
139 OrderedSocketData
data(GetReads(), GetNumReads(),
140 GetWrites(), GetNumWrites());
141 MockConnect
connect_data(SYNCHRONOUS
, OK
);
142 data
.set_connect_data(connect_data
);
144 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
146 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
148 base::WeakPtr
<SpdyStream
> stream
=
149 CreateStreamSynchronously(
150 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
151 ASSERT_TRUE(stream
.get() != NULL
);
153 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
154 stream
->SetDelegate(&delegate
);
156 EXPECT_FALSE(stream
->HasUrlFromHeaders());
158 scoped_ptr
<SpdyHeaderBlock
> headers(
159 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
160 EXPECT_EQ(ERR_IO_PENDING
,
161 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
162 EXPECT_TRUE(stream
->HasUrlFromHeaders());
163 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
165 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
167 EXPECT_TRUE(delegate
.send_headers_completed());
168 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
169 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
170 delegate
.TakeReceivedData());
171 EXPECT_TRUE(data
.at_write_eof());
174 TEST_P(SpdyStreamTest
, PushedStream
) {
175 session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
179 OrderedSocketData
data(GetReads(), GetNumReads(),
180 GetWrites(), GetNumWrites());
181 MockConnect
connect_data(SYNCHRONOUS
, OK
);
182 data
.set_connect_data(connect_data
);
184 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
186 base::WeakPtr
<SpdySession
> spdy_session(CreateDefaultSpdySession());
188 // Conjure up a stream.
189 SpdyStream
stream(SPDY_PUSH_STREAM
, spdy_session
, GURL(), DEFAULT_PRIORITY
,
190 SpdySession::GetInitialWindowSize(kProtoSPDY31
),
191 SpdySession::GetInitialWindowSize(kProtoSPDY31
),
193 stream
.set_stream_id(2);
194 EXPECT_FALSE(stream
.HasUrlFromHeaders());
196 // Set required request headers.
197 SpdyHeaderBlock request_headers
;
198 spdy_util_
.AddUrlToHeaderBlock(kStreamUrl
, &request_headers
);
199 stream
.OnPushPromiseHeadersReceived(request_headers
);
201 // Send some basic response headers.
202 SpdyHeaderBlock response
;
203 response
[spdy_util_
.GetStatusKey()] = "200";
204 response
[spdy_util_
.GetVersionKey()] = "OK";
205 stream
.OnInitialResponseHeadersReceived(
206 response
, base::Time::Now(), base::TimeTicks::Now());
208 // And some more headers.
209 // TODO(baranovich): not valid for HTTP 2.
210 SpdyHeaderBlock headers
;
211 headers
["alpha"] = "beta";
212 stream
.OnAdditionalResponseHeadersReceived(headers
);
214 EXPECT_TRUE(stream
.HasUrlFromHeaders());
215 EXPECT_EQ(kStreamUrl
, stream
.GetUrlFromHeaders().spec());
217 StreamDelegateDoNothing
delegate(stream
.GetWeakPtr());
218 stream
.SetDelegate(&delegate
);
220 base::MessageLoop::current()->RunUntilIdle();
222 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
223 EXPECT_EQ("beta", delegate
.GetResponseHeaderValue("alpha"));
225 EXPECT_TRUE(spdy_session
== NULL
);
228 TEST_P(SpdyStreamTest
, StreamError
) {
229 GURL
url(kStreamUrl
);
231 session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
233 scoped_ptr
<SpdyFrame
> req(
234 spdy_util_
.ConstructSpdyPost(
235 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
238 scoped_ptr
<SpdyFrame
> resp(
239 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
242 scoped_ptr
<SpdyFrame
> msg(
243 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
246 scoped_ptr
<SpdyFrame
> echo(
247 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
252 CapturingBoundNetLog log
;
254 OrderedSocketData
data(GetReads(), GetNumReads(),
255 GetWrites(), GetNumWrites());
256 MockConnect
connect_data(SYNCHRONOUS
, OK
);
257 data
.set_connect_data(connect_data
);
259 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
261 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
263 base::WeakPtr
<SpdyStream
> stream
=
264 CreateStreamSynchronously(
265 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, log
.bound());
266 ASSERT_TRUE(stream
.get() != NULL
);
268 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
269 stream
->SetDelegate(&delegate
);
271 EXPECT_FALSE(stream
->HasUrlFromHeaders());
273 scoped_ptr
<SpdyHeaderBlock
> headers(
274 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
275 EXPECT_EQ(ERR_IO_PENDING
,
276 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
277 EXPECT_TRUE(stream
->HasUrlFromHeaders());
278 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
280 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
282 const SpdyStreamId stream_id
= delegate
.stream_id();
284 EXPECT_TRUE(delegate
.send_headers_completed());
285 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
286 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
287 delegate
.TakeReceivedData());
288 EXPECT_TRUE(data
.at_write_eof());
290 // Check that the NetLog was filled reasonably.
291 net::CapturingNetLog::CapturedEntryList entries
;
292 log
.GetEntries(&entries
);
293 EXPECT_LT(0u, entries
.size());
295 // Check that we logged SPDY_STREAM_ERROR correctly.
296 int pos
= net::ExpectLogContainsSomewhere(
297 entries
, 0, net::NetLog::TYPE_HTTP2_STREAM_ERROR
,
298 net::NetLog::PHASE_NONE
);
301 ASSERT_TRUE(entries
[pos
].GetIntegerValue("stream_id", &stream_id2
));
302 EXPECT_EQ(static_cast<int>(stream_id
), stream_id2
);
305 // Make sure that large blocks of data are properly split up into
306 // frame-sized chunks for a request/response (i.e., an HTTP-like)
308 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenRequestResponse
) {
309 GURL
url(kStreamUrl
);
311 session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
313 scoped_ptr
<SpdyFrame
> req(
314 spdy_util_
.ConstructSpdyPost(
315 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
318 std::string
chunk_data(kMaxSpdyFrameChunkSize
, 'x');
319 scoped_ptr
<SpdyFrame
> chunk(
320 spdy_util_
.ConstructSpdyBodyFrame(
321 1, chunk_data
.data(), chunk_data
.length(), false));
325 scoped_ptr
<SpdyFrame
> last_chunk(
326 spdy_util_
.ConstructSpdyBodyFrame(
327 1, chunk_data
.data(), chunk_data
.length(), true));
328 AddWrite(*last_chunk
);
330 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
335 OrderedSocketData
data(GetReads(), GetNumReads(),
336 GetWrites(), GetNumWrites());
337 MockConnect
connect_data(SYNCHRONOUS
, OK
);
338 data
.set_connect_data(connect_data
);
340 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
342 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
344 base::WeakPtr
<SpdyStream
> stream
=
345 CreateStreamSynchronously(
346 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
347 ASSERT_TRUE(stream
.get() != NULL
);
349 std::string
body_data(3 * kMaxSpdyFrameChunkSize
, 'x');
350 StreamDelegateWithBody
delegate(stream
, body_data
);
351 stream
->SetDelegate(&delegate
);
353 EXPECT_FALSE(stream
->HasUrlFromHeaders());
355 scoped_ptr
<SpdyHeaderBlock
> headers(
356 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
357 EXPECT_EQ(ERR_IO_PENDING
,
358 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
359 EXPECT_TRUE(stream
->HasUrlFromHeaders());
360 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
362 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
364 EXPECT_TRUE(delegate
.send_headers_completed());
365 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
366 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
367 EXPECT_TRUE(data
.at_write_eof());
370 // Make sure that large blocks of data are properly split up into
371 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
373 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenBidirectional
) {
374 GURL
url(kStreamUrl
);
376 session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
378 scoped_ptr
<SpdyFrame
> req(
379 spdy_util_
.ConstructSpdyPost(
380 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
383 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
386 std::string
chunk_data(kMaxSpdyFrameChunkSize
, 'x');
387 scoped_ptr
<SpdyFrame
> chunk(
388 spdy_util_
.ConstructSpdyBodyFrame(
389 1, chunk_data
.data(), chunk_data
.length(), false));
396 OrderedSocketData
data(GetReads(), GetNumReads(),
397 GetWrites(), GetNumWrites());
398 MockConnect
connect_data(SYNCHRONOUS
, OK
);
399 data
.set_connect_data(connect_data
);
401 session_deps_
.socket_factory
->AddSocketDataProvider(&data
);
403 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
405 base::WeakPtr
<SpdyStream
> stream
=
406 CreateStreamSynchronously(
407 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
408 ASSERT_TRUE(stream
.get() != NULL
);
410 std::string
body_data(3 * kMaxSpdyFrameChunkSize
, 'x');
411 StreamDelegateSendImmediate
delegate(stream
, body_data
);
412 stream
->SetDelegate(&delegate
);
414 EXPECT_FALSE(stream
->HasUrlFromHeaders());
416 scoped_ptr
<SpdyHeaderBlock
> headers(
417 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
418 EXPECT_EQ(ERR_IO_PENDING
,
419 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
420 EXPECT_TRUE(stream
->HasUrlFromHeaders());
421 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
423 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
425 EXPECT_TRUE(delegate
.send_headers_completed());
426 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
427 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
428 EXPECT_TRUE(data
.at_write_eof());
431 // Receiving a header with uppercase ASCII should result in a protocol
433 TEST_P(SpdyStreamTest
, UpperCaseHeaders
) {
434 GURL
url(kStreamUrl
);
437 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
439 scoped_ptr
<SpdyFrame
> syn(
440 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
443 const char* const kExtraHeaders
[] = {"X-UpperCase", "yes"};
444 scoped_ptr
<SpdyFrame
>
445 reply(spdy_util_
.ConstructSpdyGetSynReply(kExtraHeaders
, 1, 1));
448 scoped_ptr
<SpdyFrame
> rst(
449 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
454 DeterministicSocketData
data(GetReads(), GetNumReads(),
455 GetWrites(), GetNumWrites());
456 MockConnect
connect_data(SYNCHRONOUS
, OK
);
457 data
.set_connect_data(connect_data
);
459 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
461 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
463 base::WeakPtr
<SpdyStream
> stream
=
464 CreateStreamSynchronously(
465 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
466 ASSERT_TRUE(stream
.get() != NULL
);
468 StreamDelegateDoNothing
delegate(stream
);
469 stream
->SetDelegate(&delegate
);
471 EXPECT_FALSE(stream
->HasUrlFromHeaders());
473 scoped_ptr
<SpdyHeaderBlock
> headers(
474 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
475 EXPECT_EQ(ERR_IO_PENDING
,
476 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
477 EXPECT_TRUE(stream
->HasUrlFromHeaders());
478 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
482 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
485 // Receiving a header with uppercase ASCII should result in a protocol
486 // error even for a push stream.
487 TEST_P(SpdyStreamTest
, UpperCaseHeadersOnPush
) {
488 GURL
url(kStreamUrl
);
491 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
493 scoped_ptr
<SpdyFrame
> syn(
494 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
497 scoped_ptr
<SpdyFrame
>
498 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
501 const char* const extra_headers
[] = {"X-UpperCase", "yes"};
502 scoped_ptr
<SpdyFrame
>
503 push(spdy_util_
.ConstructSpdyPush(extra_headers
, 1, 2, 1, kStreamUrl
));
506 scoped_ptr
<SpdyFrame
> rst(
507 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
512 DeterministicSocketData
data(GetReads(), GetNumReads(),
513 GetWrites(), GetNumWrites());
514 MockConnect
connect_data(SYNCHRONOUS
, OK
);
515 data
.set_connect_data(connect_data
);
517 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
519 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
521 base::WeakPtr
<SpdyStream
> stream
=
522 CreateStreamSynchronously(
523 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
524 ASSERT_TRUE(stream
.get() != NULL
);
526 StreamDelegateDoNothing
delegate(stream
);
527 stream
->SetDelegate(&delegate
);
529 EXPECT_FALSE(stream
->HasUrlFromHeaders());
531 scoped_ptr
<SpdyHeaderBlock
> headers(
532 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
533 EXPECT_EQ(ERR_IO_PENDING
,
534 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
535 EXPECT_TRUE(stream
->HasUrlFromHeaders());
536 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
540 base::WeakPtr
<SpdyStream
> push_stream
;
541 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
542 EXPECT_FALSE(push_stream
);
546 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
549 // Receiving a header with uppercase ASCII in a HEADERS frame should
550 // result in a protocol error.
551 TEST_P(SpdyStreamTest
, UpperCaseHeadersInHeadersFrame
) {
552 GURL
url(kStreamUrl
);
555 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
557 scoped_ptr
<SpdyFrame
> syn(
558 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
561 scoped_ptr
<SpdyFrame
>
562 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
565 scoped_ptr
<SpdyFrame
>
566 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
569 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
570 (*late_headers
)["X-UpperCase"] = "yes";
571 scoped_ptr
<SpdyFrame
> headers_frame(
572 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
579 AddRead(*headers_frame
);
581 scoped_ptr
<SpdyFrame
> rst(
582 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
587 DeterministicSocketData
data(GetReads(), GetNumReads(),
588 GetWrites(), GetNumWrites());
589 MockConnect
connect_data(SYNCHRONOUS
, OK
);
590 data
.set_connect_data(connect_data
);
592 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
594 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
596 base::WeakPtr
<SpdyStream
> stream
=
597 CreateStreamSynchronously(
598 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
599 ASSERT_TRUE(stream
.get() != NULL
);
601 StreamDelegateDoNothing
delegate(stream
);
602 stream
->SetDelegate(&delegate
);
604 EXPECT_FALSE(stream
->HasUrlFromHeaders());
606 scoped_ptr
<SpdyHeaderBlock
> headers(
607 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
608 EXPECT_EQ(ERR_IO_PENDING
,
609 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
610 EXPECT_TRUE(stream
->HasUrlFromHeaders());
611 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
615 base::WeakPtr
<SpdyStream
> push_stream
;
616 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
617 EXPECT_TRUE(push_stream
);
621 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
622 EXPECT_FALSE(push_stream
);
626 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
629 // Receiving a duplicate header in a HEADERS frame should result in a
631 TEST_P(SpdyStreamTest
, DuplicateHeaders
) {
632 GURL
url(kStreamUrl
);
635 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
637 scoped_ptr
<SpdyFrame
> syn(
638 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
641 scoped_ptr
<SpdyFrame
>
642 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
645 scoped_ptr
<SpdyFrame
>
646 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
649 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
650 (*late_headers
)[spdy_util_
.GetStatusKey()] = "500 Server Error";
651 scoped_ptr
<SpdyFrame
> headers_frame(
652 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
659 AddRead(*headers_frame
);
661 scoped_ptr
<SpdyFrame
> rst(
662 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
667 DeterministicSocketData
data(GetReads(), GetNumReads(),
668 GetWrites(), GetNumWrites());
669 MockConnect
connect_data(SYNCHRONOUS
, OK
);
670 data
.set_connect_data(connect_data
);
672 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
674 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
676 base::WeakPtr
<SpdyStream
> stream
=
677 CreateStreamSynchronously(
678 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
679 ASSERT_TRUE(stream
.get() != NULL
);
681 StreamDelegateDoNothing
delegate(stream
);
682 stream
->SetDelegate(&delegate
);
684 EXPECT_FALSE(stream
->HasUrlFromHeaders());
686 scoped_ptr
<SpdyHeaderBlock
> headers(
687 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
688 EXPECT_EQ(ERR_IO_PENDING
,
689 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
690 EXPECT_TRUE(stream
->HasUrlFromHeaders());
691 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
695 base::WeakPtr
<SpdyStream
> push_stream
;
696 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
697 EXPECT_TRUE(push_stream
);
701 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
702 EXPECT_FALSE(push_stream
);
706 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
709 // The tests below are only for SPDY/3 and above.
711 // Call IncreaseSendWindowSize on a stream with a large enough delta
712 // to overflow an int32. The SpdyStream should handle that case
714 TEST_P(SpdyStreamTest
, IncreaseSendWindowSizeOverflow
) {
716 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
718 scoped_ptr
<SpdyFrame
> req(
719 spdy_util_
.ConstructSpdyPost(
720 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
723 // Triggered by the overflowing call to IncreaseSendWindowSize
725 scoped_ptr
<SpdyFrame
> rst(
726 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR
));
731 CapturingBoundNetLog log
;
733 DeterministicSocketData
data(GetReads(), GetNumReads(),
734 GetWrites(), GetNumWrites());
735 MockConnect
connect_data(SYNCHRONOUS
, OK
);
736 data
.set_connect_data(connect_data
);
738 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
740 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
741 GURL
url(kStreamUrl
);
743 base::WeakPtr
<SpdyStream
> stream
=
744 CreateStreamSynchronously(
745 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, log
.bound());
746 ASSERT_TRUE(stream
.get() != NULL
);
747 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
748 stream
->SetDelegate(&delegate
);
750 scoped_ptr
<SpdyHeaderBlock
> headers(
751 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
752 EXPECT_EQ(ERR_IO_PENDING
,
753 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
754 EXPECT_TRUE(stream
->HasUrlFromHeaders());
755 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
759 int32 old_send_window_size
= stream
->send_window_size();
760 ASSERT_GT(old_send_window_size
, 0);
761 int32 delta_window_size
= kint32max
- old_send_window_size
+ 1;
762 stream
->IncreaseSendWindowSize(delta_window_size
);
763 EXPECT_EQ(NULL
, stream
.get());
767 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
770 // Functions used with
771 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
773 void StallStream(const base::WeakPtr
<SpdyStream
>& stream
) {
774 // Reduce the send window size to 0 to stall.
775 while (stream
->send_window_size() > 0) {
776 stream
->DecreaseSendWindowSize(
777 std::min(kMaxSpdyFrameChunkSize
, stream
->send_window_size()));
781 void IncreaseStreamSendWindowSize(const base::WeakPtr
<SpdyStream
>& stream
,
782 int32 delta_window_size
) {
783 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
784 stream
->IncreaseSendWindowSize(delta_window_size
);
785 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
788 void AdjustStreamSendWindowSize(const base::WeakPtr
<SpdyStream
>& stream
,
789 int32 delta_window_size
) {
790 // Make sure that negative adjustments are handled properly.
791 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
792 stream
->AdjustSendWindowSize(-delta_window_size
);
793 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
794 stream
->AdjustSendWindowSize(+delta_window_size
);
795 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
796 stream
->AdjustSendWindowSize(+delta_window_size
);
797 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
800 // Given an unstall function, runs a test to make sure that a
801 // request/response (i.e., an HTTP-like) stream resumes after a stall
803 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
804 const UnstallFunction
& unstall_function
) {
805 GURL
url(kStreamUrl
);
808 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
810 scoped_ptr
<SpdyFrame
> req(
811 spdy_util_
.ConstructSpdyPost(
812 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
815 scoped_ptr
<SpdyFrame
> body(
816 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, true));
819 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
824 DeterministicSocketData
data(GetReads(), GetNumReads(),
825 GetWrites(), GetNumWrites());
826 MockConnect
connect_data(SYNCHRONOUS
, OK
);
827 data
.set_connect_data(connect_data
);
829 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
831 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
833 base::WeakPtr
<SpdyStream
> stream
=
834 CreateStreamSynchronously(
835 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
836 ASSERT_TRUE(stream
.get() != NULL
);
838 StreamDelegateWithBody
delegate(stream
, kPostBodyStringPiece
);
839 stream
->SetDelegate(&delegate
);
841 EXPECT_FALSE(stream
->HasUrlFromHeaders());
842 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
844 scoped_ptr
<SpdyHeaderBlock
> headers(
845 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
846 EXPECT_EQ(ERR_IO_PENDING
,
847 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
848 EXPECT_TRUE(stream
->HasUrlFromHeaders());
849 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
855 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
857 unstall_function
.Run(stream
, kPostBodyLength
);
859 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
863 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
865 EXPECT_TRUE(delegate
.send_headers_completed());
866 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
867 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
868 EXPECT_TRUE(data
.at_write_eof());
871 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseRequestResponse
) {
872 RunResumeAfterUnstallRequestResponseTest(
873 base::Bind(&IncreaseStreamSendWindowSize
));
876 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustRequestResponse
) {
877 RunResumeAfterUnstallRequestResponseTest(
878 base::Bind(&AdjustStreamSendWindowSize
));
881 // Given an unstall function, runs a test to make sure that a
882 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
884 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
885 const UnstallFunction
& unstall_function
) {
886 GURL
url(kStreamUrl
);
889 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
891 scoped_ptr
<SpdyFrame
> req(
892 spdy_util_
.ConstructSpdyPost(
893 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
896 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
899 scoped_ptr
<SpdyFrame
> msg(
900 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
903 scoped_ptr
<SpdyFrame
> echo(
904 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
909 DeterministicSocketData
data(GetReads(), GetNumReads(),
910 GetWrites(), GetNumWrites());
911 MockConnect
connect_data(SYNCHRONOUS
, OK
);
912 data
.set_connect_data(connect_data
);
914 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
916 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
918 base::WeakPtr
<SpdyStream
> stream
=
919 CreateStreamSynchronously(
920 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
921 ASSERT_TRUE(stream
.get() != NULL
);
923 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
924 stream
->SetDelegate(&delegate
);
926 EXPECT_FALSE(stream
->HasUrlFromHeaders());
928 scoped_ptr
<SpdyHeaderBlock
> headers(
929 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
930 EXPECT_EQ(ERR_IO_PENDING
,
931 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
932 EXPECT_TRUE(stream
->HasUrlFromHeaders());
933 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
937 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
943 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
945 unstall_function
.Run(stream
, kPostBodyLength
);
947 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
951 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
953 EXPECT_TRUE(delegate
.send_headers_completed());
954 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
955 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
956 delegate
.TakeReceivedData());
957 EXPECT_TRUE(data
.at_write_eof());
960 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseBidirectional
) {
961 RunResumeAfterUnstallBidirectionalTest(
962 base::Bind(&IncreaseStreamSendWindowSize
));
965 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustBidirectional
) {
966 RunResumeAfterUnstallBidirectionalTest(
967 base::Bind(&AdjustStreamSendWindowSize
));
970 // Test calculation of amount of bytes received from network.
971 TEST_P(SpdyStreamTest
, ReceivedBytes
) {
972 GURL
url(kStreamUrl
);
975 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
977 scoped_ptr
<SpdyFrame
> syn(
978 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
981 scoped_ptr
<SpdyFrame
>
982 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
985 scoped_ptr
<SpdyFrame
> msg(
986 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
991 DeterministicSocketData
data(GetReads(), GetNumReads(),
992 GetWrites(), GetNumWrites());
993 MockConnect
connect_data(SYNCHRONOUS
, OK
);
994 data
.set_connect_data(connect_data
);
996 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
998 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
1000 base::WeakPtr
<SpdyStream
> stream
=
1001 CreateStreamSynchronously(
1002 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
1003 ASSERT_TRUE(stream
.get() != NULL
);
1005 StreamDelegateDoNothing
delegate(stream
);
1006 stream
->SetDelegate(&delegate
);
1008 EXPECT_FALSE(stream
->HasUrlFromHeaders());
1010 scoped_ptr
<SpdyHeaderBlock
> headers(
1011 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
1012 EXPECT_EQ(ERR_IO_PENDING
,
1013 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
1014 EXPECT_TRUE(stream
->HasUrlFromHeaders());
1015 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
1017 int64 reply_frame_len
= reply
->size();
1018 int64 data_header_len
= spdy_util_
.CreateFramer(false)
1019 ->GetDataFrameMinimumSize();
1020 int64 data_frame_len
= data_header_len
+ kPostBodyLength
;
1021 int64 response_len
= reply_frame_len
+ data_frame_len
;
1023 EXPECT_EQ(0, stream
->raw_received_bytes());
1024 data
.RunFor(1); // SYN
1025 EXPECT_EQ(0, stream
->raw_received_bytes());
1026 data
.RunFor(1); // REPLY
1027 EXPECT_EQ(reply_frame_len
, stream
->raw_received_bytes());
1028 data
.RunFor(1); // DATA
1029 EXPECT_EQ(response_len
, stream
->raw_received_bytes());
1030 data
.RunFor(1); // FIN
1032 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());