1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_piece.h"
13 #include "net/base/completion_callback.h"
14 #include "net/base/request_priority.h"
15 #include "net/log/net_log_unittest.h"
16 #include "net/socket/next_proto.h"
17 #include "net/socket/socket_test_util.h"
18 #include "net/spdy/buffered_spdy_framer.h"
19 #include "net/spdy/spdy_http_utils.h"
20 #include "net/spdy/spdy_protocol.h"
21 #include "net/spdy/spdy_session.h"
22 #include "net/spdy/spdy_stream.h"
23 #include "net/spdy/spdy_stream_test_util.h"
24 #include "net/spdy/spdy_test_util_common.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
35 const char kStreamUrl
[] = "http://www.example.org/";
36 const char kPostBody
[] = "\0hello!\xff";
37 const size_t kPostBodyLength
= arraysize(kPostBody
);
38 const base::StringPiece
kPostBodyStringPiece(kPostBody
, kPostBodyLength
);
40 class SpdyStreamTest
: public ::testing::Test
,
41 public ::testing::WithParamInterface
<NextProto
> {
43 // A function that takes a SpdyStream and the number of bytes which
44 // will unstall the next frame completely.
45 typedef base::Callback
<void(const base::WeakPtr
<SpdyStream
>&, int32
)>
49 : spdy_util_(GetParam()),
50 session_deps_(GetParam()),
53 base::WeakPtr
<SpdySession
> CreateDefaultSpdySession() {
54 SpdySessionKey
key(HostPortPair("www.example.org", 80),
55 ProxyServer::Direct(), PRIVACY_MODE_DISABLED
);
56 return CreateInsecureSpdySession(session_
, key
, BoundNetLog());
59 void TearDown() override
{ base::MessageLoop::current()->RunUntilIdle(); }
61 void RunResumeAfterUnstallRequestResponseTest(
62 const UnstallFunction
& unstall_function
);
64 void RunResumeAfterUnstallBidirectionalTest(
65 const UnstallFunction
& unstall_function
);
67 // Add{Read,Write}() populates lists that are eventually passed to a
68 // SocketData class. |frame| must live for the whole test.
70 void AddRead(const SpdyFrame
& frame
) {
71 reads_
.push_back(CreateMockRead(frame
, offset_
++));
74 void AddWrite(const SpdyFrame
& frame
) {
75 writes_
.push_back(CreateMockWrite(frame
, offset_
++));
79 reads_
.push_back(MockRead(ASYNC
, 0, offset_
++));
82 MockRead
* GetReads() {
83 return vector_as_array(&reads_
);
86 size_t GetNumReads() const {
90 MockWrite
* GetWrites() {
91 return vector_as_array(&writes_
);
94 int GetNumWrites() const {
95 return writes_
.size();
98 SpdyTestUtil spdy_util_
;
99 SpdySessionDependencies session_deps_
;
100 scoped_refptr
<HttpNetworkSession
> session_
;
103 // Used by Add{Read,Write}() above.
104 std::vector
<MockWrite
> writes_
;
105 std::vector
<MockRead
> reads_
;
109 INSTANTIATE_TEST_CASE_P(NextProto
,
111 testing::Values(kProtoSPDY31
,
115 TEST_P(SpdyStreamTest
, SendDataAfterOpen
) {
116 GURL
url(kStreamUrl
);
119 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
121 scoped_ptr
<SpdyFrame
> req(
122 spdy_util_
.ConstructSpdyPost(
123 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
126 scoped_ptr
<SpdyFrame
> resp(
127 spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
130 scoped_ptr
<SpdyFrame
> msg(
131 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
134 scoped_ptr
<SpdyFrame
> echo(
135 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
140 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
142 MockConnect
connect_data(SYNCHRONOUS
, OK
);
143 data
.set_connect_data(connect_data
);
145 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
147 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
149 base::WeakPtr
<SpdyStream
> stream
=
150 CreateStreamSynchronously(
151 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
152 ASSERT_TRUE(stream
.get() != NULL
);
154 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
155 stream
->SetDelegate(&delegate
);
157 EXPECT_FALSE(stream
->HasUrlFromHeaders());
159 scoped_ptr
<SpdyHeaderBlock
> headers(
160 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
161 EXPECT_EQ(ERR_IO_PENDING
,
162 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
163 EXPECT_TRUE(stream
->HasUrlFromHeaders());
164 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
166 data
.RunFor(GetNumReads() + GetNumWrites());
167 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
169 EXPECT_TRUE(delegate
.send_headers_completed());
170 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
171 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
172 delegate
.TakeReceivedData());
173 EXPECT_TRUE(data
.at_write_eof());
176 TEST_P(SpdyStreamTest
, PushedStream
) {
178 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
182 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
184 MockConnect
connect_data(SYNCHRONOUS
, OK
);
185 data
.set_connect_data(connect_data
);
187 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
189 base::WeakPtr
<SpdySession
> spdy_session(CreateDefaultSpdySession());
191 // Conjure up a stream.
192 SpdyStream
stream(SPDY_PUSH_STREAM
, spdy_session
, GURL(), DEFAULT_PRIORITY
,
193 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31
),
194 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31
),
196 stream
.set_stream_id(2);
197 EXPECT_FALSE(stream
.HasUrlFromHeaders());
199 // Set required request headers.
200 SpdyHeaderBlock request_headers
;
201 spdy_util_
.AddUrlToHeaderBlock(kStreamUrl
, &request_headers
);
202 stream
.OnPushPromiseHeadersReceived(request_headers
);
204 // Send some basic response headers.
205 SpdyHeaderBlock response
;
206 response
[spdy_util_
.GetStatusKey()] = "200";
207 response
[spdy_util_
.GetVersionKey()] = "OK";
208 stream
.OnInitialResponseHeadersReceived(
209 response
, base::Time::Now(), base::TimeTicks::Now());
211 // And some more headers.
212 // TODO(baranovich): not valid for HTTP 2.
213 SpdyHeaderBlock headers
;
214 headers
["alpha"] = "beta";
215 stream
.OnAdditionalResponseHeadersReceived(headers
);
217 EXPECT_TRUE(stream
.HasUrlFromHeaders());
218 EXPECT_EQ(kStreamUrl
, stream
.GetUrlFromHeaders().spec());
220 StreamDelegateDoNothing
delegate(stream
.GetWeakPtr());
221 stream
.SetDelegate(&delegate
);
223 data
.RunFor(GetNumReads() + GetNumWrites());
225 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
226 EXPECT_EQ("beta", delegate
.GetResponseHeaderValue("alpha"));
228 EXPECT_TRUE(spdy_session
== NULL
);
231 TEST_P(SpdyStreamTest
, StreamError
) {
232 GURL
url(kStreamUrl
);
235 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
237 scoped_ptr
<SpdyFrame
> req(
238 spdy_util_
.ConstructSpdyPost(
239 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
242 scoped_ptr
<SpdyFrame
> resp(
243 spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
246 scoped_ptr
<SpdyFrame
> msg(
247 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
250 scoped_ptr
<SpdyFrame
> echo(
251 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
258 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
260 MockConnect
connect_data(SYNCHRONOUS
, OK
);
261 data
.set_connect_data(connect_data
);
263 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
265 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
267 base::WeakPtr
<SpdyStream
> stream
=
268 CreateStreamSynchronously(
269 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, log
.bound());
270 ASSERT_TRUE(stream
.get() != NULL
);
272 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
273 stream
->SetDelegate(&delegate
);
275 EXPECT_FALSE(stream
->HasUrlFromHeaders());
277 scoped_ptr
<SpdyHeaderBlock
> headers(
278 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
279 EXPECT_EQ(ERR_IO_PENDING
,
280 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
281 EXPECT_TRUE(stream
->HasUrlFromHeaders());
282 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
284 data
.RunFor(GetNumReads() + GetNumWrites());
285 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
287 const SpdyStreamId stream_id
= delegate
.stream_id();
289 EXPECT_TRUE(delegate
.send_headers_completed());
290 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
291 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
292 delegate
.TakeReceivedData());
293 EXPECT_TRUE(data
.at_write_eof());
295 // Check that the NetLog was filled reasonably.
296 net::TestNetLog::CapturedEntryList entries
;
297 log
.GetEntries(&entries
);
298 EXPECT_LT(0u, entries
.size());
300 // Check that we logged SPDY_STREAM_ERROR correctly.
301 int pos
= net::ExpectLogContainsSomewhere(
302 entries
, 0, net::NetLog::TYPE_HTTP2_STREAM_ERROR
,
303 net::NetLog::PHASE_NONE
);
306 ASSERT_TRUE(entries
[pos
].GetIntegerValue("stream_id", &stream_id2
));
307 EXPECT_EQ(static_cast<int>(stream_id
), stream_id2
);
310 // Make sure that large blocks of data are properly split up into
311 // frame-sized chunks for a request/response (i.e., an HTTP-like)
313 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenRequestResponse
) {
314 GURL
url(kStreamUrl
);
317 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
319 scoped_ptr
<SpdyFrame
> req(
320 spdy_util_
.ConstructSpdyPost(
321 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
324 std::string
chunk_data(kMaxSpdyFrameChunkSize
, 'x');
325 scoped_ptr
<SpdyFrame
> chunk(
326 spdy_util_
.ConstructSpdyBodyFrame(
327 1, chunk_data
.data(), chunk_data
.length(), false));
331 scoped_ptr
<SpdyFrame
> last_chunk(
332 spdy_util_
.ConstructSpdyBodyFrame(
333 1, chunk_data
.data(), chunk_data
.length(), true));
334 AddWrite(*last_chunk
);
336 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
341 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
343 MockConnect
connect_data(SYNCHRONOUS
, OK
);
344 data
.set_connect_data(connect_data
);
346 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
348 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
350 base::WeakPtr
<SpdyStream
> stream
=
351 CreateStreamSynchronously(
352 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
353 ASSERT_TRUE(stream
.get() != NULL
);
355 std::string
body_data(3 * kMaxSpdyFrameChunkSize
, 'x');
356 StreamDelegateWithBody
delegate(stream
, body_data
);
357 stream
->SetDelegate(&delegate
);
359 EXPECT_FALSE(stream
->HasUrlFromHeaders());
361 scoped_ptr
<SpdyHeaderBlock
> headers(
362 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
363 EXPECT_EQ(ERR_IO_PENDING
,
364 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
365 EXPECT_TRUE(stream
->HasUrlFromHeaders());
366 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
368 data
.RunFor(GetNumReads() + GetNumWrites());
369 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
371 EXPECT_TRUE(delegate
.send_headers_completed());
372 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
373 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
374 EXPECT_TRUE(data
.at_write_eof());
377 // Make sure that large blocks of data are properly split up into
378 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
380 TEST_P(SpdyStreamTest
, SendLargeDataAfterOpenBidirectional
) {
381 GURL
url(kStreamUrl
);
384 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
386 scoped_ptr
<SpdyFrame
> req(
387 spdy_util_
.ConstructSpdyPost(
388 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
391 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyPostSynReply(NULL
, 0));
394 std::string
chunk_data(kMaxSpdyFrameChunkSize
, 'x');
395 scoped_ptr
<SpdyFrame
> chunk(
396 spdy_util_
.ConstructSpdyBodyFrame(
397 1, chunk_data
.data(), chunk_data
.length(), false));
404 DeterministicSocketData
data(GetReads(), GetNumReads(), GetWrites(),
406 MockConnect
connect_data(SYNCHRONOUS
, OK
);
407 data
.set_connect_data(connect_data
);
409 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
411 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
413 base::WeakPtr
<SpdyStream
> stream
=
414 CreateStreamSynchronously(
415 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
416 ASSERT_TRUE(stream
.get() != NULL
);
418 std::string
body_data(3 * kMaxSpdyFrameChunkSize
, 'x');
419 StreamDelegateSendImmediate
delegate(stream
, body_data
);
420 stream
->SetDelegate(&delegate
);
422 EXPECT_FALSE(stream
->HasUrlFromHeaders());
424 scoped_ptr
<SpdyHeaderBlock
> headers(
425 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
426 EXPECT_EQ(ERR_IO_PENDING
,
427 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
428 EXPECT_TRUE(stream
->HasUrlFromHeaders());
429 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
431 data
.RunFor(GetNumReads() + GetNumWrites());
432 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
434 EXPECT_TRUE(delegate
.send_headers_completed());
435 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(spdy_util_
.GetStatusKey()));
436 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
437 EXPECT_TRUE(data
.at_write_eof());
440 // Receiving a header with uppercase ASCII should result in a protocol
442 TEST_P(SpdyStreamTest
, UpperCaseHeaders
) {
443 GURL
url(kStreamUrl
);
446 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
448 scoped_ptr
<SpdyFrame
> syn(
449 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
452 const char* const kExtraHeaders
[] = {"X-UpperCase", "yes"};
453 scoped_ptr
<SpdyFrame
>
454 reply(spdy_util_
.ConstructSpdyGetSynReply(kExtraHeaders
, 1, 1));
457 scoped_ptr
<SpdyFrame
> rst(
458 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR
));
463 DeterministicSocketData
data(GetReads(), GetNumReads(),
464 GetWrites(), GetNumWrites());
465 MockConnect
connect_data(SYNCHRONOUS
, OK
);
466 data
.set_connect_data(connect_data
);
468 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
470 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
472 base::WeakPtr
<SpdyStream
> stream
=
473 CreateStreamSynchronously(
474 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
475 ASSERT_TRUE(stream
.get() != NULL
);
477 StreamDelegateDoNothing
delegate(stream
);
478 stream
->SetDelegate(&delegate
);
480 EXPECT_FALSE(stream
->HasUrlFromHeaders());
482 scoped_ptr
<SpdyHeaderBlock
> headers(
483 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
484 EXPECT_EQ(ERR_IO_PENDING
,
485 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
486 EXPECT_TRUE(stream
->HasUrlFromHeaders());
487 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
491 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
494 // Receiving a header with uppercase ASCII should result in a protocol
495 // error even for a push stream.
496 TEST_P(SpdyStreamTest
, UpperCaseHeadersOnPush
) {
497 GURL
url(kStreamUrl
);
500 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
502 scoped_ptr
<SpdyFrame
> syn(
503 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
506 scoped_ptr
<SpdyFrame
>
507 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
510 const char* const extra_headers
[] = {"X-UpperCase", "yes"};
511 scoped_ptr
<SpdyFrame
>
512 push(spdy_util_
.ConstructSpdyPush(extra_headers
, 1, 2, 1, kStreamUrl
));
515 scoped_ptr
<SpdyFrame
> rst(
516 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
521 DeterministicSocketData
data(GetReads(), GetNumReads(),
522 GetWrites(), GetNumWrites());
523 MockConnect
connect_data(SYNCHRONOUS
, OK
);
524 data
.set_connect_data(connect_data
);
526 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
528 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
530 base::WeakPtr
<SpdyStream
> stream
=
531 CreateStreamSynchronously(
532 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
533 ASSERT_TRUE(stream
.get() != NULL
);
535 StreamDelegateDoNothing
delegate(stream
);
536 stream
->SetDelegate(&delegate
);
538 EXPECT_FALSE(stream
->HasUrlFromHeaders());
540 scoped_ptr
<SpdyHeaderBlock
> headers(
541 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
542 EXPECT_EQ(ERR_IO_PENDING
,
543 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
544 EXPECT_TRUE(stream
->HasUrlFromHeaders());
545 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
549 base::WeakPtr
<SpdyStream
> push_stream
;
550 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
551 EXPECT_FALSE(push_stream
);
555 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
558 // Receiving a header with uppercase ASCII in a HEADERS frame should
559 // result in a protocol error.
560 TEST_P(SpdyStreamTest
, UpperCaseHeadersInHeadersFrame
) {
561 GURL
url(kStreamUrl
);
564 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
566 scoped_ptr
<SpdyFrame
> syn(
567 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
570 scoped_ptr
<SpdyFrame
>
571 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
574 scoped_ptr
<SpdyFrame
>
575 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
578 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
579 (*late_headers
)["X-UpperCase"] = "yes";
580 scoped_ptr
<SpdyFrame
> headers_frame(
581 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
588 AddRead(*headers_frame
);
590 scoped_ptr
<SpdyFrame
> rst(
591 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
596 DeterministicSocketData
data(GetReads(), GetNumReads(),
597 GetWrites(), GetNumWrites());
598 MockConnect
connect_data(SYNCHRONOUS
, OK
);
599 data
.set_connect_data(connect_data
);
601 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
603 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
605 base::WeakPtr
<SpdyStream
> stream
=
606 CreateStreamSynchronously(
607 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
608 ASSERT_TRUE(stream
.get() != NULL
);
610 StreamDelegateDoNothing
delegate(stream
);
611 stream
->SetDelegate(&delegate
);
613 EXPECT_FALSE(stream
->HasUrlFromHeaders());
615 scoped_ptr
<SpdyHeaderBlock
> headers(
616 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
617 EXPECT_EQ(ERR_IO_PENDING
,
618 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
619 EXPECT_TRUE(stream
->HasUrlFromHeaders());
620 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
624 base::WeakPtr
<SpdyStream
> push_stream
;
625 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
626 EXPECT_TRUE(push_stream
);
630 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
631 EXPECT_FALSE(push_stream
);
635 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
638 // Receiving a duplicate header in a HEADERS frame should result in a
640 TEST_P(SpdyStreamTest
, DuplicateHeaders
) {
641 GURL
url(kStreamUrl
);
644 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
646 scoped_ptr
<SpdyFrame
> syn(
647 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
650 scoped_ptr
<SpdyFrame
>
651 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
654 scoped_ptr
<SpdyFrame
>
655 push(spdy_util_
.ConstructSpdyPush(NULL
, 0, 2, 1, kStreamUrl
));
658 scoped_ptr
<SpdyHeaderBlock
> late_headers(new SpdyHeaderBlock());
659 (*late_headers
)[spdy_util_
.GetStatusKey()] = "500 Server Error";
660 scoped_ptr
<SpdyFrame
> headers_frame(
661 spdy_util_
.ConstructSpdyControlFrame(late_headers
.Pass(),
668 AddRead(*headers_frame
);
670 scoped_ptr
<SpdyFrame
> rst(
671 spdy_util_
.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR
));
676 DeterministicSocketData
data(GetReads(), GetNumReads(),
677 GetWrites(), GetNumWrites());
678 MockConnect
connect_data(SYNCHRONOUS
, OK
);
679 data
.set_connect_data(connect_data
);
681 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
683 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
685 base::WeakPtr
<SpdyStream
> stream
=
686 CreateStreamSynchronously(
687 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
688 ASSERT_TRUE(stream
.get() != NULL
);
690 StreamDelegateDoNothing
delegate(stream
);
691 stream
->SetDelegate(&delegate
);
693 EXPECT_FALSE(stream
->HasUrlFromHeaders());
695 scoped_ptr
<SpdyHeaderBlock
> headers(
696 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
697 EXPECT_EQ(ERR_IO_PENDING
,
698 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
699 EXPECT_TRUE(stream
->HasUrlFromHeaders());
700 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
704 base::WeakPtr
<SpdyStream
> push_stream
;
705 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
706 EXPECT_TRUE(push_stream
);
710 EXPECT_EQ(OK
, session
->GetPushStream(url
, &push_stream
, BoundNetLog()));
711 EXPECT_FALSE(push_stream
);
715 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
718 // The tests below are only for SPDY/3 and above.
720 // Call IncreaseSendWindowSize on a stream with a large enough delta
721 // to overflow an int32. The SpdyStream should handle that case
723 TEST_P(SpdyStreamTest
, IncreaseSendWindowSizeOverflow
) {
725 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
727 scoped_ptr
<SpdyFrame
> req(
728 spdy_util_
.ConstructSpdyPost(
729 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
732 // Triggered by the overflowing call to IncreaseSendWindowSize
734 scoped_ptr
<SpdyFrame
> rst(
735 spdy_util_
.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR
));
742 DeterministicSocketData
data(GetReads(), GetNumReads(),
743 GetWrites(), GetNumWrites());
744 MockConnect
connect_data(SYNCHRONOUS
, OK
);
745 data
.set_connect_data(connect_data
);
747 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
749 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
750 GURL
url(kStreamUrl
);
752 base::WeakPtr
<SpdyStream
> stream
=
753 CreateStreamSynchronously(
754 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, log
.bound());
755 ASSERT_TRUE(stream
.get() != NULL
);
756 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
757 stream
->SetDelegate(&delegate
);
759 scoped_ptr
<SpdyHeaderBlock
> headers(
760 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
761 EXPECT_EQ(ERR_IO_PENDING
,
762 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
763 EXPECT_TRUE(stream
->HasUrlFromHeaders());
764 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
768 int32 old_send_window_size
= stream
->send_window_size();
769 ASSERT_GT(old_send_window_size
, 0);
770 int32 delta_window_size
= kint32max
- old_send_window_size
+ 1;
771 stream
->IncreaseSendWindowSize(delta_window_size
);
772 EXPECT_EQ(NULL
, stream
.get());
776 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR
, delegate
.WaitForClose());
779 // Functions used with
780 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
782 void StallStream(const base::WeakPtr
<SpdyStream
>& stream
) {
783 // Reduce the send window size to 0 to stall.
784 while (stream
->send_window_size() > 0) {
785 stream
->DecreaseSendWindowSize(
786 std::min(kMaxSpdyFrameChunkSize
, stream
->send_window_size()));
790 void IncreaseStreamSendWindowSize(const base::WeakPtr
<SpdyStream
>& stream
,
791 int32 delta_window_size
) {
792 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
793 stream
->IncreaseSendWindowSize(delta_window_size
);
794 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
797 void AdjustStreamSendWindowSize(const base::WeakPtr
<SpdyStream
>& stream
,
798 int32 delta_window_size
) {
799 // Make sure that negative adjustments are handled properly.
800 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
801 stream
->AdjustSendWindowSize(-delta_window_size
);
802 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
803 stream
->AdjustSendWindowSize(+delta_window_size
);
804 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
805 stream
->AdjustSendWindowSize(+delta_window_size
);
806 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
809 // Given an unstall function, runs a test to make sure that a
810 // request/response (i.e., an HTTP-like) stream resumes after a stall
812 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
813 const UnstallFunction
& unstall_function
) {
814 GURL
url(kStreamUrl
);
817 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
819 scoped_ptr
<SpdyFrame
> req(
820 spdy_util_
.ConstructSpdyPost(
821 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
824 scoped_ptr
<SpdyFrame
> body(
825 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, true));
828 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
833 DeterministicSocketData
data(GetReads(), GetNumReads(),
834 GetWrites(), GetNumWrites());
835 MockConnect
connect_data(SYNCHRONOUS
, OK
);
836 data
.set_connect_data(connect_data
);
838 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
840 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
842 base::WeakPtr
<SpdyStream
> stream
=
843 CreateStreamSynchronously(
844 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
845 ASSERT_TRUE(stream
.get() != NULL
);
847 StreamDelegateWithBody
delegate(stream
, kPostBodyStringPiece
);
848 stream
->SetDelegate(&delegate
);
850 EXPECT_FALSE(stream
->HasUrlFromHeaders());
851 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
853 scoped_ptr
<SpdyHeaderBlock
> headers(
854 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
855 EXPECT_EQ(ERR_IO_PENDING
,
856 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
857 EXPECT_TRUE(stream
->HasUrlFromHeaders());
858 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
864 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
866 unstall_function
.Run(stream
, kPostBodyLength
);
868 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
872 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
874 EXPECT_TRUE(delegate
.send_headers_completed());
875 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
876 EXPECT_EQ(std::string(), delegate
.TakeReceivedData());
877 EXPECT_TRUE(data
.at_write_eof());
880 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseRequestResponse
) {
881 RunResumeAfterUnstallRequestResponseTest(
882 base::Bind(&IncreaseStreamSendWindowSize
));
885 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustRequestResponse
) {
886 RunResumeAfterUnstallRequestResponseTest(
887 base::Bind(&AdjustStreamSendWindowSize
));
890 // Given an unstall function, runs a test to make sure that a
891 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
893 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
894 const UnstallFunction
& unstall_function
) {
895 GURL
url(kStreamUrl
);
898 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
900 scoped_ptr
<SpdyFrame
> req(
901 spdy_util_
.ConstructSpdyPost(
902 kStreamUrl
, 1, kPostBodyLength
, LOWEST
, NULL
, 0));
905 scoped_ptr
<SpdyFrame
> resp(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
908 scoped_ptr
<SpdyFrame
> msg(
909 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
912 scoped_ptr
<SpdyFrame
> echo(
913 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
918 DeterministicSocketData
data(GetReads(), GetNumReads(),
919 GetWrites(), GetNumWrites());
920 MockConnect
connect_data(SYNCHRONOUS
, OK
);
921 data
.set_connect_data(connect_data
);
923 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
925 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
927 base::WeakPtr
<SpdyStream
> stream
=
928 CreateStreamSynchronously(
929 SPDY_BIDIRECTIONAL_STREAM
, session
, url
, LOWEST
, BoundNetLog());
930 ASSERT_TRUE(stream
.get() != NULL
);
932 StreamDelegateSendImmediate
delegate(stream
, kPostBodyStringPiece
);
933 stream
->SetDelegate(&delegate
);
935 EXPECT_FALSE(stream
->HasUrlFromHeaders());
937 scoped_ptr
<SpdyHeaderBlock
> headers(
938 spdy_util_
.ConstructPostHeaderBlock(kStreamUrl
, kPostBodyLength
));
939 EXPECT_EQ(ERR_IO_PENDING
,
940 stream
->SendRequestHeaders(headers
.Pass(), MORE_DATA_TO_SEND
));
941 EXPECT_TRUE(stream
->HasUrlFromHeaders());
942 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
946 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
952 EXPECT_TRUE(stream
->send_stalled_by_flow_control());
954 unstall_function
.Run(stream
, kPostBodyLength
);
956 EXPECT_FALSE(stream
->send_stalled_by_flow_control());
960 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());
962 EXPECT_TRUE(delegate
.send_headers_completed());
963 EXPECT_EQ("200", delegate
.GetResponseHeaderValue(":status"));
964 EXPECT_EQ(std::string(kPostBody
, kPostBodyLength
),
965 delegate
.TakeReceivedData());
966 EXPECT_TRUE(data
.at_write_eof());
969 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeIncreaseBidirectional
) {
970 RunResumeAfterUnstallBidirectionalTest(
971 base::Bind(&IncreaseStreamSendWindowSize
));
974 TEST_P(SpdyStreamTest
, ResumeAfterSendWindowSizeAdjustBidirectional
) {
975 RunResumeAfterUnstallBidirectionalTest(
976 base::Bind(&AdjustStreamSendWindowSize
));
979 // Test calculation of amount of bytes received from network.
980 TEST_P(SpdyStreamTest
, ReceivedBytes
) {
981 GURL
url(kStreamUrl
);
984 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_
);
986 scoped_ptr
<SpdyFrame
> syn(
987 spdy_util_
.ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
, true));
990 scoped_ptr
<SpdyFrame
>
991 reply(spdy_util_
.ConstructSpdyGetSynReply(NULL
, 0, 1));
994 scoped_ptr
<SpdyFrame
> msg(
995 spdy_util_
.ConstructSpdyBodyFrame(1, kPostBody
, kPostBodyLength
, false));
1000 DeterministicSocketData
data(GetReads(), GetNumReads(),
1001 GetWrites(), GetNumWrites());
1002 MockConnect
connect_data(SYNCHRONOUS
, OK
);
1003 data
.set_connect_data(connect_data
);
1005 session_deps_
.deterministic_socket_factory
->AddSocketDataProvider(&data
);
1007 base::WeakPtr
<SpdySession
> session(CreateDefaultSpdySession());
1009 base::WeakPtr
<SpdyStream
> stream
=
1010 CreateStreamSynchronously(
1011 SPDY_REQUEST_RESPONSE_STREAM
, session
, url
, LOWEST
, BoundNetLog());
1012 ASSERT_TRUE(stream
.get() != NULL
);
1014 StreamDelegateDoNothing
delegate(stream
);
1015 stream
->SetDelegate(&delegate
);
1017 EXPECT_FALSE(stream
->HasUrlFromHeaders());
1019 scoped_ptr
<SpdyHeaderBlock
> headers(
1020 spdy_util_
.ConstructGetHeaderBlock(kStreamUrl
));
1021 EXPECT_EQ(ERR_IO_PENDING
,
1022 stream
->SendRequestHeaders(headers
.Pass(), NO_MORE_DATA_TO_SEND
));
1023 EXPECT_TRUE(stream
->HasUrlFromHeaders());
1024 EXPECT_EQ(kStreamUrl
, stream
->GetUrlFromHeaders().spec());
1026 int64 reply_frame_len
= reply
->size();
1027 int64 data_header_len
= spdy_util_
.CreateFramer(false)
1028 ->GetDataFrameMinimumSize();
1029 int64 data_frame_len
= data_header_len
+ kPostBodyLength
;
1030 int64 response_len
= reply_frame_len
+ data_frame_len
;
1032 EXPECT_EQ(0, stream
->raw_received_bytes());
1033 data
.RunFor(1); // SYN
1034 EXPECT_EQ(0, stream
->raw_received_bytes());
1035 data
.RunFor(1); // REPLY
1036 EXPECT_EQ(reply_frame_len
, stream
->raw_received_bytes());
1037 data
.RunFor(1); // DATA
1038 EXPECT_EQ(response_len
, stream
->raw_received_bytes());
1039 data
.RunFor(1); // FIN
1041 EXPECT_EQ(ERR_CONNECTION_CLOSED
, delegate
.WaitForClose());