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