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(kProtoDeprecatedSPDY2,
114 kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
116 TEST_P(SpdyStreamTest, SendDataAfterOpen) {
117 GURL url(kStreamUrl);
119 session_ = SpdySessionDependencies::SpdyCreateSession(&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 OrderedSocketData data(GetReads(), GetNumReads(),
141 GetWrites(), GetNumWrites());
142 MockConnect connect_data(SYNCHRONOUS, OK);
143 data.set_connect_data(connect_data);
145 session_deps_.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 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
168 EXPECT_TRUE(delegate.send_headers_completed());
169 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
170 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
171 delegate.TakeReceivedData());
172 EXPECT_TRUE(data.at_write_eof());
175 TEST_P(SpdyStreamTest, PushedStream) {
176 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
180 OrderedSocketData data(GetReads(), GetNumReads(),
181 GetWrites(), GetNumWrites());
182 MockConnect connect_data(SYNCHRONOUS, OK);
183 data.set_connect_data(connect_data);
185 session_deps_.socket_factory->AddSocketDataProvider(&data);
187 base::WeakPtr<SpdySession> spdy_session(CreateDefaultSpdySession());
189 // Conjure up a stream.
190 SpdyStream stream(SPDY_PUSH_STREAM,
194 kSpdyStreamInitialWindowSize,
195 kSpdyStreamInitialWindowSize,
197 stream.set_stream_id(2);
198 EXPECT_FALSE(stream.HasUrlFromHeaders());
200 // Set required request headers.
201 SpdyHeaderBlock request_headers;
202 spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &request_headers);
203 stream.OnPushPromiseHeadersReceived(request_headers);
205 // Send some basic response headers.
206 SpdyHeaderBlock response;
207 response[spdy_util_.GetStatusKey()] = "200";
208 response[spdy_util_.GetVersionKey()] = "OK";
209 stream.OnInitialResponseHeadersReceived(
210 response, base::Time::Now(), base::TimeTicks::Now());
212 // And some more headers.
213 // TODO(baranovich): not valid for HTTP 2.
214 SpdyHeaderBlock headers;
215 headers["alpha"] = "beta";
216 stream.OnAdditionalResponseHeadersReceived(headers);
218 EXPECT_TRUE(stream.HasUrlFromHeaders());
219 EXPECT_EQ(kStreamUrl, stream.GetUrlFromHeaders().spec());
221 StreamDelegateDoNothing delegate(stream.GetWeakPtr());
222 stream.SetDelegate(&delegate);
224 base::MessageLoop::current()->RunUntilIdle();
226 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
227 EXPECT_EQ("beta", delegate.GetResponseHeaderValue("alpha"));
229 EXPECT_TRUE(spdy_session == NULL);
232 TEST_P(SpdyStreamTest, StreamError) {
233 GURL url(kStreamUrl);
235 session_ = SpdySessionDependencies::SpdyCreateSession(&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));
256 CapturingBoundNetLog log;
258 OrderedSocketData data(GetReads(), GetNumReads(),
259 GetWrites(), GetNumWrites());
260 MockConnect connect_data(SYNCHRONOUS, OK);
261 data.set_connect_data(connect_data);
263 session_deps_.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 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
286 const SpdyStreamId stream_id = delegate.stream_id();
288 EXPECT_TRUE(delegate.send_headers_completed());
289 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
290 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
291 delegate.TakeReceivedData());
292 EXPECT_TRUE(data.at_write_eof());
294 // Check that the NetLog was filled reasonably.
295 net::CapturingNetLog::CapturedEntryList entries;
296 log.GetEntries(&entries);
297 EXPECT_LT(0u, entries.size());
299 // Check that we logged SPDY_STREAM_ERROR correctly.
300 int pos = net::ExpectLogContainsSomewhere(
302 net::NetLog::TYPE_SPDY_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);
316 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
318 scoped_ptr<SpdyFrame> req(
319 spdy_util_.ConstructSpdyPost(
320 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
323 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
324 scoped_ptr<SpdyFrame> chunk(
325 spdy_util_.ConstructSpdyBodyFrame(
326 1, chunk_data.data(), chunk_data.length(), false));
330 scoped_ptr<SpdyFrame> last_chunk(
331 spdy_util_.ConstructSpdyBodyFrame(
332 1, chunk_data.data(), chunk_data.length(), true));
333 AddWrite(*last_chunk);
335 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
340 OrderedSocketData data(GetReads(), GetNumReads(),
341 GetWrites(), GetNumWrites());
342 MockConnect connect_data(SYNCHRONOUS, OK);
343 data.set_connect_data(connect_data);
345 session_deps_.socket_factory->AddSocketDataProvider(&data);
347 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
349 base::WeakPtr<SpdyStream> stream =
350 CreateStreamSynchronously(
351 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
352 ASSERT_TRUE(stream.get() != NULL);
354 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
355 StreamDelegateWithBody delegate(stream, body_data);
356 stream->SetDelegate(&delegate);
358 EXPECT_FALSE(stream->HasUrlFromHeaders());
360 scoped_ptr<SpdyHeaderBlock> headers(
361 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
362 EXPECT_EQ(ERR_IO_PENDING,
363 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
364 EXPECT_TRUE(stream->HasUrlFromHeaders());
365 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
367 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
369 EXPECT_TRUE(delegate.send_headers_completed());
370 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
371 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
372 EXPECT_TRUE(data.at_write_eof());
375 // Make sure that large blocks of data are properly split up into
376 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
378 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
379 GURL url(kStreamUrl);
381 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
383 scoped_ptr<SpdyFrame> req(
384 spdy_util_.ConstructSpdyPost(
385 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
388 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
391 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
392 scoped_ptr<SpdyFrame> chunk(
393 spdy_util_.ConstructSpdyBodyFrame(
394 1, chunk_data.data(), chunk_data.length(), false));
401 OrderedSocketData data(GetReads(), GetNumReads(),
402 GetWrites(), GetNumWrites());
403 MockConnect connect_data(SYNCHRONOUS, OK);
404 data.set_connect_data(connect_data);
406 session_deps_.socket_factory->AddSocketDataProvider(&data);
408 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
410 base::WeakPtr<SpdyStream> stream =
411 CreateStreamSynchronously(
412 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
413 ASSERT_TRUE(stream.get() != NULL);
415 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
416 StreamDelegateSendImmediate delegate(stream, body_data);
417 stream->SetDelegate(&delegate);
419 EXPECT_FALSE(stream->HasUrlFromHeaders());
421 scoped_ptr<SpdyHeaderBlock> headers(
422 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
423 EXPECT_EQ(ERR_IO_PENDING,
424 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
425 EXPECT_TRUE(stream->HasUrlFromHeaders());
426 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
428 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
430 EXPECT_TRUE(delegate.send_headers_completed());
431 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
432 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
433 EXPECT_TRUE(data.at_write_eof());
436 // Receiving a header with uppercase ASCII should result in a protocol
438 TEST_P(SpdyStreamTest, UpperCaseHeaders) {
439 GURL url(kStreamUrl);
442 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
444 scoped_ptr<SpdyFrame> syn(
445 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
448 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
449 scoped_ptr<SpdyFrame>
450 reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
453 scoped_ptr<SpdyFrame> rst(
454 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
459 DeterministicSocketData data(GetReads(), GetNumReads(),
460 GetWrites(), GetNumWrites());
461 MockConnect connect_data(SYNCHRONOUS, OK);
462 data.set_connect_data(connect_data);
464 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
466 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
468 base::WeakPtr<SpdyStream> stream =
469 CreateStreamSynchronously(
470 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
471 ASSERT_TRUE(stream.get() != NULL);
473 StreamDelegateDoNothing delegate(stream);
474 stream->SetDelegate(&delegate);
476 EXPECT_FALSE(stream->HasUrlFromHeaders());
478 scoped_ptr<SpdyHeaderBlock> headers(
479 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
480 EXPECT_EQ(ERR_IO_PENDING,
481 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
482 EXPECT_TRUE(stream->HasUrlFromHeaders());
483 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
487 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
490 // Receiving a header with uppercase ASCII should result in a protocol
491 // error even for a push stream.
492 TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
493 GURL url(kStreamUrl);
496 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
498 scoped_ptr<SpdyFrame> syn(
499 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
502 scoped_ptr<SpdyFrame>
503 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
506 const char* const extra_headers[] = {"X-UpperCase", "yes"};
507 scoped_ptr<SpdyFrame>
508 push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
511 scoped_ptr<SpdyFrame> rst(
512 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
517 DeterministicSocketData data(GetReads(), GetNumReads(),
518 GetWrites(), GetNumWrites());
519 MockConnect connect_data(SYNCHRONOUS, OK);
520 data.set_connect_data(connect_data);
522 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
524 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
526 base::WeakPtr<SpdyStream> stream =
527 CreateStreamSynchronously(
528 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
529 ASSERT_TRUE(stream.get() != NULL);
531 StreamDelegateDoNothing delegate(stream);
532 stream->SetDelegate(&delegate);
534 EXPECT_FALSE(stream->HasUrlFromHeaders());
536 scoped_ptr<SpdyHeaderBlock> headers(
537 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
538 EXPECT_EQ(ERR_IO_PENDING,
539 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
540 EXPECT_TRUE(stream->HasUrlFromHeaders());
541 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
545 base::WeakPtr<SpdyStream> push_stream;
546 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
547 EXPECT_FALSE(push_stream);
551 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
554 // Receiving a header with uppercase ASCII in a HEADERS frame should
555 // result in a protocol error.
556 TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
557 GURL url(kStreamUrl);
560 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
562 scoped_ptr<SpdyFrame> syn(
563 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
566 scoped_ptr<SpdyFrame>
567 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
570 scoped_ptr<SpdyFrame>
571 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
574 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
575 (*late_headers)["X-UpperCase"] = "yes";
576 scoped_ptr<SpdyFrame> headers_frame(
577 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
584 AddRead(*headers_frame);
586 scoped_ptr<SpdyFrame> rst(
587 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
592 DeterministicSocketData data(GetReads(), GetNumReads(),
593 GetWrites(), GetNumWrites());
594 MockConnect connect_data(SYNCHRONOUS, OK);
595 data.set_connect_data(connect_data);
597 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
599 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
601 base::WeakPtr<SpdyStream> stream =
602 CreateStreamSynchronously(
603 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
604 ASSERT_TRUE(stream.get() != NULL);
606 StreamDelegateDoNothing delegate(stream);
607 stream->SetDelegate(&delegate);
609 EXPECT_FALSE(stream->HasUrlFromHeaders());
611 scoped_ptr<SpdyHeaderBlock> headers(
612 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
613 EXPECT_EQ(ERR_IO_PENDING,
614 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
615 EXPECT_TRUE(stream->HasUrlFromHeaders());
616 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
620 base::WeakPtr<SpdyStream> push_stream;
621 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
622 EXPECT_TRUE(push_stream);
626 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
627 EXPECT_FALSE(push_stream);
631 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
634 // Receiving a duplicate header in a HEADERS frame should result in a
636 TEST_P(SpdyStreamTest, DuplicateHeaders) {
637 GURL url(kStreamUrl);
640 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
642 scoped_ptr<SpdyFrame> syn(
643 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
646 scoped_ptr<SpdyFrame>
647 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
650 scoped_ptr<SpdyFrame>
651 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
654 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
655 (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error";
656 scoped_ptr<SpdyFrame> headers_frame(
657 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
664 AddRead(*headers_frame);
666 scoped_ptr<SpdyFrame> rst(
667 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
672 DeterministicSocketData data(GetReads(), GetNumReads(),
673 GetWrites(), GetNumWrites());
674 MockConnect connect_data(SYNCHRONOUS, OK);
675 data.set_connect_data(connect_data);
677 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
679 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
681 base::WeakPtr<SpdyStream> stream =
682 CreateStreamSynchronously(
683 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
684 ASSERT_TRUE(stream.get() != NULL);
686 StreamDelegateDoNothing delegate(stream);
687 stream->SetDelegate(&delegate);
689 EXPECT_FALSE(stream->HasUrlFromHeaders());
691 scoped_ptr<SpdyHeaderBlock> headers(
692 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
693 EXPECT_EQ(ERR_IO_PENDING,
694 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
695 EXPECT_TRUE(stream->HasUrlFromHeaders());
696 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
700 base::WeakPtr<SpdyStream> push_stream;
701 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
702 EXPECT_TRUE(push_stream);
706 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
707 EXPECT_FALSE(push_stream);
711 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
714 // The tests below are only for SPDY/3 and above.
716 // Call IncreaseSendWindowSize on a stream with a large enough delta
717 // to overflow an int32. The SpdyStream should handle that case
719 TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
720 if (spdy_util_.protocol() < kProtoSPDY3)
724 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
726 scoped_ptr<SpdyFrame> req(
727 spdy_util_.ConstructSpdyPost(
728 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
731 // Triggered by the overflowing call to IncreaseSendWindowSize
733 scoped_ptr<SpdyFrame> rst(
734 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
739 CapturingBoundNetLog log;
741 DeterministicSocketData data(GetReads(), GetNumReads(),
742 GetWrites(), GetNumWrites());
743 MockConnect connect_data(SYNCHRONOUS, OK);
744 data.set_connect_data(connect_data);
746 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
748 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
749 GURL url(kStreamUrl);
751 base::WeakPtr<SpdyStream> stream =
752 CreateStreamSynchronously(
753 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
754 ASSERT_TRUE(stream.get() != NULL);
755 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
756 stream->SetDelegate(&delegate);
758 scoped_ptr<SpdyHeaderBlock> headers(
759 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
760 EXPECT_EQ(ERR_IO_PENDING,
761 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
762 EXPECT_TRUE(stream->HasUrlFromHeaders());
763 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
767 int32 old_send_window_size = stream->send_window_size();
768 ASSERT_GT(old_send_window_size, 0);
769 int32 delta_window_size = kint32max - old_send_window_size + 1;
770 stream->IncreaseSendWindowSize(delta_window_size);
771 EXPECT_EQ(NULL, stream.get());
775 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
778 // Functions used with
779 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
781 void StallStream(const base::WeakPtr<SpdyStream>& stream) {
782 // Reduce the send window size to 0 to stall.
783 while (stream->send_window_size() > 0) {
784 stream->DecreaseSendWindowSize(
785 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
789 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
790 int32 delta_window_size) {
791 EXPECT_TRUE(stream->send_stalled_by_flow_control());
792 stream->IncreaseSendWindowSize(delta_window_size);
793 EXPECT_FALSE(stream->send_stalled_by_flow_control());
796 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
797 int32 delta_window_size) {
798 // Make sure that negative adjustments are handled properly.
799 EXPECT_TRUE(stream->send_stalled_by_flow_control());
800 stream->AdjustSendWindowSize(-delta_window_size);
801 EXPECT_TRUE(stream->send_stalled_by_flow_control());
802 stream->AdjustSendWindowSize(+delta_window_size);
803 EXPECT_TRUE(stream->send_stalled_by_flow_control());
804 stream->AdjustSendWindowSize(+delta_window_size);
805 EXPECT_FALSE(stream->send_stalled_by_flow_control());
808 // Given an unstall function, runs a test to make sure that a
809 // request/response (i.e., an HTTP-like) stream resumes after a stall
811 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
812 const UnstallFunction& unstall_function) {
813 GURL url(kStreamUrl);
816 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
818 scoped_ptr<SpdyFrame> req(
819 spdy_util_.ConstructSpdyPost(
820 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
823 scoped_ptr<SpdyFrame> body(
824 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
827 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
832 DeterministicSocketData data(GetReads(), GetNumReads(),
833 GetWrites(), GetNumWrites());
834 MockConnect connect_data(SYNCHRONOUS, OK);
835 data.set_connect_data(connect_data);
837 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
839 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
841 base::WeakPtr<SpdyStream> stream =
842 CreateStreamSynchronously(
843 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
844 ASSERT_TRUE(stream.get() != NULL);
846 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
847 stream->SetDelegate(&delegate);
849 EXPECT_FALSE(stream->HasUrlFromHeaders());
850 EXPECT_FALSE(stream->send_stalled_by_flow_control());
852 scoped_ptr<SpdyHeaderBlock> headers(
853 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
854 EXPECT_EQ(ERR_IO_PENDING,
855 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
856 EXPECT_TRUE(stream->HasUrlFromHeaders());
857 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
863 EXPECT_TRUE(stream->send_stalled_by_flow_control());
865 unstall_function.Run(stream, kPostBodyLength);
867 EXPECT_FALSE(stream->send_stalled_by_flow_control());
871 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
873 EXPECT_TRUE(delegate.send_headers_completed());
874 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
875 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
876 EXPECT_TRUE(data.at_write_eof());
879 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
880 if (spdy_util_.protocol() < kProtoSPDY3)
883 RunResumeAfterUnstallRequestResponseTest(
884 base::Bind(&IncreaseStreamSendWindowSize));
887 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
888 if (spdy_util_.protocol() < kProtoSPDY3)
891 RunResumeAfterUnstallRequestResponseTest(
892 base::Bind(&AdjustStreamSendWindowSize));
895 // Given an unstall function, runs a test to make sure that a
896 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
898 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
899 const UnstallFunction& unstall_function) {
900 GURL url(kStreamUrl);
903 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
905 scoped_ptr<SpdyFrame> req(
906 spdy_util_.ConstructSpdyPost(
907 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
910 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
913 scoped_ptr<SpdyFrame> msg(
914 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
917 scoped_ptr<SpdyFrame> echo(
918 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
923 DeterministicSocketData data(GetReads(), GetNumReads(),
924 GetWrites(), GetNumWrites());
925 MockConnect connect_data(SYNCHRONOUS, OK);
926 data.set_connect_data(connect_data);
928 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
930 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
932 base::WeakPtr<SpdyStream> stream =
933 CreateStreamSynchronously(
934 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
935 ASSERT_TRUE(stream.get() != NULL);
937 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
938 stream->SetDelegate(&delegate);
940 EXPECT_FALSE(stream->HasUrlFromHeaders());
942 scoped_ptr<SpdyHeaderBlock> headers(
943 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
944 EXPECT_EQ(ERR_IO_PENDING,
945 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
946 EXPECT_TRUE(stream->HasUrlFromHeaders());
947 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
951 EXPECT_FALSE(stream->send_stalled_by_flow_control());
957 EXPECT_TRUE(stream->send_stalled_by_flow_control());
959 unstall_function.Run(stream, kPostBodyLength);
961 EXPECT_FALSE(stream->send_stalled_by_flow_control());
965 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
967 EXPECT_TRUE(delegate.send_headers_completed());
968 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
969 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
970 delegate.TakeReceivedData());
971 EXPECT_TRUE(data.at_write_eof());
974 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
975 if (spdy_util_.protocol() < kProtoSPDY3)
978 RunResumeAfterUnstallBidirectionalTest(
979 base::Bind(&IncreaseStreamSendWindowSize));
982 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
983 if (spdy_util_.protocol() < kProtoSPDY3)
986 RunResumeAfterUnstallBidirectionalTest(
987 base::Bind(&AdjustStreamSendWindowSize));
990 // Test calculation of amount of bytes received from network.
991 TEST_P(SpdyStreamTest, ReceivedBytes) {
992 GURL url(kStreamUrl);
995 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
997 scoped_ptr<SpdyFrame> syn(
998 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1001 scoped_ptr<SpdyFrame>
1002 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1005 scoped_ptr<SpdyFrame> msg(
1006 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
1011 DeterministicSocketData data(GetReads(), GetNumReads(),
1012 GetWrites(), GetNumWrites());
1013 MockConnect connect_data(SYNCHRONOUS, OK);
1014 data.set_connect_data(connect_data);
1016 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1018 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
1020 base::WeakPtr<SpdyStream> stream =
1021 CreateStreamSynchronously(
1022 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
1023 ASSERT_TRUE(stream.get() != NULL);
1025 StreamDelegateDoNothing delegate(stream);
1026 stream->SetDelegate(&delegate);
1028 EXPECT_FALSE(stream->HasUrlFromHeaders());
1030 scoped_ptr<SpdyHeaderBlock> headers(
1031 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
1032 EXPECT_EQ(ERR_IO_PENDING,
1033 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
1034 EXPECT_TRUE(stream->HasUrlFromHeaders());
1035 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
1037 int64 reply_frame_len = reply->size();
1038 int64 data_header_len = spdy_util_.CreateFramer(false)
1039 ->GetDataFrameMinimumSize();
1040 int64 data_frame_len = data_header_len + kPostBodyLength;
1041 int64 response_len = reply_frame_len + data_frame_len;
1043 EXPECT_EQ(0, stream->raw_received_bytes());
1044 data.RunFor(1); // SYN
1045 EXPECT_EQ(0, stream->raw_received_bytes());
1046 data.RunFor(1); // REPLY
1047 EXPECT_EQ(reply_frame_len, stream->raw_received_bytes());
1048 data.RunFor(1); // DATA
1049 EXPECT_EQ(response_len, stream->raw_received_bytes());
1050 data.RunFor(1); // FIN
1052 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());