Port Android relocation packer to chromium build
[chromium-blink-merge.git] / net / spdy / spdy_stream_unittest.cc
blob71a4142b3d8c279d7a61e9a218f0eaab8dc8899e
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 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_++));
79 void AddReadEOF() {
80 reads_.push_back(MockRead(ASYNC, 0, offset_++));
83 MockRead* GetReads() {
84 return vector_as_array(&reads_);
87 size_t GetNumReads() const {
88 return reads_.size();
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_;
103 private:
104 // Used by Add{Read,Write}() above.
105 std::vector<MockWrite> writes_;
106 std::vector<MockRead> reads_;
107 int offset_;
110 INSTANTIATE_TEST_CASE_P(NextProto,
111 SpdyStreamTest,
112 testing::Values(kProtoSPDY31,
113 kProtoSPDY4_14,
114 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));
124 AddWrite(*req);
126 scoped_ptr<SpdyFrame> resp(
127 spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
128 AddRead(*resp);
130 scoped_ptr<SpdyFrame> msg(
131 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
132 AddWrite(*msg);
134 scoped_ptr<SpdyFrame> echo(
135 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
136 AddRead(*echo);
138 AddReadEOF();
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_);
178 AddReadEOF();
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, spdy_session, GURL(), DEFAULT_PRIORITY,
191 SpdySession::GetInitialWindowSize(kProtoSPDY31),
192 SpdySession::GetInitialWindowSize(kProtoSPDY31),
193 BoundNetLog());
194 stream.set_stream_id(2);
195 EXPECT_FALSE(stream.HasUrlFromHeaders());
197 // Set required request headers.
198 SpdyHeaderBlock request_headers;
199 spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &request_headers);
200 stream.OnPushPromiseHeadersReceived(request_headers);
202 // Send some basic response headers.
203 SpdyHeaderBlock response;
204 response[spdy_util_.GetStatusKey()] = "200";
205 response[spdy_util_.GetVersionKey()] = "OK";
206 stream.OnInitialResponseHeadersReceived(
207 response, base::Time::Now(), base::TimeTicks::Now());
209 // And some more headers.
210 // TODO(baranovich): not valid for HTTP 2.
211 SpdyHeaderBlock headers;
212 headers["alpha"] = "beta";
213 stream.OnAdditionalResponseHeadersReceived(headers);
215 EXPECT_TRUE(stream.HasUrlFromHeaders());
216 EXPECT_EQ(kStreamUrl, stream.GetUrlFromHeaders().spec());
218 StreamDelegateDoNothing delegate(stream.GetWeakPtr());
219 stream.SetDelegate(&delegate);
221 base::MessageLoop::current()->RunUntilIdle();
223 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
224 EXPECT_EQ("beta", delegate.GetResponseHeaderValue("alpha"));
226 EXPECT_TRUE(spdy_session == NULL);
229 TEST_P(SpdyStreamTest, StreamError) {
230 GURL url(kStreamUrl);
232 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
234 scoped_ptr<SpdyFrame> req(
235 spdy_util_.ConstructSpdyPost(
236 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
237 AddWrite(*req);
239 scoped_ptr<SpdyFrame> resp(
240 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
241 AddRead(*resp);
243 scoped_ptr<SpdyFrame> msg(
244 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
245 AddWrite(*msg);
247 scoped_ptr<SpdyFrame> echo(
248 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
249 AddRead(*echo);
251 AddReadEOF();
253 CapturingBoundNetLog log;
255 OrderedSocketData data(GetReads(), GetNumReads(),
256 GetWrites(), GetNumWrites());
257 MockConnect connect_data(SYNCHRONOUS, OK);
258 data.set_connect_data(connect_data);
260 session_deps_.socket_factory->AddSocketDataProvider(&data);
262 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
264 base::WeakPtr<SpdyStream> stream =
265 CreateStreamSynchronously(
266 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
267 ASSERT_TRUE(stream.get() != NULL);
269 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
270 stream->SetDelegate(&delegate);
272 EXPECT_FALSE(stream->HasUrlFromHeaders());
274 scoped_ptr<SpdyHeaderBlock> headers(
275 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
276 EXPECT_EQ(ERR_IO_PENDING,
277 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
278 EXPECT_TRUE(stream->HasUrlFromHeaders());
279 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
281 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
283 const SpdyStreamId stream_id = delegate.stream_id();
285 EXPECT_TRUE(delegate.send_headers_completed());
286 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
287 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
288 delegate.TakeReceivedData());
289 EXPECT_TRUE(data.at_write_eof());
291 // Check that the NetLog was filled reasonably.
292 net::CapturingNetLog::CapturedEntryList entries;
293 log.GetEntries(&entries);
294 EXPECT_LT(0u, entries.size());
296 // Check that we logged SPDY_STREAM_ERROR correctly.
297 int pos = net::ExpectLogContainsSomewhere(
298 entries, 0, net::NetLog::TYPE_HTTP2_STREAM_ERROR,
299 net::NetLog::PHASE_NONE);
301 int stream_id2;
302 ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2));
303 EXPECT_EQ(static_cast<int>(stream_id), stream_id2);
306 // Make sure that large blocks of data are properly split up into
307 // frame-sized chunks for a request/response (i.e., an HTTP-like)
308 // stream.
309 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
310 GURL url(kStreamUrl);
312 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
314 scoped_ptr<SpdyFrame> req(
315 spdy_util_.ConstructSpdyPost(
316 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
317 AddWrite(*req);
319 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
320 scoped_ptr<SpdyFrame> chunk(
321 spdy_util_.ConstructSpdyBodyFrame(
322 1, chunk_data.data(), chunk_data.length(), false));
323 AddWrite(*chunk);
324 AddWrite(*chunk);
326 scoped_ptr<SpdyFrame> last_chunk(
327 spdy_util_.ConstructSpdyBodyFrame(
328 1, chunk_data.data(), chunk_data.length(), true));
329 AddWrite(*last_chunk);
331 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
332 AddRead(*resp);
334 AddReadEOF();
336 OrderedSocketData data(GetReads(), GetNumReads(),
337 GetWrites(), GetNumWrites());
338 MockConnect connect_data(SYNCHRONOUS, OK);
339 data.set_connect_data(connect_data);
341 session_deps_.socket_factory->AddSocketDataProvider(&data);
343 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
345 base::WeakPtr<SpdyStream> stream =
346 CreateStreamSynchronously(
347 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
348 ASSERT_TRUE(stream.get() != NULL);
350 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
351 StreamDelegateWithBody delegate(stream, body_data);
352 stream->SetDelegate(&delegate);
354 EXPECT_FALSE(stream->HasUrlFromHeaders());
356 scoped_ptr<SpdyHeaderBlock> headers(
357 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
358 EXPECT_EQ(ERR_IO_PENDING,
359 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
360 EXPECT_TRUE(stream->HasUrlFromHeaders());
361 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
363 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
365 EXPECT_TRUE(delegate.send_headers_completed());
366 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
367 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
368 EXPECT_TRUE(data.at_write_eof());
371 // Make sure that large blocks of data are properly split up into
372 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
373 // stream.
374 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
375 GURL url(kStreamUrl);
377 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
379 scoped_ptr<SpdyFrame> req(
380 spdy_util_.ConstructSpdyPost(
381 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
382 AddWrite(*req);
384 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
385 AddRead(*resp);
387 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
388 scoped_ptr<SpdyFrame> chunk(
389 spdy_util_.ConstructSpdyBodyFrame(
390 1, chunk_data.data(), chunk_data.length(), false));
391 AddWrite(*chunk);
392 AddWrite(*chunk);
393 AddWrite(*chunk);
395 AddReadEOF();
397 OrderedSocketData data(GetReads(), GetNumReads(),
398 GetWrites(), GetNumWrites());
399 MockConnect connect_data(SYNCHRONOUS, OK);
400 data.set_connect_data(connect_data);
402 session_deps_.socket_factory->AddSocketDataProvider(&data);
404 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
406 base::WeakPtr<SpdyStream> stream =
407 CreateStreamSynchronously(
408 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
409 ASSERT_TRUE(stream.get() != NULL);
411 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
412 StreamDelegateSendImmediate delegate(stream, body_data);
413 stream->SetDelegate(&delegate);
415 EXPECT_FALSE(stream->HasUrlFromHeaders());
417 scoped_ptr<SpdyHeaderBlock> headers(
418 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
419 EXPECT_EQ(ERR_IO_PENDING,
420 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
421 EXPECT_TRUE(stream->HasUrlFromHeaders());
422 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
424 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
426 EXPECT_TRUE(delegate.send_headers_completed());
427 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
428 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
429 EXPECT_TRUE(data.at_write_eof());
432 // Receiving a header with uppercase ASCII should result in a protocol
433 // error.
434 TEST_P(SpdyStreamTest, UpperCaseHeaders) {
435 GURL url(kStreamUrl);
437 session_ =
438 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
440 scoped_ptr<SpdyFrame> syn(
441 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
442 AddWrite(*syn);
444 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
445 scoped_ptr<SpdyFrame>
446 reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
447 AddRead(*reply);
449 scoped_ptr<SpdyFrame> rst(
450 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
451 AddWrite(*rst);
453 AddReadEOF();
455 DeterministicSocketData data(GetReads(), GetNumReads(),
456 GetWrites(), GetNumWrites());
457 MockConnect connect_data(SYNCHRONOUS, OK);
458 data.set_connect_data(connect_data);
460 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
462 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
464 base::WeakPtr<SpdyStream> stream =
465 CreateStreamSynchronously(
466 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
467 ASSERT_TRUE(stream.get() != NULL);
469 StreamDelegateDoNothing delegate(stream);
470 stream->SetDelegate(&delegate);
472 EXPECT_FALSE(stream->HasUrlFromHeaders());
474 scoped_ptr<SpdyHeaderBlock> headers(
475 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
476 EXPECT_EQ(ERR_IO_PENDING,
477 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
478 EXPECT_TRUE(stream->HasUrlFromHeaders());
479 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
481 data.RunFor(4);
483 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
486 // Receiving a header with uppercase ASCII should result in a protocol
487 // error even for a push stream.
488 TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
489 GURL url(kStreamUrl);
491 session_ =
492 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
494 scoped_ptr<SpdyFrame> syn(
495 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
496 AddWrite(*syn);
498 scoped_ptr<SpdyFrame>
499 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
500 AddRead(*reply);
502 const char* const extra_headers[] = {"X-UpperCase", "yes"};
503 scoped_ptr<SpdyFrame>
504 push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
505 AddRead(*push);
507 scoped_ptr<SpdyFrame> rst(
508 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
509 AddWrite(*rst);
511 AddReadEOF();
513 DeterministicSocketData data(GetReads(), GetNumReads(),
514 GetWrites(), GetNumWrites());
515 MockConnect connect_data(SYNCHRONOUS, OK);
516 data.set_connect_data(connect_data);
518 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
520 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
522 base::WeakPtr<SpdyStream> stream =
523 CreateStreamSynchronously(
524 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
525 ASSERT_TRUE(stream.get() != NULL);
527 StreamDelegateDoNothing delegate(stream);
528 stream->SetDelegate(&delegate);
530 EXPECT_FALSE(stream->HasUrlFromHeaders());
532 scoped_ptr<SpdyHeaderBlock> headers(
533 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
534 EXPECT_EQ(ERR_IO_PENDING,
535 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
536 EXPECT_TRUE(stream->HasUrlFromHeaders());
537 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
539 data.RunFor(4);
541 base::WeakPtr<SpdyStream> push_stream;
542 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
543 EXPECT_FALSE(push_stream);
545 data.RunFor(1);
547 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
550 // Receiving a header with uppercase ASCII in a HEADERS frame should
551 // result in a protocol error.
552 TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
553 GURL url(kStreamUrl);
555 session_ =
556 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
558 scoped_ptr<SpdyFrame> syn(
559 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
560 AddWrite(*syn);
562 scoped_ptr<SpdyFrame>
563 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
564 AddRead(*reply);
566 scoped_ptr<SpdyFrame>
567 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
568 AddRead(*push);
570 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
571 (*late_headers)["X-UpperCase"] = "yes";
572 scoped_ptr<SpdyFrame> headers_frame(
573 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
574 false,
576 LOWEST,
577 HEADERS,
578 CONTROL_FLAG_NONE,
579 0));
580 AddRead(*headers_frame);
582 scoped_ptr<SpdyFrame> rst(
583 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
584 AddWrite(*rst);
586 AddReadEOF();
588 DeterministicSocketData data(GetReads(), GetNumReads(),
589 GetWrites(), GetNumWrites());
590 MockConnect connect_data(SYNCHRONOUS, OK);
591 data.set_connect_data(connect_data);
593 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
595 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
597 base::WeakPtr<SpdyStream> stream =
598 CreateStreamSynchronously(
599 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
600 ASSERT_TRUE(stream.get() != NULL);
602 StreamDelegateDoNothing delegate(stream);
603 stream->SetDelegate(&delegate);
605 EXPECT_FALSE(stream->HasUrlFromHeaders());
607 scoped_ptr<SpdyHeaderBlock> headers(
608 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
609 EXPECT_EQ(ERR_IO_PENDING,
610 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
611 EXPECT_TRUE(stream->HasUrlFromHeaders());
612 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
614 data.RunFor(3);
616 base::WeakPtr<SpdyStream> push_stream;
617 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
618 EXPECT_TRUE(push_stream);
620 data.RunFor(1);
622 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
623 EXPECT_FALSE(push_stream);
625 data.RunFor(2);
627 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
630 // Receiving a duplicate header in a HEADERS frame should result in a
631 // protocol error.
632 TEST_P(SpdyStreamTest, DuplicateHeaders) {
633 GURL url(kStreamUrl);
635 session_ =
636 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
638 scoped_ptr<SpdyFrame> syn(
639 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
640 AddWrite(*syn);
642 scoped_ptr<SpdyFrame>
643 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
644 AddRead(*reply);
646 scoped_ptr<SpdyFrame>
647 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
648 AddRead(*push);
650 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
651 (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error";
652 scoped_ptr<SpdyFrame> headers_frame(
653 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
654 false,
656 LOWEST,
657 HEADERS,
658 CONTROL_FLAG_NONE,
659 0));
660 AddRead(*headers_frame);
662 scoped_ptr<SpdyFrame> rst(
663 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
664 AddWrite(*rst);
666 AddReadEOF();
668 DeterministicSocketData data(GetReads(), GetNumReads(),
669 GetWrites(), GetNumWrites());
670 MockConnect connect_data(SYNCHRONOUS, OK);
671 data.set_connect_data(connect_data);
673 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
675 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
677 base::WeakPtr<SpdyStream> stream =
678 CreateStreamSynchronously(
679 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
680 ASSERT_TRUE(stream.get() != NULL);
682 StreamDelegateDoNothing delegate(stream);
683 stream->SetDelegate(&delegate);
685 EXPECT_FALSE(stream->HasUrlFromHeaders());
687 scoped_ptr<SpdyHeaderBlock> headers(
688 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
689 EXPECT_EQ(ERR_IO_PENDING,
690 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
691 EXPECT_TRUE(stream->HasUrlFromHeaders());
692 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
694 data.RunFor(3);
696 base::WeakPtr<SpdyStream> push_stream;
697 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
698 EXPECT_TRUE(push_stream);
700 data.RunFor(1);
702 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
703 EXPECT_FALSE(push_stream);
705 data.RunFor(2);
707 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
710 // The tests below are only for SPDY/3 and above.
712 // Call IncreaseSendWindowSize on a stream with a large enough delta
713 // to overflow an int32. The SpdyStream should handle that case
714 // gracefully.
715 TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
716 session_ =
717 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
719 scoped_ptr<SpdyFrame> req(
720 spdy_util_.ConstructSpdyPost(
721 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
722 AddWrite(*req);
724 // Triggered by the overflowing call to IncreaseSendWindowSize
725 // below.
726 scoped_ptr<SpdyFrame> rst(
727 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
728 AddWrite(*rst);
730 AddReadEOF();
732 CapturingBoundNetLog log;
734 DeterministicSocketData data(GetReads(), GetNumReads(),
735 GetWrites(), GetNumWrites());
736 MockConnect connect_data(SYNCHRONOUS, OK);
737 data.set_connect_data(connect_data);
739 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
741 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
742 GURL url(kStreamUrl);
744 base::WeakPtr<SpdyStream> stream =
745 CreateStreamSynchronously(
746 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
747 ASSERT_TRUE(stream.get() != NULL);
748 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
749 stream->SetDelegate(&delegate);
751 scoped_ptr<SpdyHeaderBlock> headers(
752 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
753 EXPECT_EQ(ERR_IO_PENDING,
754 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
755 EXPECT_TRUE(stream->HasUrlFromHeaders());
756 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
758 data.RunFor(1);
760 int32 old_send_window_size = stream->send_window_size();
761 ASSERT_GT(old_send_window_size, 0);
762 int32 delta_window_size = kint32max - old_send_window_size + 1;
763 stream->IncreaseSendWindowSize(delta_window_size);
764 EXPECT_EQ(NULL, stream.get());
766 data.RunFor(2);
768 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
771 // Functions used with
772 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
774 void StallStream(const base::WeakPtr<SpdyStream>& stream) {
775 // Reduce the send window size to 0 to stall.
776 while (stream->send_window_size() > 0) {
777 stream->DecreaseSendWindowSize(
778 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
782 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
783 int32 delta_window_size) {
784 EXPECT_TRUE(stream->send_stalled_by_flow_control());
785 stream->IncreaseSendWindowSize(delta_window_size);
786 EXPECT_FALSE(stream->send_stalled_by_flow_control());
789 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
790 int32 delta_window_size) {
791 // Make sure that negative adjustments are handled properly.
792 EXPECT_TRUE(stream->send_stalled_by_flow_control());
793 stream->AdjustSendWindowSize(-delta_window_size);
794 EXPECT_TRUE(stream->send_stalled_by_flow_control());
795 stream->AdjustSendWindowSize(+delta_window_size);
796 EXPECT_TRUE(stream->send_stalled_by_flow_control());
797 stream->AdjustSendWindowSize(+delta_window_size);
798 EXPECT_FALSE(stream->send_stalled_by_flow_control());
801 // Given an unstall function, runs a test to make sure that a
802 // request/response (i.e., an HTTP-like) stream resumes after a stall
803 // and unstall.
804 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
805 const UnstallFunction& unstall_function) {
806 GURL url(kStreamUrl);
808 session_ =
809 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
811 scoped_ptr<SpdyFrame> req(
812 spdy_util_.ConstructSpdyPost(
813 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
814 AddWrite(*req);
816 scoped_ptr<SpdyFrame> body(
817 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
818 AddWrite(*body);
820 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
821 AddRead(*resp);
823 AddReadEOF();
825 DeterministicSocketData data(GetReads(), GetNumReads(),
826 GetWrites(), GetNumWrites());
827 MockConnect connect_data(SYNCHRONOUS, OK);
828 data.set_connect_data(connect_data);
830 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
832 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
834 base::WeakPtr<SpdyStream> stream =
835 CreateStreamSynchronously(
836 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
837 ASSERT_TRUE(stream.get() != NULL);
839 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
840 stream->SetDelegate(&delegate);
842 EXPECT_FALSE(stream->HasUrlFromHeaders());
843 EXPECT_FALSE(stream->send_stalled_by_flow_control());
845 scoped_ptr<SpdyHeaderBlock> headers(
846 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
847 EXPECT_EQ(ERR_IO_PENDING,
848 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
849 EXPECT_TRUE(stream->HasUrlFromHeaders());
850 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
852 StallStream(stream);
854 data.RunFor(1);
856 EXPECT_TRUE(stream->send_stalled_by_flow_control());
858 unstall_function.Run(stream, kPostBodyLength);
860 EXPECT_FALSE(stream->send_stalled_by_flow_control());
862 data.RunFor(3);
864 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
866 EXPECT_TRUE(delegate.send_headers_completed());
867 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
868 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
869 EXPECT_TRUE(data.at_write_eof());
872 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
873 RunResumeAfterUnstallRequestResponseTest(
874 base::Bind(&IncreaseStreamSendWindowSize));
877 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
878 RunResumeAfterUnstallRequestResponseTest(
879 base::Bind(&AdjustStreamSendWindowSize));
882 // Given an unstall function, runs a test to make sure that a
883 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
884 // and unstall.
885 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
886 const UnstallFunction& unstall_function) {
887 GURL url(kStreamUrl);
889 session_ =
890 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
892 scoped_ptr<SpdyFrame> req(
893 spdy_util_.ConstructSpdyPost(
894 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
895 AddWrite(*req);
897 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
898 AddRead(*resp);
900 scoped_ptr<SpdyFrame> msg(
901 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
902 AddWrite(*msg);
904 scoped_ptr<SpdyFrame> echo(
905 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
906 AddRead(*echo);
908 AddReadEOF();
910 DeterministicSocketData data(GetReads(), GetNumReads(),
911 GetWrites(), GetNumWrites());
912 MockConnect connect_data(SYNCHRONOUS, OK);
913 data.set_connect_data(connect_data);
915 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
917 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
919 base::WeakPtr<SpdyStream> stream =
920 CreateStreamSynchronously(
921 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
922 ASSERT_TRUE(stream.get() != NULL);
924 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
925 stream->SetDelegate(&delegate);
927 EXPECT_FALSE(stream->HasUrlFromHeaders());
929 scoped_ptr<SpdyHeaderBlock> headers(
930 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
931 EXPECT_EQ(ERR_IO_PENDING,
932 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
933 EXPECT_TRUE(stream->HasUrlFromHeaders());
934 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
936 data.RunFor(1);
938 EXPECT_FALSE(stream->send_stalled_by_flow_control());
940 StallStream(stream);
942 data.RunFor(1);
944 EXPECT_TRUE(stream->send_stalled_by_flow_control());
946 unstall_function.Run(stream, kPostBodyLength);
948 EXPECT_FALSE(stream->send_stalled_by_flow_control());
950 data.RunFor(3);
952 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
954 EXPECT_TRUE(delegate.send_headers_completed());
955 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
956 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
957 delegate.TakeReceivedData());
958 EXPECT_TRUE(data.at_write_eof());
961 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
962 RunResumeAfterUnstallBidirectionalTest(
963 base::Bind(&IncreaseStreamSendWindowSize));
966 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
967 RunResumeAfterUnstallBidirectionalTest(
968 base::Bind(&AdjustStreamSendWindowSize));
971 // Test calculation of amount of bytes received from network.
972 TEST_P(SpdyStreamTest, ReceivedBytes) {
973 GURL url(kStreamUrl);
975 session_ =
976 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
978 scoped_ptr<SpdyFrame> syn(
979 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
980 AddWrite(*syn);
982 scoped_ptr<SpdyFrame>
983 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
984 AddRead(*reply);
986 scoped_ptr<SpdyFrame> msg(
987 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
988 AddRead(*msg);
990 AddReadEOF();
992 DeterministicSocketData data(GetReads(), GetNumReads(),
993 GetWrites(), GetNumWrites());
994 MockConnect connect_data(SYNCHRONOUS, OK);
995 data.set_connect_data(connect_data);
997 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
999 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
1001 base::WeakPtr<SpdyStream> stream =
1002 CreateStreamSynchronously(
1003 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
1004 ASSERT_TRUE(stream.get() != NULL);
1006 StreamDelegateDoNothing delegate(stream);
1007 stream->SetDelegate(&delegate);
1009 EXPECT_FALSE(stream->HasUrlFromHeaders());
1011 scoped_ptr<SpdyHeaderBlock> headers(
1012 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
1013 EXPECT_EQ(ERR_IO_PENDING,
1014 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
1015 EXPECT_TRUE(stream->HasUrlFromHeaders());
1016 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
1018 int64 reply_frame_len = reply->size();
1019 int64 data_header_len = spdy_util_.CreateFramer(false)
1020 ->GetDataFrameMinimumSize();
1021 int64 data_frame_len = data_header_len + kPostBodyLength;
1022 int64 response_len = reply_frame_len + data_frame_len;
1024 EXPECT_EQ(0, stream->raw_received_bytes());
1025 data.RunFor(1); // SYN
1026 EXPECT_EQ(0, stream->raw_received_bytes());
1027 data.RunFor(1); // REPLY
1028 EXPECT_EQ(reply_frame_len, stream->raw_received_bytes());
1029 data.RunFor(1); // DATA
1030 EXPECT_EQ(response_len, stream->raw_received_bytes());
1031 data.RunFor(1); // FIN
1033 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1036 } // namespace
1038 } // namespace test
1040 } // namespace net