Fix more MSVC warnings, courgette/ edition.
[chromium-blink-merge.git] / net / spdy / spdy_stream_unittest.cc
blobf754be662c7c6f71a04ca6a32f114b1f162e6024
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.
5 #include <cstddef>
6 #include <string>
7 #include <vector>
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
29 namespace net {
31 namespace test {
33 namespace {
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> {
42 protected:
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)>
46 UnstallFunction;
48 SpdyStreamTest()
49 : spdy_util_(GetParam()),
50 session_deps_(GetParam()),
51 offset_(0) {}
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 virtual void TearDown() {
61 base::MessageLoop::current()->RunUntilIdle();
64 void RunResumeAfterUnstallRequestResponseTest(
65 const UnstallFunction& unstall_function);
67 void RunResumeAfterUnstallBidirectionalTest(
68 const UnstallFunction& unstall_function);
70 // Add{Read,Write}() populates lists that are eventually passed to a
71 // SocketData class. |frame| must live for the whole test.
73 void AddRead(const SpdyFrame& frame) {
74 reads_.push_back(CreateMockRead(frame, offset_++));
77 void AddWrite(const SpdyFrame& frame) {
78 writes_.push_back(CreateMockWrite(frame, offset_++));
81 void AddReadEOF() {
82 reads_.push_back(MockRead(ASYNC, 0, offset_++));
85 MockRead* GetReads() {
86 return vector_as_array(&reads_);
89 size_t GetNumReads() const {
90 return reads_.size();
93 MockWrite* GetWrites() {
94 return vector_as_array(&writes_);
97 int GetNumWrites() const {
98 return writes_.size();
101 SpdyTestUtil spdy_util_;
102 SpdySessionDependencies session_deps_;
103 scoped_refptr<HttpNetworkSession> session_;
105 private:
106 // Used by Add{Read,Write}() above.
107 std::vector<MockWrite> writes_;
108 std::vector<MockRead> reads_;
109 int offset_;
112 INSTANTIATE_TEST_CASE_P(
113 NextProto,
114 SpdyStreamTest,
115 testing::Values(kProtoDeprecatedSPDY2,
116 kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
118 TEST_P(SpdyStreamTest, SendDataAfterOpen) {
119 GURL url(kStreamUrl);
121 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
123 scoped_ptr<SpdyFrame> req(
124 spdy_util_.ConstructSpdyPost(
125 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
126 AddWrite(*req);
128 scoped_ptr<SpdyFrame> resp(
129 spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
130 AddRead(*resp);
132 scoped_ptr<SpdyFrame> msg(
133 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
134 AddWrite(*msg);
136 scoped_ptr<SpdyFrame> echo(
137 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
138 AddRead(*echo);
140 AddReadEOF();
142 OrderedSocketData data(GetReads(), GetNumReads(),
143 GetWrites(), GetNumWrites());
144 MockConnect connect_data(SYNCHRONOUS, OK);
145 data.set_connect_data(connect_data);
147 session_deps_.socket_factory->AddSocketDataProvider(&data);
149 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
151 base::WeakPtr<SpdyStream> stream =
152 CreateStreamSynchronously(
153 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
154 ASSERT_TRUE(stream.get() != NULL);
156 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
157 stream->SetDelegate(&delegate);
159 EXPECT_FALSE(stream->HasUrlFromHeaders());
161 scoped_ptr<SpdyHeaderBlock> headers(
162 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
163 EXPECT_EQ(ERR_IO_PENDING,
164 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
165 EXPECT_TRUE(stream->HasUrlFromHeaders());
166 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
168 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
170 EXPECT_TRUE(delegate.send_headers_completed());
171 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
172 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
173 delegate.TakeReceivedData());
174 EXPECT_TRUE(data.at_write_eof());
177 TEST_P(SpdyStreamTest, PushedStream) {
178 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
180 AddReadEOF();
182 OrderedSocketData data(GetReads(), GetNumReads(),
183 GetWrites(), GetNumWrites());
184 MockConnect connect_data(SYNCHRONOUS, OK);
185 data.set_connect_data(connect_data);
187 session_deps_.socket_factory->AddSocketDataProvider(&data);
189 base::WeakPtr<SpdySession> spdy_session(CreateDefaultSpdySession());
191 // Conjure up a stream.
192 SpdyStream stream(SPDY_PUSH_STREAM,
193 spdy_session,
194 GURL(),
195 DEFAULT_PRIORITY,
196 kSpdyStreamInitialWindowSize,
197 kSpdyStreamInitialWindowSize,
198 BoundNetLog());
199 stream.set_stream_id(2);
200 EXPECT_FALSE(stream.HasUrlFromHeaders());
202 // Set required request headers.
203 SpdyHeaderBlock request_headers;
204 spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &request_headers);
205 stream.OnPushPromiseHeadersReceived(request_headers);
207 // Send some basic response headers.
208 SpdyHeaderBlock response;
209 response[spdy_util_.GetStatusKey()] = "200";
210 response[spdy_util_.GetVersionKey()] = "OK";
211 stream.OnInitialResponseHeadersReceived(
212 response, base::Time::Now(), base::TimeTicks::Now());
214 // And some more headers.
215 // TODO(baranovich): not valid for HTTP 2.
216 SpdyHeaderBlock headers;
217 headers["alpha"] = "beta";
218 stream.OnAdditionalResponseHeadersReceived(headers);
220 EXPECT_TRUE(stream.HasUrlFromHeaders());
221 EXPECT_EQ(kStreamUrl, stream.GetUrlFromHeaders().spec());
223 StreamDelegateDoNothing delegate(stream.GetWeakPtr());
224 stream.SetDelegate(&delegate);
226 base::MessageLoop::current()->RunUntilIdle();
228 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
229 EXPECT_EQ("beta", delegate.GetResponseHeaderValue("alpha"));
231 EXPECT_TRUE(spdy_session == NULL);
234 TEST_P(SpdyStreamTest, StreamError) {
235 GURL url(kStreamUrl);
237 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
239 scoped_ptr<SpdyFrame> req(
240 spdy_util_.ConstructSpdyPost(
241 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
242 AddWrite(*req);
244 scoped_ptr<SpdyFrame> resp(
245 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
246 AddRead(*resp);
248 scoped_ptr<SpdyFrame> msg(
249 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
250 AddWrite(*msg);
252 scoped_ptr<SpdyFrame> echo(
253 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
254 AddRead(*echo);
256 AddReadEOF();
258 CapturingBoundNetLog log;
260 OrderedSocketData data(GetReads(), GetNumReads(),
261 GetWrites(), GetNumWrites());
262 MockConnect connect_data(SYNCHRONOUS, OK);
263 data.set_connect_data(connect_data);
265 session_deps_.socket_factory->AddSocketDataProvider(&data);
267 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
269 base::WeakPtr<SpdyStream> stream =
270 CreateStreamSynchronously(
271 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
272 ASSERT_TRUE(stream.get() != NULL);
274 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
275 stream->SetDelegate(&delegate);
277 EXPECT_FALSE(stream->HasUrlFromHeaders());
279 scoped_ptr<SpdyHeaderBlock> headers(
280 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
281 EXPECT_EQ(ERR_IO_PENDING,
282 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
283 EXPECT_TRUE(stream->HasUrlFromHeaders());
284 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
286 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
288 const SpdyStreamId stream_id = delegate.stream_id();
290 EXPECT_TRUE(delegate.send_headers_completed());
291 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
292 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
293 delegate.TakeReceivedData());
294 EXPECT_TRUE(data.at_write_eof());
296 // Check that the NetLog was filled reasonably.
297 net::CapturingNetLog::CapturedEntryList entries;
298 log.GetEntries(&entries);
299 EXPECT_LT(0u, entries.size());
301 // Check that we logged SPDY_STREAM_ERROR correctly.
302 int pos = net::ExpectLogContainsSomewhere(
303 entries, 0,
304 net::NetLog::TYPE_SPDY_STREAM_ERROR,
305 net::NetLog::PHASE_NONE);
307 int stream_id2;
308 ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2));
309 EXPECT_EQ(static_cast<int>(stream_id), stream_id2);
312 // Make sure that large blocks of data are properly split up into
313 // frame-sized chunks for a request/response (i.e., an HTTP-like)
314 // stream.
315 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
316 GURL url(kStreamUrl);
318 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
320 scoped_ptr<SpdyFrame> req(
321 spdy_util_.ConstructSpdyPost(
322 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
323 AddWrite(*req);
325 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
326 scoped_ptr<SpdyFrame> chunk(
327 spdy_util_.ConstructSpdyBodyFrame(
328 1, chunk_data.data(), chunk_data.length(), false));
329 AddWrite(*chunk);
330 AddWrite(*chunk);
332 scoped_ptr<SpdyFrame> last_chunk(
333 spdy_util_.ConstructSpdyBodyFrame(
334 1, chunk_data.data(), chunk_data.length(), true));
335 AddWrite(*last_chunk);
337 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
338 AddRead(*resp);
340 AddReadEOF();
342 OrderedSocketData data(GetReads(), GetNumReads(),
343 GetWrites(), GetNumWrites());
344 MockConnect connect_data(SYNCHRONOUS, OK);
345 data.set_connect_data(connect_data);
347 session_deps_.socket_factory->AddSocketDataProvider(&data);
349 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
351 base::WeakPtr<SpdyStream> stream =
352 CreateStreamSynchronously(
353 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
354 ASSERT_TRUE(stream.get() != NULL);
356 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
357 StreamDelegateWithBody delegate(stream, body_data);
358 stream->SetDelegate(&delegate);
360 EXPECT_FALSE(stream->HasUrlFromHeaders());
362 scoped_ptr<SpdyHeaderBlock> headers(
363 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
364 EXPECT_EQ(ERR_IO_PENDING,
365 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
366 EXPECT_TRUE(stream->HasUrlFromHeaders());
367 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
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)
379 // stream.
380 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
381 GURL url(kStreamUrl);
383 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
385 scoped_ptr<SpdyFrame> req(
386 spdy_util_.ConstructSpdyPost(
387 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
388 AddWrite(*req);
390 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
391 AddRead(*resp);
393 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
394 scoped_ptr<SpdyFrame> chunk(
395 spdy_util_.ConstructSpdyBodyFrame(
396 1, chunk_data.data(), chunk_data.length(), false));
397 AddWrite(*chunk);
398 AddWrite(*chunk);
399 AddWrite(*chunk);
401 AddReadEOF();
403 OrderedSocketData data(GetReads(), GetNumReads(),
404 GetWrites(), GetNumWrites());
405 MockConnect connect_data(SYNCHRONOUS, OK);
406 data.set_connect_data(connect_data);
408 session_deps_.socket_factory->AddSocketDataProvider(&data);
410 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
412 base::WeakPtr<SpdyStream> stream =
413 CreateStreamSynchronously(
414 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
415 ASSERT_TRUE(stream.get() != NULL);
417 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
418 StreamDelegateSendImmediate delegate(stream, body_data);
419 stream->SetDelegate(&delegate);
421 EXPECT_FALSE(stream->HasUrlFromHeaders());
423 scoped_ptr<SpdyHeaderBlock> headers(
424 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
425 EXPECT_EQ(ERR_IO_PENDING,
426 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
427 EXPECT_TRUE(stream->HasUrlFromHeaders());
428 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
430 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
432 EXPECT_TRUE(delegate.send_headers_completed());
433 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
434 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
435 EXPECT_TRUE(data.at_write_eof());
438 // Receiving a header with uppercase ASCII should result in a protocol
439 // error.
440 TEST_P(SpdyStreamTest, UpperCaseHeaders) {
441 GURL url(kStreamUrl);
443 session_ =
444 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
446 scoped_ptr<SpdyFrame> syn(
447 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
448 AddWrite(*syn);
450 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
451 scoped_ptr<SpdyFrame>
452 reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
453 AddRead(*reply);
455 scoped_ptr<SpdyFrame> rst(
456 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
457 AddWrite(*rst);
459 AddReadEOF();
461 DeterministicSocketData data(GetReads(), GetNumReads(),
462 GetWrites(), GetNumWrites());
463 MockConnect connect_data(SYNCHRONOUS, OK);
464 data.set_connect_data(connect_data);
466 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
468 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
470 base::WeakPtr<SpdyStream> stream =
471 CreateStreamSynchronously(
472 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
473 ASSERT_TRUE(stream.get() != NULL);
475 StreamDelegateDoNothing delegate(stream);
476 stream->SetDelegate(&delegate);
478 EXPECT_FALSE(stream->HasUrlFromHeaders());
480 scoped_ptr<SpdyHeaderBlock> headers(
481 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
482 EXPECT_EQ(ERR_IO_PENDING,
483 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
484 EXPECT_TRUE(stream->HasUrlFromHeaders());
485 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
487 data.RunFor(4);
489 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
492 // Receiving a header with uppercase ASCII should result in a protocol
493 // error even for a push stream.
494 TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
495 GURL url(kStreamUrl);
497 session_ =
498 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
500 scoped_ptr<SpdyFrame> syn(
501 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
502 AddWrite(*syn);
504 scoped_ptr<SpdyFrame>
505 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
506 AddRead(*reply);
508 const char* const extra_headers[] = {"X-UpperCase", "yes"};
509 scoped_ptr<SpdyFrame>
510 push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
511 AddRead(*push);
513 scoped_ptr<SpdyFrame> rst(
514 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
515 AddWrite(*rst);
517 AddReadEOF();
519 DeterministicSocketData data(GetReads(), GetNumReads(),
520 GetWrites(), GetNumWrites());
521 MockConnect connect_data(SYNCHRONOUS, OK);
522 data.set_connect_data(connect_data);
524 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
526 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
528 base::WeakPtr<SpdyStream> stream =
529 CreateStreamSynchronously(
530 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
531 ASSERT_TRUE(stream.get() != NULL);
533 StreamDelegateDoNothing delegate(stream);
534 stream->SetDelegate(&delegate);
536 EXPECT_FALSE(stream->HasUrlFromHeaders());
538 scoped_ptr<SpdyHeaderBlock> headers(
539 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
540 EXPECT_EQ(ERR_IO_PENDING,
541 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
542 EXPECT_TRUE(stream->HasUrlFromHeaders());
543 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
545 data.RunFor(4);
547 base::WeakPtr<SpdyStream> push_stream;
548 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
549 EXPECT_FALSE(push_stream);
551 data.RunFor(1);
553 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
556 // Receiving a header with uppercase ASCII in a HEADERS frame should
557 // result in a protocol error.
558 TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
559 GURL url(kStreamUrl);
561 session_ =
562 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
564 scoped_ptr<SpdyFrame> syn(
565 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
566 AddWrite(*syn);
568 scoped_ptr<SpdyFrame>
569 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
570 AddRead(*reply);
572 scoped_ptr<SpdyFrame>
573 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
574 AddRead(*push);
576 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
577 (*late_headers)["X-UpperCase"] = "yes";
578 scoped_ptr<SpdyFrame> headers_frame(
579 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
580 false,
582 LOWEST,
583 HEADERS,
584 CONTROL_FLAG_NONE,
585 0));
586 AddRead(*headers_frame);
588 scoped_ptr<SpdyFrame> rst(
589 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
590 AddWrite(*rst);
592 AddReadEOF();
594 DeterministicSocketData data(GetReads(), GetNumReads(),
595 GetWrites(), GetNumWrites());
596 MockConnect connect_data(SYNCHRONOUS, OK);
597 data.set_connect_data(connect_data);
599 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
601 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
603 base::WeakPtr<SpdyStream> stream =
604 CreateStreamSynchronously(
605 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
606 ASSERT_TRUE(stream.get() != NULL);
608 StreamDelegateDoNothing delegate(stream);
609 stream->SetDelegate(&delegate);
611 EXPECT_FALSE(stream->HasUrlFromHeaders());
613 scoped_ptr<SpdyHeaderBlock> headers(
614 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
615 EXPECT_EQ(ERR_IO_PENDING,
616 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
617 EXPECT_TRUE(stream->HasUrlFromHeaders());
618 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
620 data.RunFor(3);
622 base::WeakPtr<SpdyStream> push_stream;
623 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
624 EXPECT_TRUE(push_stream);
626 data.RunFor(1);
628 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
629 EXPECT_FALSE(push_stream);
631 data.RunFor(2);
633 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
636 // Receiving a duplicate header in a HEADERS frame should result in a
637 // protocol error.
638 TEST_P(SpdyStreamTest, DuplicateHeaders) {
639 GURL url(kStreamUrl);
641 session_ =
642 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
644 scoped_ptr<SpdyFrame> syn(
645 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
646 AddWrite(*syn);
648 scoped_ptr<SpdyFrame>
649 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
650 AddRead(*reply);
652 scoped_ptr<SpdyFrame>
653 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
654 AddRead(*push);
656 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
657 (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error";
658 scoped_ptr<SpdyFrame> headers_frame(
659 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
660 false,
662 LOWEST,
663 HEADERS,
664 CONTROL_FLAG_NONE,
665 0));
666 AddRead(*headers_frame);
668 scoped_ptr<SpdyFrame> rst(
669 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
670 AddWrite(*rst);
672 AddReadEOF();
674 DeterministicSocketData data(GetReads(), GetNumReads(),
675 GetWrites(), GetNumWrites());
676 MockConnect connect_data(SYNCHRONOUS, OK);
677 data.set_connect_data(connect_data);
679 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
681 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
683 base::WeakPtr<SpdyStream> stream =
684 CreateStreamSynchronously(
685 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
686 ASSERT_TRUE(stream.get() != NULL);
688 StreamDelegateDoNothing delegate(stream);
689 stream->SetDelegate(&delegate);
691 EXPECT_FALSE(stream->HasUrlFromHeaders());
693 scoped_ptr<SpdyHeaderBlock> headers(
694 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
695 EXPECT_EQ(ERR_IO_PENDING,
696 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
697 EXPECT_TRUE(stream->HasUrlFromHeaders());
698 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
700 data.RunFor(3);
702 base::WeakPtr<SpdyStream> push_stream;
703 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
704 EXPECT_TRUE(push_stream);
706 data.RunFor(1);
708 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
709 EXPECT_FALSE(push_stream);
711 data.RunFor(2);
713 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
716 // The tests below are only for SPDY/3 and above.
718 // Call IncreaseSendWindowSize on a stream with a large enough delta
719 // to overflow an int32. The SpdyStream should handle that case
720 // gracefully.
721 TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
722 if (spdy_util_.protocol() < kProtoSPDY3)
723 return;
725 session_ =
726 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
728 scoped_ptr<SpdyFrame> req(
729 spdy_util_.ConstructSpdyPost(
730 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
731 AddWrite(*req);
733 // Triggered by the overflowing call to IncreaseSendWindowSize
734 // below.
735 scoped_ptr<SpdyFrame> rst(
736 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
737 AddWrite(*rst);
739 AddReadEOF();
741 CapturingBoundNetLog log;
743 DeterministicSocketData data(GetReads(), GetNumReads(),
744 GetWrites(), GetNumWrites());
745 MockConnect connect_data(SYNCHRONOUS, OK);
746 data.set_connect_data(connect_data);
748 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
750 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
751 GURL url(kStreamUrl);
753 base::WeakPtr<SpdyStream> stream =
754 CreateStreamSynchronously(
755 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
756 ASSERT_TRUE(stream.get() != NULL);
757 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
758 stream->SetDelegate(&delegate);
760 scoped_ptr<SpdyHeaderBlock> headers(
761 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
762 EXPECT_EQ(ERR_IO_PENDING,
763 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
764 EXPECT_TRUE(stream->HasUrlFromHeaders());
765 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
767 data.RunFor(1);
769 int32 old_send_window_size = stream->send_window_size();
770 ASSERT_GT(old_send_window_size, 0);
771 int32 delta_window_size = kint32max - old_send_window_size + 1;
772 stream->IncreaseSendWindowSize(delta_window_size);
773 EXPECT_EQ(NULL, stream.get());
775 data.RunFor(2);
777 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
780 // Functions used with
781 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
783 void StallStream(const base::WeakPtr<SpdyStream>& stream) {
784 // Reduce the send window size to 0 to stall.
785 while (stream->send_window_size() > 0) {
786 stream->DecreaseSendWindowSize(
787 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
791 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
792 int32 delta_window_size) {
793 EXPECT_TRUE(stream->send_stalled_by_flow_control());
794 stream->IncreaseSendWindowSize(delta_window_size);
795 EXPECT_FALSE(stream->send_stalled_by_flow_control());
798 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
799 int32 delta_window_size) {
800 // Make sure that negative adjustments are handled properly.
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_TRUE(stream->send_stalled_by_flow_control());
806 stream->AdjustSendWindowSize(+delta_window_size);
807 EXPECT_FALSE(stream->send_stalled_by_flow_control());
810 // Given an unstall function, runs a test to make sure that a
811 // request/response (i.e., an HTTP-like) stream resumes after a stall
812 // and unstall.
813 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
814 const UnstallFunction& unstall_function) {
815 GURL url(kStreamUrl);
817 session_ =
818 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
820 scoped_ptr<SpdyFrame> req(
821 spdy_util_.ConstructSpdyPost(
822 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
823 AddWrite(*req);
825 scoped_ptr<SpdyFrame> body(
826 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
827 AddWrite(*body);
829 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
830 AddRead(*resp);
832 AddReadEOF();
834 DeterministicSocketData data(GetReads(), GetNumReads(),
835 GetWrites(), GetNumWrites());
836 MockConnect connect_data(SYNCHRONOUS, OK);
837 data.set_connect_data(connect_data);
839 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
841 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
843 base::WeakPtr<SpdyStream> stream =
844 CreateStreamSynchronously(
845 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
846 ASSERT_TRUE(stream.get() != NULL);
848 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
849 stream->SetDelegate(&delegate);
851 EXPECT_FALSE(stream->HasUrlFromHeaders());
852 EXPECT_FALSE(stream->send_stalled_by_flow_control());
854 scoped_ptr<SpdyHeaderBlock> headers(
855 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
856 EXPECT_EQ(ERR_IO_PENDING,
857 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
858 EXPECT_TRUE(stream->HasUrlFromHeaders());
859 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
861 StallStream(stream);
863 data.RunFor(1);
865 EXPECT_TRUE(stream->send_stalled_by_flow_control());
867 unstall_function.Run(stream, kPostBodyLength);
869 EXPECT_FALSE(stream->send_stalled_by_flow_control());
871 data.RunFor(3);
873 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
875 EXPECT_TRUE(delegate.send_headers_completed());
876 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
877 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
878 EXPECT_TRUE(data.at_write_eof());
881 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
882 if (spdy_util_.protocol() < kProtoSPDY3)
883 return;
885 RunResumeAfterUnstallRequestResponseTest(
886 base::Bind(&IncreaseStreamSendWindowSize));
889 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
890 if (spdy_util_.protocol() < kProtoSPDY3)
891 return;
893 RunResumeAfterUnstallRequestResponseTest(
894 base::Bind(&AdjustStreamSendWindowSize));
897 // Given an unstall function, runs a test to make sure that a
898 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
899 // and unstall.
900 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
901 const UnstallFunction& unstall_function) {
902 GURL url(kStreamUrl);
904 session_ =
905 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
907 scoped_ptr<SpdyFrame> req(
908 spdy_util_.ConstructSpdyPost(
909 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
910 AddWrite(*req);
912 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
913 AddRead(*resp);
915 scoped_ptr<SpdyFrame> msg(
916 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
917 AddWrite(*msg);
919 scoped_ptr<SpdyFrame> echo(
920 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
921 AddRead(*echo);
923 AddReadEOF();
925 DeterministicSocketData data(GetReads(), GetNumReads(),
926 GetWrites(), GetNumWrites());
927 MockConnect connect_data(SYNCHRONOUS, OK);
928 data.set_connect_data(connect_data);
930 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
932 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
934 base::WeakPtr<SpdyStream> stream =
935 CreateStreamSynchronously(
936 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
937 ASSERT_TRUE(stream.get() != NULL);
939 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
940 stream->SetDelegate(&delegate);
942 EXPECT_FALSE(stream->HasUrlFromHeaders());
944 scoped_ptr<SpdyHeaderBlock> headers(
945 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
946 EXPECT_EQ(ERR_IO_PENDING,
947 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
948 EXPECT_TRUE(stream->HasUrlFromHeaders());
949 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
951 data.RunFor(1);
953 EXPECT_FALSE(stream->send_stalled_by_flow_control());
955 StallStream(stream);
957 data.RunFor(1);
959 EXPECT_TRUE(stream->send_stalled_by_flow_control());
961 unstall_function.Run(stream, kPostBodyLength);
963 EXPECT_FALSE(stream->send_stalled_by_flow_control());
965 data.RunFor(3);
967 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
969 EXPECT_TRUE(delegate.send_headers_completed());
970 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
971 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
972 delegate.TakeReceivedData());
973 EXPECT_TRUE(data.at_write_eof());
976 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
977 if (spdy_util_.protocol() < kProtoSPDY3)
978 return;
980 RunResumeAfterUnstallBidirectionalTest(
981 base::Bind(&IncreaseStreamSendWindowSize));
984 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
985 if (spdy_util_.protocol() < kProtoSPDY3)
986 return;
988 RunResumeAfterUnstallBidirectionalTest(
989 base::Bind(&AdjustStreamSendWindowSize));
992 // Test calculation of amount of bytes received from network.
993 TEST_P(SpdyStreamTest, ReceivedBytes) {
994 GURL url(kStreamUrl);
996 session_ =
997 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
999 scoped_ptr<SpdyFrame> syn(
1000 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1001 AddWrite(*syn);
1003 scoped_ptr<SpdyFrame>
1004 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1005 AddRead(*reply);
1007 scoped_ptr<SpdyFrame> msg(
1008 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
1009 AddRead(*msg);
1011 AddReadEOF();
1013 DeterministicSocketData data(GetReads(), GetNumReads(),
1014 GetWrites(), GetNumWrites());
1015 MockConnect connect_data(SYNCHRONOUS, OK);
1016 data.set_connect_data(connect_data);
1018 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1020 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
1022 base::WeakPtr<SpdyStream> stream =
1023 CreateStreamSynchronously(
1024 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
1025 ASSERT_TRUE(stream.get() != NULL);
1027 StreamDelegateDoNothing delegate(stream);
1028 stream->SetDelegate(&delegate);
1030 EXPECT_FALSE(stream->HasUrlFromHeaders());
1032 scoped_ptr<SpdyHeaderBlock> headers(
1033 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
1034 EXPECT_EQ(ERR_IO_PENDING,
1035 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
1036 EXPECT_TRUE(stream->HasUrlFromHeaders());
1037 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
1039 int64 reply_frame_len = reply->size();
1040 int64 data_header_len = spdy_util_.CreateFramer(false)
1041 ->GetDataFrameMinimumSize();
1042 int64 data_frame_len = data_header_len + kPostBodyLength;
1043 int64 response_len = reply_frame_len + data_frame_len;
1045 EXPECT_EQ(0, stream->raw_received_bytes());
1046 data.RunFor(1); // SYN
1047 EXPECT_EQ(0, stream->raw_received_bytes());
1048 data.RunFor(1); // REPLY
1049 EXPECT_EQ(reply_frame_len, stream->raw_received_bytes());
1050 data.RunFor(1); // DATA
1051 EXPECT_EQ(response_len, stream->raw_received_bytes());
1052 data.RunFor(1); // FIN
1054 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1057 } // namespace
1059 } // namespace test
1061 } // namespace net