Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / spdy / spdy_stream_unittest.cc
blobb87634f5c2ce26ad87b585c253e6824b8302e8f0
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/request_priority.h"
15 #include "net/log/test_net_log.h"
16 #include "net/log/test_net_log_entry.h"
17 #include "net/log/test_net_log_util.h"
18 #include "net/socket/next_proto.h"
19 #include "net/socket/socket_test_util.h"
20 #include "net/spdy/buffered_spdy_framer.h"
21 #include "net/spdy/spdy_http_utils.h"
22 #include "net/spdy/spdy_protocol.h"
23 #include "net/spdy/spdy_session.h"
24 #include "net/spdy/spdy_stream.h"
25 #include "net/spdy/spdy_stream_test_util.h"
26 #include "net/spdy/spdy_test_util_common.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
31 namespace net {
33 namespace test {
35 namespace {
37 const char kStreamUrl[] = "http://www.example.org/";
38 const char kPostBody[] = "\0hello!\xff";
39 const size_t kPostBodyLength = arraysize(kPostBody);
40 const base::StringPiece kPostBodyStringPiece(kPostBody, kPostBodyLength);
42 class SpdyStreamTest : public ::testing::Test,
43 public ::testing::WithParamInterface<NextProto> {
44 protected:
45 // A function that takes a SpdyStream and the number of bytes which
46 // will unstall the next frame completely.
47 typedef base::Callback<void(const base::WeakPtr<SpdyStream>&, int32)>
48 UnstallFunction;
50 SpdyStreamTest()
51 : spdy_util_(GetParam()),
52 session_deps_(GetParam()),
53 offset_(0) {}
55 base::WeakPtr<SpdySession> CreateDefaultSpdySession() {
56 SpdySessionKey key(HostPortPair("www.example.org", 80),
57 ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
58 return CreateInsecureSpdySession(session_, key, BoundNetLog());
61 void TearDown() override { base::MessageLoop::current()->RunUntilIdle(); }
63 void RunResumeAfterUnstallRequestResponseTest(
64 const UnstallFunction& unstall_function);
66 void RunResumeAfterUnstallBidirectionalTest(
67 const UnstallFunction& unstall_function);
69 // Add{Read,Write}() populates lists that are eventually passed to a
70 // SocketData class. |frame| must live for the whole test.
72 void AddRead(const SpdyFrame& frame) {
73 reads_.push_back(CreateMockRead(frame, offset_++));
76 void AddWrite(const SpdyFrame& frame) {
77 writes_.push_back(CreateMockWrite(frame, offset_++));
80 void AddReadEOF() {
81 reads_.push_back(MockRead(ASYNC, 0, offset_++));
84 MockRead* GetReads() {
85 return vector_as_array(&reads_);
88 size_t GetNumReads() const {
89 return reads_.size();
92 MockWrite* GetWrites() {
93 return vector_as_array(&writes_);
96 int GetNumWrites() const {
97 return writes_.size();
100 SpdyTestUtil spdy_util_;
101 SpdySessionDependencies session_deps_;
102 scoped_refptr<HttpNetworkSession> session_;
104 private:
105 // Used by Add{Read,Write}() above.
106 std::vector<MockWrite> writes_;
107 std::vector<MockRead> reads_;
108 int offset_;
111 INSTANTIATE_TEST_CASE_P(NextProto,
112 SpdyStreamTest,
113 testing::Values(kProtoSPDY31,
114 kProtoHTTP2_14,
115 kProtoHTTP2));
117 TEST_P(SpdyStreamTest, SendDataAfterOpen) {
118 GURL url(kStreamUrl);
120 session_ =
121 SpdySessionDependencies::SpdyCreateSessionDeterministic(&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 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
143 GetNumWrites());
144 MockConnect connect_data(SYNCHRONOUS, OK);
145 data.set_connect_data(connect_data);
147 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
149 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
151 base::WeakPtr<SpdyStream> stream =
152 CreateStreamSynchronously(
153 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
154 ASSERT_TRUE(stream.get() != NULL);
156 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
157 stream->SetDelegate(&delegate);
159 EXPECT_FALSE(stream->HasUrlFromHeaders());
161 scoped_ptr<SpdyHeaderBlock> headers(
162 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
163 EXPECT_EQ(ERR_IO_PENDING,
164 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
165 EXPECT_TRUE(stream->HasUrlFromHeaders());
166 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
168 data.RunFor(GetNumReads() + GetNumWrites());
169 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
171 EXPECT_TRUE(delegate.send_headers_completed());
172 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
173 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
174 delegate.TakeReceivedData());
175 EXPECT_TRUE(data.AllWriteDataConsumed());
178 TEST_P(SpdyStreamTest, PushedStream) {
179 session_ =
180 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
182 AddReadEOF();
184 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
185 GetNumWrites());
186 MockConnect connect_data(SYNCHRONOUS, OK);
187 data.set_connect_data(connect_data);
189 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
191 base::WeakPtr<SpdySession> spdy_session(CreateDefaultSpdySession());
193 // Conjure up a stream.
194 SpdyStream stream(SPDY_PUSH_STREAM, spdy_session, GURL(), DEFAULT_PRIORITY,
195 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31),
196 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31),
197 BoundNetLog());
198 stream.set_stream_id(2);
199 EXPECT_FALSE(stream.HasUrlFromHeaders());
201 // Set required request headers.
202 SpdyHeaderBlock request_headers;
203 spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &request_headers);
204 stream.OnPushPromiseHeadersReceived(request_headers);
206 // Send some basic response headers.
207 SpdyHeaderBlock response;
208 response[spdy_util_.GetStatusKey()] = "200";
209 response[spdy_util_.GetVersionKey()] = "OK";
210 stream.OnInitialResponseHeadersReceived(
211 response, base::Time::Now(), base::TimeTicks::Now());
213 // And some more headers.
214 // TODO(baranovich): not valid for HTTP 2.
215 SpdyHeaderBlock headers;
216 headers["alpha"] = "beta";
217 stream.OnAdditionalResponseHeadersReceived(headers);
219 EXPECT_TRUE(stream.HasUrlFromHeaders());
220 EXPECT_EQ(kStreamUrl, stream.GetUrlFromHeaders().spec());
222 StreamDelegateDoNothing delegate(stream.GetWeakPtr());
223 stream.SetDelegate(&delegate);
225 data.RunFor(GetNumReads() + GetNumWrites());
227 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
228 EXPECT_EQ("beta", delegate.GetResponseHeaderValue("alpha"));
230 EXPECT_TRUE(spdy_session == NULL);
233 TEST_P(SpdyStreamTest, StreamError) {
234 GURL url(kStreamUrl);
236 session_ =
237 SpdySessionDependencies::SpdyCreateSessionDeterministic(&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 BoundTestNetLog log;
260 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
261 GetNumWrites());
262 MockConnect connect_data(SYNCHRONOUS, OK);
263 data.set_connect_data(connect_data);
265 session_deps_.deterministic_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 data.RunFor(GetNumReads() + GetNumWrites());
287 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
289 const SpdyStreamId stream_id = delegate.stream_id();
291 EXPECT_TRUE(delegate.send_headers_completed());
292 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
293 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
294 delegate.TakeReceivedData());
295 EXPECT_TRUE(data.AllWriteDataConsumed());
297 // Check that the NetLog was filled reasonably.
298 TestNetLogEntry::List entries;
299 log.GetEntries(&entries);
300 EXPECT_LT(0u, entries.size());
302 // Check that we logged SPDY_STREAM_ERROR correctly.
303 int pos = ExpectLogContainsSomewhere(
304 entries, 0, NetLog::TYPE_HTTP2_STREAM_ERROR, NetLog::PHASE_NONE);
306 int stream_id2;
307 ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2));
308 EXPECT_EQ(static_cast<int>(stream_id), stream_id2);
311 // Make sure that large blocks of data are properly split up into
312 // frame-sized chunks for a request/response (i.e., an HTTP-like)
313 // stream.
314 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
315 GURL url(kStreamUrl);
317 session_ =
318 SpdySessionDependencies::SpdyCreateSessionDeterministic(&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 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
343 GetNumWrites());
344 MockConnect connect_data(SYNCHRONOUS, OK);
345 data.set_connect_data(connect_data);
347 session_deps_.deterministic_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 data.RunFor(GetNumReads() + GetNumWrites());
370 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
372 EXPECT_TRUE(delegate.send_headers_completed());
373 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
374 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
375 EXPECT_TRUE(data.AllWriteDataConsumed());
378 // Make sure that large blocks of data are properly split up into
379 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
380 // stream.
381 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
382 GURL url(kStreamUrl);
384 session_ =
385 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
387 scoped_ptr<SpdyFrame> req(
388 spdy_util_.ConstructSpdyPost(
389 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
390 AddWrite(*req);
392 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
393 AddRead(*resp);
395 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
396 scoped_ptr<SpdyFrame> chunk(
397 spdy_util_.ConstructSpdyBodyFrame(
398 1, chunk_data.data(), chunk_data.length(), false));
399 AddWrite(*chunk);
400 AddWrite(*chunk);
401 AddWrite(*chunk);
403 AddReadEOF();
405 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
406 GetNumWrites());
407 MockConnect connect_data(SYNCHRONOUS, OK);
408 data.set_connect_data(connect_data);
410 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
412 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
414 base::WeakPtr<SpdyStream> stream =
415 CreateStreamSynchronously(
416 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
417 ASSERT_TRUE(stream.get() != NULL);
419 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
420 StreamDelegateSendImmediate delegate(stream, body_data);
421 stream->SetDelegate(&delegate);
423 EXPECT_FALSE(stream->HasUrlFromHeaders());
425 scoped_ptr<SpdyHeaderBlock> headers(
426 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
427 EXPECT_EQ(ERR_IO_PENDING,
428 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
429 EXPECT_TRUE(stream->HasUrlFromHeaders());
430 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
432 data.RunFor(GetNumReads() + GetNumWrites());
433 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
435 EXPECT_TRUE(delegate.send_headers_completed());
436 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
437 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
438 EXPECT_TRUE(data.AllWriteDataConsumed());
441 // Receiving a header with uppercase ASCII should result in a protocol
442 // error.
443 TEST_P(SpdyStreamTest, UpperCaseHeaders) {
444 GURL url(kStreamUrl);
446 session_ =
447 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
449 scoped_ptr<SpdyFrame> syn(
450 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
451 AddWrite(*syn);
453 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
454 scoped_ptr<SpdyFrame>
455 reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
456 AddRead(*reply);
458 scoped_ptr<SpdyFrame> rst(
459 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
460 AddWrite(*rst);
462 AddReadEOF();
464 DeterministicSocketData data(GetReads(), GetNumReads(),
465 GetWrites(), GetNumWrites());
466 MockConnect connect_data(SYNCHRONOUS, OK);
467 data.set_connect_data(connect_data);
469 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
471 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
473 base::WeakPtr<SpdyStream> stream =
474 CreateStreamSynchronously(
475 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
476 ASSERT_TRUE(stream.get() != NULL);
478 StreamDelegateDoNothing delegate(stream);
479 stream->SetDelegate(&delegate);
481 EXPECT_FALSE(stream->HasUrlFromHeaders());
483 scoped_ptr<SpdyHeaderBlock> headers(
484 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
485 EXPECT_EQ(ERR_IO_PENDING,
486 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
487 EXPECT_TRUE(stream->HasUrlFromHeaders());
488 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
490 data.RunFor(4);
492 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
495 // Receiving a header with uppercase ASCII should result in a protocol
496 // error even for a push stream.
497 TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
498 GURL url(kStreamUrl);
500 session_ =
501 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
503 scoped_ptr<SpdyFrame> syn(
504 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
505 AddWrite(*syn);
507 scoped_ptr<SpdyFrame>
508 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
509 AddRead(*reply);
511 const char* const extra_headers[] = {"X-UpperCase", "yes"};
512 scoped_ptr<SpdyFrame>
513 push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
514 AddRead(*push);
516 scoped_ptr<SpdyFrame> rst(
517 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
518 AddWrite(*rst);
520 AddReadEOF();
522 DeterministicSocketData data(GetReads(), GetNumReads(),
523 GetWrites(), GetNumWrites());
524 MockConnect connect_data(SYNCHRONOUS, OK);
525 data.set_connect_data(connect_data);
527 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
529 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
531 base::WeakPtr<SpdyStream> stream =
532 CreateStreamSynchronously(
533 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
534 ASSERT_TRUE(stream.get() != NULL);
536 StreamDelegateDoNothing delegate(stream);
537 stream->SetDelegate(&delegate);
539 EXPECT_FALSE(stream->HasUrlFromHeaders());
541 scoped_ptr<SpdyHeaderBlock> headers(
542 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
543 EXPECT_EQ(ERR_IO_PENDING,
544 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
545 EXPECT_TRUE(stream->HasUrlFromHeaders());
546 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
548 data.RunFor(4);
550 base::WeakPtr<SpdyStream> push_stream;
551 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
552 EXPECT_FALSE(push_stream);
554 data.RunFor(1);
556 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
559 // Receiving a header with uppercase ASCII in a HEADERS frame should
560 // result in a protocol error.
561 TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
562 GURL url(kStreamUrl);
564 session_ =
565 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
567 scoped_ptr<SpdyFrame> syn(
568 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
569 AddWrite(*syn);
571 scoped_ptr<SpdyFrame>
572 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
573 AddRead(*reply);
575 scoped_ptr<SpdyFrame>
576 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
577 AddRead(*push);
579 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
580 (*late_headers)["X-UpperCase"] = "yes";
581 scoped_ptr<SpdyFrame> headers_frame(
582 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
583 false,
585 LOWEST,
586 HEADERS,
587 CONTROL_FLAG_NONE,
588 0));
589 AddRead(*headers_frame);
591 scoped_ptr<SpdyFrame> rst(
592 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
593 AddWrite(*rst);
595 AddReadEOF();
597 DeterministicSocketData data(GetReads(), GetNumReads(),
598 GetWrites(), GetNumWrites());
599 MockConnect connect_data(SYNCHRONOUS, OK);
600 data.set_connect_data(connect_data);
602 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
604 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
606 base::WeakPtr<SpdyStream> stream =
607 CreateStreamSynchronously(
608 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
609 ASSERT_TRUE(stream.get() != NULL);
611 StreamDelegateDoNothing delegate(stream);
612 stream->SetDelegate(&delegate);
614 EXPECT_FALSE(stream->HasUrlFromHeaders());
616 scoped_ptr<SpdyHeaderBlock> headers(
617 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
618 EXPECT_EQ(ERR_IO_PENDING,
619 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
620 EXPECT_TRUE(stream->HasUrlFromHeaders());
621 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
623 data.RunFor(3);
625 base::WeakPtr<SpdyStream> push_stream;
626 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
627 EXPECT_TRUE(push_stream);
629 data.RunFor(1);
631 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
632 EXPECT_FALSE(push_stream);
634 data.RunFor(2);
636 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
639 // Receiving a duplicate header in a HEADERS frame should result in a
640 // protocol error.
641 TEST_P(SpdyStreamTest, DuplicateHeaders) {
642 GURL url(kStreamUrl);
644 session_ =
645 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
647 scoped_ptr<SpdyFrame> syn(
648 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
649 AddWrite(*syn);
651 scoped_ptr<SpdyFrame>
652 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
653 AddRead(*reply);
655 scoped_ptr<SpdyFrame>
656 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
657 AddRead(*push);
659 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
660 (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error";
661 scoped_ptr<SpdyFrame> headers_frame(
662 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
663 false,
665 LOWEST,
666 HEADERS,
667 CONTROL_FLAG_NONE,
668 0));
669 AddRead(*headers_frame);
671 scoped_ptr<SpdyFrame> rst(
672 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
673 AddWrite(*rst);
675 AddReadEOF();
677 DeterministicSocketData data(GetReads(), GetNumReads(),
678 GetWrites(), GetNumWrites());
679 MockConnect connect_data(SYNCHRONOUS, OK);
680 data.set_connect_data(connect_data);
682 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
684 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
686 base::WeakPtr<SpdyStream> stream =
687 CreateStreamSynchronously(
688 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
689 ASSERT_TRUE(stream.get() != NULL);
691 StreamDelegateDoNothing delegate(stream);
692 stream->SetDelegate(&delegate);
694 EXPECT_FALSE(stream->HasUrlFromHeaders());
696 scoped_ptr<SpdyHeaderBlock> headers(
697 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
698 EXPECT_EQ(ERR_IO_PENDING,
699 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
700 EXPECT_TRUE(stream->HasUrlFromHeaders());
701 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
703 data.RunFor(3);
705 base::WeakPtr<SpdyStream> push_stream;
706 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
707 EXPECT_TRUE(push_stream);
709 data.RunFor(1);
711 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
712 EXPECT_FALSE(push_stream);
714 data.RunFor(2);
716 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
719 // The tests below are only for SPDY/3 and above.
721 // Call IncreaseSendWindowSize on a stream with a large enough delta
722 // to overflow an int32. The SpdyStream should handle that case
723 // gracefully.
724 TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
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 BoundTestNetLog 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.AllWriteDataConsumed());
881 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
882 RunResumeAfterUnstallRequestResponseTest(
883 base::Bind(&IncreaseStreamSendWindowSize));
886 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
887 RunResumeAfterUnstallRequestResponseTest(
888 base::Bind(&AdjustStreamSendWindowSize));
891 // Given an unstall function, runs a test to make sure that a
892 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
893 // and unstall.
894 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
895 const UnstallFunction& unstall_function) {
896 GURL url(kStreamUrl);
898 session_ =
899 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
901 scoped_ptr<SpdyFrame> req(
902 spdy_util_.ConstructSpdyPost(
903 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
904 AddWrite(*req);
906 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
907 AddRead(*resp);
909 scoped_ptr<SpdyFrame> msg(
910 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
911 AddWrite(*msg);
913 scoped_ptr<SpdyFrame> echo(
914 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
915 AddRead(*echo);
917 AddReadEOF();
919 DeterministicSocketData data(GetReads(), GetNumReads(),
920 GetWrites(), GetNumWrites());
921 MockConnect connect_data(SYNCHRONOUS, OK);
922 data.set_connect_data(connect_data);
924 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
926 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
928 base::WeakPtr<SpdyStream> stream =
929 CreateStreamSynchronously(
930 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
931 ASSERT_TRUE(stream.get() != NULL);
933 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
934 stream->SetDelegate(&delegate);
936 EXPECT_FALSE(stream->HasUrlFromHeaders());
938 scoped_ptr<SpdyHeaderBlock> headers(
939 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
940 EXPECT_EQ(ERR_IO_PENDING,
941 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
942 EXPECT_TRUE(stream->HasUrlFromHeaders());
943 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
945 data.RunFor(1);
947 EXPECT_FALSE(stream->send_stalled_by_flow_control());
949 StallStream(stream);
951 data.RunFor(1);
953 EXPECT_TRUE(stream->send_stalled_by_flow_control());
955 unstall_function.Run(stream, kPostBodyLength);
957 EXPECT_FALSE(stream->send_stalled_by_flow_control());
959 data.RunFor(3);
961 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
963 EXPECT_TRUE(delegate.send_headers_completed());
964 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
965 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
966 delegate.TakeReceivedData());
967 EXPECT_TRUE(data.AllWriteDataConsumed());
970 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
971 RunResumeAfterUnstallBidirectionalTest(
972 base::Bind(&IncreaseStreamSendWindowSize));
975 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
976 RunResumeAfterUnstallBidirectionalTest(
977 base::Bind(&AdjustStreamSendWindowSize));
980 // Test calculation of amount of bytes received from network.
981 TEST_P(SpdyStreamTest, ReceivedBytes) {
982 GURL url(kStreamUrl);
984 session_ =
985 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
987 scoped_ptr<SpdyFrame> syn(
988 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
989 AddWrite(*syn);
991 scoped_ptr<SpdyFrame>
992 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
993 AddRead(*reply);
995 scoped_ptr<SpdyFrame> msg(
996 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
997 AddRead(*msg);
999 AddReadEOF();
1001 DeterministicSocketData data(GetReads(), GetNumReads(),
1002 GetWrites(), GetNumWrites());
1003 MockConnect connect_data(SYNCHRONOUS, OK);
1004 data.set_connect_data(connect_data);
1006 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1008 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
1010 base::WeakPtr<SpdyStream> stream =
1011 CreateStreamSynchronously(
1012 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
1013 ASSERT_TRUE(stream.get() != NULL);
1015 StreamDelegateDoNothing delegate(stream);
1016 stream->SetDelegate(&delegate);
1018 EXPECT_FALSE(stream->HasUrlFromHeaders());
1020 scoped_ptr<SpdyHeaderBlock> headers(
1021 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
1022 EXPECT_EQ(ERR_IO_PENDING,
1023 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
1024 EXPECT_TRUE(stream->HasUrlFromHeaders());
1025 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
1027 int64 reply_frame_len = reply->size();
1028 int64 data_header_len = spdy_util_.CreateFramer(false)
1029 ->GetDataFrameMinimumSize();
1030 int64 data_frame_len = data_header_len + kPostBodyLength;
1031 int64 response_len = reply_frame_len + data_frame_len;
1033 EXPECT_EQ(0, stream->raw_received_bytes());
1034 data.RunFor(1); // SYN
1035 EXPECT_EQ(0, stream->raw_received_bytes());
1036 data.RunFor(1); // REPLY
1037 EXPECT_EQ(reply_frame_len, stream->raw_received_bytes());
1038 data.RunFor(1); // DATA
1039 EXPECT_EQ(response_len, stream->raw_received_bytes());
1040 data.RunFor(1); // FIN
1042 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1045 } // namespace
1047 } // namespace test
1049 } // namespace net