Move InMemoryURLIndex into chrome/browser/autocomplete
[chromium-blink-merge.git] / net / spdy / spdy_stream_unittest.cc
blobd5645d8de226e3bfc46a48a1c05606062e60bda2
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(
111 NextProto,
112 SpdyStreamTest,
113 testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
115 TEST_P(SpdyStreamTest, SendDataAfterOpen) {
116 GURL url(kStreamUrl);
118 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
120 scoped_ptr<SpdyFrame> req(
121 spdy_util_.ConstructSpdyPost(
122 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
123 AddWrite(*req);
125 scoped_ptr<SpdyFrame> resp(
126 spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
127 AddRead(*resp);
129 scoped_ptr<SpdyFrame> msg(
130 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
131 AddWrite(*msg);
133 scoped_ptr<SpdyFrame> echo(
134 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
135 AddRead(*echo);
137 AddReadEOF();
139 OrderedSocketData data(GetReads(), GetNumReads(),
140 GetWrites(), GetNumWrites());
141 MockConnect connect_data(SYNCHRONOUS, OK);
142 data.set_connect_data(connect_data);
144 session_deps_.socket_factory->AddSocketDataProvider(&data);
146 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
148 base::WeakPtr<SpdyStream> stream =
149 CreateStreamSynchronously(
150 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
151 ASSERT_TRUE(stream.get() != NULL);
153 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
154 stream->SetDelegate(&delegate);
156 EXPECT_FALSE(stream->HasUrlFromHeaders());
158 scoped_ptr<SpdyHeaderBlock> headers(
159 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
160 EXPECT_EQ(ERR_IO_PENDING,
161 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
162 EXPECT_TRUE(stream->HasUrlFromHeaders());
163 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
165 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
167 EXPECT_TRUE(delegate.send_headers_completed());
168 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
169 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
170 delegate.TakeReceivedData());
171 EXPECT_TRUE(data.at_write_eof());
174 TEST_P(SpdyStreamTest, PushedStream) {
175 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
177 AddReadEOF();
179 OrderedSocketData data(GetReads(), GetNumReads(),
180 GetWrites(), GetNumWrites());
181 MockConnect connect_data(SYNCHRONOUS, OK);
182 data.set_connect_data(connect_data);
184 session_deps_.socket_factory->AddSocketDataProvider(&data);
186 base::WeakPtr<SpdySession> spdy_session(CreateDefaultSpdySession());
188 // Conjure up a stream.
189 SpdyStream stream(SPDY_PUSH_STREAM, spdy_session, GURL(), DEFAULT_PRIORITY,
190 SpdySession::GetInitialWindowSize(kProtoSPDY31),
191 SpdySession::GetInitialWindowSize(kProtoSPDY31),
192 BoundNetLog());
193 stream.set_stream_id(2);
194 EXPECT_FALSE(stream.HasUrlFromHeaders());
196 // Set required request headers.
197 SpdyHeaderBlock request_headers;
198 spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &request_headers);
199 stream.OnPushPromiseHeadersReceived(request_headers);
201 // Send some basic response headers.
202 SpdyHeaderBlock response;
203 response[spdy_util_.GetStatusKey()] = "200";
204 response[spdy_util_.GetVersionKey()] = "OK";
205 stream.OnInitialResponseHeadersReceived(
206 response, base::Time::Now(), base::TimeTicks::Now());
208 // And some more headers.
209 // TODO(baranovich): not valid for HTTP 2.
210 SpdyHeaderBlock headers;
211 headers["alpha"] = "beta";
212 stream.OnAdditionalResponseHeadersReceived(headers);
214 EXPECT_TRUE(stream.HasUrlFromHeaders());
215 EXPECT_EQ(kStreamUrl, stream.GetUrlFromHeaders().spec());
217 StreamDelegateDoNothing delegate(stream.GetWeakPtr());
218 stream.SetDelegate(&delegate);
220 base::MessageLoop::current()->RunUntilIdle();
222 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
223 EXPECT_EQ("beta", delegate.GetResponseHeaderValue("alpha"));
225 EXPECT_TRUE(spdy_session == NULL);
228 TEST_P(SpdyStreamTest, StreamError) {
229 GURL url(kStreamUrl);
231 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
233 scoped_ptr<SpdyFrame> req(
234 spdy_util_.ConstructSpdyPost(
235 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
236 AddWrite(*req);
238 scoped_ptr<SpdyFrame> resp(
239 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
240 AddRead(*resp);
242 scoped_ptr<SpdyFrame> msg(
243 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
244 AddWrite(*msg);
246 scoped_ptr<SpdyFrame> echo(
247 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
248 AddRead(*echo);
250 AddReadEOF();
252 CapturingBoundNetLog log;
254 OrderedSocketData data(GetReads(), GetNumReads(),
255 GetWrites(), GetNumWrites());
256 MockConnect connect_data(SYNCHRONOUS, OK);
257 data.set_connect_data(connect_data);
259 session_deps_.socket_factory->AddSocketDataProvider(&data);
261 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
263 base::WeakPtr<SpdyStream> stream =
264 CreateStreamSynchronously(
265 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
266 ASSERT_TRUE(stream.get() != NULL);
268 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
269 stream->SetDelegate(&delegate);
271 EXPECT_FALSE(stream->HasUrlFromHeaders());
273 scoped_ptr<SpdyHeaderBlock> headers(
274 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
275 EXPECT_EQ(ERR_IO_PENDING,
276 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
277 EXPECT_TRUE(stream->HasUrlFromHeaders());
278 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
280 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
282 const SpdyStreamId stream_id = delegate.stream_id();
284 EXPECT_TRUE(delegate.send_headers_completed());
285 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
286 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
287 delegate.TakeReceivedData());
288 EXPECT_TRUE(data.at_write_eof());
290 // Check that the NetLog was filled reasonably.
291 net::CapturingNetLog::CapturedEntryList entries;
292 log.GetEntries(&entries);
293 EXPECT_LT(0u, entries.size());
295 // Check that we logged SPDY_STREAM_ERROR correctly.
296 int pos = net::ExpectLogContainsSomewhere(
297 entries, 0, net::NetLog::TYPE_HTTP2_STREAM_ERROR,
298 net::NetLog::PHASE_NONE);
300 int stream_id2;
301 ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2));
302 EXPECT_EQ(static_cast<int>(stream_id), stream_id2);
305 // Make sure that large blocks of data are properly split up into
306 // frame-sized chunks for a request/response (i.e., an HTTP-like)
307 // stream.
308 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
309 GURL url(kStreamUrl);
311 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
313 scoped_ptr<SpdyFrame> req(
314 spdy_util_.ConstructSpdyPost(
315 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
316 AddWrite(*req);
318 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
319 scoped_ptr<SpdyFrame> chunk(
320 spdy_util_.ConstructSpdyBodyFrame(
321 1, chunk_data.data(), chunk_data.length(), false));
322 AddWrite(*chunk);
323 AddWrite(*chunk);
325 scoped_ptr<SpdyFrame> last_chunk(
326 spdy_util_.ConstructSpdyBodyFrame(
327 1, chunk_data.data(), chunk_data.length(), true));
328 AddWrite(*last_chunk);
330 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
331 AddRead(*resp);
333 AddReadEOF();
335 OrderedSocketData data(GetReads(), GetNumReads(),
336 GetWrites(), GetNumWrites());
337 MockConnect connect_data(SYNCHRONOUS, OK);
338 data.set_connect_data(connect_data);
340 session_deps_.socket_factory->AddSocketDataProvider(&data);
342 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
344 base::WeakPtr<SpdyStream> stream =
345 CreateStreamSynchronously(
346 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
347 ASSERT_TRUE(stream.get() != NULL);
349 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
350 StreamDelegateWithBody delegate(stream, body_data);
351 stream->SetDelegate(&delegate);
353 EXPECT_FALSE(stream->HasUrlFromHeaders());
355 scoped_ptr<SpdyHeaderBlock> headers(
356 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
357 EXPECT_EQ(ERR_IO_PENDING,
358 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
359 EXPECT_TRUE(stream->HasUrlFromHeaders());
360 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
362 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
364 EXPECT_TRUE(delegate.send_headers_completed());
365 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
366 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
367 EXPECT_TRUE(data.at_write_eof());
370 // Make sure that large blocks of data are properly split up into
371 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
372 // stream.
373 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
374 GURL url(kStreamUrl);
376 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
378 scoped_ptr<SpdyFrame> req(
379 spdy_util_.ConstructSpdyPost(
380 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
381 AddWrite(*req);
383 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
384 AddRead(*resp);
386 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
387 scoped_ptr<SpdyFrame> chunk(
388 spdy_util_.ConstructSpdyBodyFrame(
389 1, chunk_data.data(), chunk_data.length(), false));
390 AddWrite(*chunk);
391 AddWrite(*chunk);
392 AddWrite(*chunk);
394 AddReadEOF();
396 OrderedSocketData data(GetReads(), GetNumReads(),
397 GetWrites(), GetNumWrites());
398 MockConnect connect_data(SYNCHRONOUS, OK);
399 data.set_connect_data(connect_data);
401 session_deps_.socket_factory->AddSocketDataProvider(&data);
403 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
405 base::WeakPtr<SpdyStream> stream =
406 CreateStreamSynchronously(
407 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
408 ASSERT_TRUE(stream.get() != NULL);
410 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
411 StreamDelegateSendImmediate delegate(stream, body_data);
412 stream->SetDelegate(&delegate);
414 EXPECT_FALSE(stream->HasUrlFromHeaders());
416 scoped_ptr<SpdyHeaderBlock> headers(
417 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
418 EXPECT_EQ(ERR_IO_PENDING,
419 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
420 EXPECT_TRUE(stream->HasUrlFromHeaders());
421 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
423 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
425 EXPECT_TRUE(delegate.send_headers_completed());
426 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
427 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
428 EXPECT_TRUE(data.at_write_eof());
431 // Receiving a header with uppercase ASCII should result in a protocol
432 // error.
433 TEST_P(SpdyStreamTest, UpperCaseHeaders) {
434 GURL url(kStreamUrl);
436 session_ =
437 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
439 scoped_ptr<SpdyFrame> syn(
440 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
441 AddWrite(*syn);
443 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
444 scoped_ptr<SpdyFrame>
445 reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
446 AddRead(*reply);
448 scoped_ptr<SpdyFrame> rst(
449 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
450 AddWrite(*rst);
452 AddReadEOF();
454 DeterministicSocketData data(GetReads(), GetNumReads(),
455 GetWrites(), GetNumWrites());
456 MockConnect connect_data(SYNCHRONOUS, OK);
457 data.set_connect_data(connect_data);
459 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
461 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
463 base::WeakPtr<SpdyStream> stream =
464 CreateStreamSynchronously(
465 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
466 ASSERT_TRUE(stream.get() != NULL);
468 StreamDelegateDoNothing delegate(stream);
469 stream->SetDelegate(&delegate);
471 EXPECT_FALSE(stream->HasUrlFromHeaders());
473 scoped_ptr<SpdyHeaderBlock> headers(
474 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
475 EXPECT_EQ(ERR_IO_PENDING,
476 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
477 EXPECT_TRUE(stream->HasUrlFromHeaders());
478 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
480 data.RunFor(4);
482 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
485 // Receiving a header with uppercase ASCII should result in a protocol
486 // error even for a push stream.
487 TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
488 GURL url(kStreamUrl);
490 session_ =
491 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
493 scoped_ptr<SpdyFrame> syn(
494 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
495 AddWrite(*syn);
497 scoped_ptr<SpdyFrame>
498 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
499 AddRead(*reply);
501 const char* const extra_headers[] = {"X-UpperCase", "yes"};
502 scoped_ptr<SpdyFrame>
503 push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
504 AddRead(*push);
506 scoped_ptr<SpdyFrame> rst(
507 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
508 AddWrite(*rst);
510 AddReadEOF();
512 DeterministicSocketData data(GetReads(), GetNumReads(),
513 GetWrites(), GetNumWrites());
514 MockConnect connect_data(SYNCHRONOUS, OK);
515 data.set_connect_data(connect_data);
517 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
519 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
521 base::WeakPtr<SpdyStream> stream =
522 CreateStreamSynchronously(
523 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
524 ASSERT_TRUE(stream.get() != NULL);
526 StreamDelegateDoNothing delegate(stream);
527 stream->SetDelegate(&delegate);
529 EXPECT_FALSE(stream->HasUrlFromHeaders());
531 scoped_ptr<SpdyHeaderBlock> headers(
532 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
533 EXPECT_EQ(ERR_IO_PENDING,
534 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
535 EXPECT_TRUE(stream->HasUrlFromHeaders());
536 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
538 data.RunFor(4);
540 base::WeakPtr<SpdyStream> push_stream;
541 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
542 EXPECT_FALSE(push_stream);
544 data.RunFor(1);
546 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
549 // Receiving a header with uppercase ASCII in a HEADERS frame should
550 // result in a protocol error.
551 TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
552 GURL url(kStreamUrl);
554 session_ =
555 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
557 scoped_ptr<SpdyFrame> syn(
558 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
559 AddWrite(*syn);
561 scoped_ptr<SpdyFrame>
562 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
563 AddRead(*reply);
565 scoped_ptr<SpdyFrame>
566 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
567 AddRead(*push);
569 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
570 (*late_headers)["X-UpperCase"] = "yes";
571 scoped_ptr<SpdyFrame> headers_frame(
572 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
573 false,
575 LOWEST,
576 HEADERS,
577 CONTROL_FLAG_NONE,
578 0));
579 AddRead(*headers_frame);
581 scoped_ptr<SpdyFrame> rst(
582 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
583 AddWrite(*rst);
585 AddReadEOF();
587 DeterministicSocketData data(GetReads(), GetNumReads(),
588 GetWrites(), GetNumWrites());
589 MockConnect connect_data(SYNCHRONOUS, OK);
590 data.set_connect_data(connect_data);
592 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
594 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
596 base::WeakPtr<SpdyStream> stream =
597 CreateStreamSynchronously(
598 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
599 ASSERT_TRUE(stream.get() != NULL);
601 StreamDelegateDoNothing delegate(stream);
602 stream->SetDelegate(&delegate);
604 EXPECT_FALSE(stream->HasUrlFromHeaders());
606 scoped_ptr<SpdyHeaderBlock> headers(
607 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
608 EXPECT_EQ(ERR_IO_PENDING,
609 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
610 EXPECT_TRUE(stream->HasUrlFromHeaders());
611 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
613 data.RunFor(3);
615 base::WeakPtr<SpdyStream> push_stream;
616 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
617 EXPECT_TRUE(push_stream);
619 data.RunFor(1);
621 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
622 EXPECT_FALSE(push_stream);
624 data.RunFor(2);
626 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
629 // Receiving a duplicate header in a HEADERS frame should result in a
630 // protocol error.
631 TEST_P(SpdyStreamTest, DuplicateHeaders) {
632 GURL url(kStreamUrl);
634 session_ =
635 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
637 scoped_ptr<SpdyFrame> syn(
638 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
639 AddWrite(*syn);
641 scoped_ptr<SpdyFrame>
642 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
643 AddRead(*reply);
645 scoped_ptr<SpdyFrame>
646 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
647 AddRead(*push);
649 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
650 (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error";
651 scoped_ptr<SpdyFrame> headers_frame(
652 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
653 false,
655 LOWEST,
656 HEADERS,
657 CONTROL_FLAG_NONE,
658 0));
659 AddRead(*headers_frame);
661 scoped_ptr<SpdyFrame> rst(
662 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
663 AddWrite(*rst);
665 AddReadEOF();
667 DeterministicSocketData data(GetReads(), GetNumReads(),
668 GetWrites(), GetNumWrites());
669 MockConnect connect_data(SYNCHRONOUS, OK);
670 data.set_connect_data(connect_data);
672 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
674 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
676 base::WeakPtr<SpdyStream> stream =
677 CreateStreamSynchronously(
678 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
679 ASSERT_TRUE(stream.get() != NULL);
681 StreamDelegateDoNothing delegate(stream);
682 stream->SetDelegate(&delegate);
684 EXPECT_FALSE(stream->HasUrlFromHeaders());
686 scoped_ptr<SpdyHeaderBlock> headers(
687 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
688 EXPECT_EQ(ERR_IO_PENDING,
689 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
690 EXPECT_TRUE(stream->HasUrlFromHeaders());
691 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
693 data.RunFor(3);
695 base::WeakPtr<SpdyStream> push_stream;
696 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
697 EXPECT_TRUE(push_stream);
699 data.RunFor(1);
701 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
702 EXPECT_FALSE(push_stream);
704 data.RunFor(2);
706 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
709 // The tests below are only for SPDY/3 and above.
711 // Call IncreaseSendWindowSize on a stream with a large enough delta
712 // to overflow an int32. The SpdyStream should handle that case
713 // gracefully.
714 TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
715 session_ =
716 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
718 scoped_ptr<SpdyFrame> req(
719 spdy_util_.ConstructSpdyPost(
720 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
721 AddWrite(*req);
723 // Triggered by the overflowing call to IncreaseSendWindowSize
724 // below.
725 scoped_ptr<SpdyFrame> rst(
726 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
727 AddWrite(*rst);
729 AddReadEOF();
731 CapturingBoundNetLog log;
733 DeterministicSocketData data(GetReads(), GetNumReads(),
734 GetWrites(), GetNumWrites());
735 MockConnect connect_data(SYNCHRONOUS, OK);
736 data.set_connect_data(connect_data);
738 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
740 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
741 GURL url(kStreamUrl);
743 base::WeakPtr<SpdyStream> stream =
744 CreateStreamSynchronously(
745 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
746 ASSERT_TRUE(stream.get() != NULL);
747 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
748 stream->SetDelegate(&delegate);
750 scoped_ptr<SpdyHeaderBlock> headers(
751 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
752 EXPECT_EQ(ERR_IO_PENDING,
753 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
754 EXPECT_TRUE(stream->HasUrlFromHeaders());
755 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
757 data.RunFor(1);
759 int32 old_send_window_size = stream->send_window_size();
760 ASSERT_GT(old_send_window_size, 0);
761 int32 delta_window_size = kint32max - old_send_window_size + 1;
762 stream->IncreaseSendWindowSize(delta_window_size);
763 EXPECT_EQ(NULL, stream.get());
765 data.RunFor(2);
767 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
770 // Functions used with
771 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
773 void StallStream(const base::WeakPtr<SpdyStream>& stream) {
774 // Reduce the send window size to 0 to stall.
775 while (stream->send_window_size() > 0) {
776 stream->DecreaseSendWindowSize(
777 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
781 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
782 int32 delta_window_size) {
783 EXPECT_TRUE(stream->send_stalled_by_flow_control());
784 stream->IncreaseSendWindowSize(delta_window_size);
785 EXPECT_FALSE(stream->send_stalled_by_flow_control());
788 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
789 int32 delta_window_size) {
790 // Make sure that negative adjustments are handled properly.
791 EXPECT_TRUE(stream->send_stalled_by_flow_control());
792 stream->AdjustSendWindowSize(-delta_window_size);
793 EXPECT_TRUE(stream->send_stalled_by_flow_control());
794 stream->AdjustSendWindowSize(+delta_window_size);
795 EXPECT_TRUE(stream->send_stalled_by_flow_control());
796 stream->AdjustSendWindowSize(+delta_window_size);
797 EXPECT_FALSE(stream->send_stalled_by_flow_control());
800 // Given an unstall function, runs a test to make sure that a
801 // request/response (i.e., an HTTP-like) stream resumes after a stall
802 // and unstall.
803 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
804 const UnstallFunction& unstall_function) {
805 GURL url(kStreamUrl);
807 session_ =
808 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
810 scoped_ptr<SpdyFrame> req(
811 spdy_util_.ConstructSpdyPost(
812 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
813 AddWrite(*req);
815 scoped_ptr<SpdyFrame> body(
816 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
817 AddWrite(*body);
819 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
820 AddRead(*resp);
822 AddReadEOF();
824 DeterministicSocketData data(GetReads(), GetNumReads(),
825 GetWrites(), GetNumWrites());
826 MockConnect connect_data(SYNCHRONOUS, OK);
827 data.set_connect_data(connect_data);
829 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
831 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
833 base::WeakPtr<SpdyStream> stream =
834 CreateStreamSynchronously(
835 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
836 ASSERT_TRUE(stream.get() != NULL);
838 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
839 stream->SetDelegate(&delegate);
841 EXPECT_FALSE(stream->HasUrlFromHeaders());
842 EXPECT_FALSE(stream->send_stalled_by_flow_control());
844 scoped_ptr<SpdyHeaderBlock> headers(
845 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
846 EXPECT_EQ(ERR_IO_PENDING,
847 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
848 EXPECT_TRUE(stream->HasUrlFromHeaders());
849 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
851 StallStream(stream);
853 data.RunFor(1);
855 EXPECT_TRUE(stream->send_stalled_by_flow_control());
857 unstall_function.Run(stream, kPostBodyLength);
859 EXPECT_FALSE(stream->send_stalled_by_flow_control());
861 data.RunFor(3);
863 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
865 EXPECT_TRUE(delegate.send_headers_completed());
866 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
867 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
868 EXPECT_TRUE(data.at_write_eof());
871 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
872 RunResumeAfterUnstallRequestResponseTest(
873 base::Bind(&IncreaseStreamSendWindowSize));
876 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
877 RunResumeAfterUnstallRequestResponseTest(
878 base::Bind(&AdjustStreamSendWindowSize));
881 // Given an unstall function, runs a test to make sure that a
882 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
883 // and unstall.
884 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
885 const UnstallFunction& unstall_function) {
886 GURL url(kStreamUrl);
888 session_ =
889 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
891 scoped_ptr<SpdyFrame> req(
892 spdy_util_.ConstructSpdyPost(
893 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
894 AddWrite(*req);
896 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
897 AddRead(*resp);
899 scoped_ptr<SpdyFrame> msg(
900 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
901 AddWrite(*msg);
903 scoped_ptr<SpdyFrame> echo(
904 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
905 AddRead(*echo);
907 AddReadEOF();
909 DeterministicSocketData data(GetReads(), GetNumReads(),
910 GetWrites(), GetNumWrites());
911 MockConnect connect_data(SYNCHRONOUS, OK);
912 data.set_connect_data(connect_data);
914 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
916 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
918 base::WeakPtr<SpdyStream> stream =
919 CreateStreamSynchronously(
920 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
921 ASSERT_TRUE(stream.get() != NULL);
923 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
924 stream->SetDelegate(&delegate);
926 EXPECT_FALSE(stream->HasUrlFromHeaders());
928 scoped_ptr<SpdyHeaderBlock> headers(
929 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
930 EXPECT_EQ(ERR_IO_PENDING,
931 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
932 EXPECT_TRUE(stream->HasUrlFromHeaders());
933 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
935 data.RunFor(1);
937 EXPECT_FALSE(stream->send_stalled_by_flow_control());
939 StallStream(stream);
941 data.RunFor(1);
943 EXPECT_TRUE(stream->send_stalled_by_flow_control());
945 unstall_function.Run(stream, kPostBodyLength);
947 EXPECT_FALSE(stream->send_stalled_by_flow_control());
949 data.RunFor(3);
951 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
953 EXPECT_TRUE(delegate.send_headers_completed());
954 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
955 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
956 delegate.TakeReceivedData());
957 EXPECT_TRUE(data.at_write_eof());
960 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
961 RunResumeAfterUnstallBidirectionalTest(
962 base::Bind(&IncreaseStreamSendWindowSize));
965 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
966 RunResumeAfterUnstallBidirectionalTest(
967 base::Bind(&AdjustStreamSendWindowSize));
970 // Test calculation of amount of bytes received from network.
971 TEST_P(SpdyStreamTest, ReceivedBytes) {
972 GURL url(kStreamUrl);
974 session_ =
975 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
977 scoped_ptr<SpdyFrame> syn(
978 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
979 AddWrite(*syn);
981 scoped_ptr<SpdyFrame>
982 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
983 AddRead(*reply);
985 scoped_ptr<SpdyFrame> msg(
986 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
987 AddRead(*msg);
989 AddReadEOF();
991 DeterministicSocketData data(GetReads(), GetNumReads(),
992 GetWrites(), GetNumWrites());
993 MockConnect connect_data(SYNCHRONOUS, OK);
994 data.set_connect_data(connect_data);
996 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
998 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
1000 base::WeakPtr<SpdyStream> stream =
1001 CreateStreamSynchronously(
1002 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
1003 ASSERT_TRUE(stream.get() != NULL);
1005 StreamDelegateDoNothing delegate(stream);
1006 stream->SetDelegate(&delegate);
1008 EXPECT_FALSE(stream->HasUrlFromHeaders());
1010 scoped_ptr<SpdyHeaderBlock> headers(
1011 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
1012 EXPECT_EQ(ERR_IO_PENDING,
1013 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
1014 EXPECT_TRUE(stream->HasUrlFromHeaders());
1015 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
1017 int64 reply_frame_len = reply->size();
1018 int64 data_header_len = spdy_util_.CreateFramer(false)
1019 ->GetDataFrameMinimumSize();
1020 int64 data_frame_len = data_header_len + kPostBodyLength;
1021 int64 response_len = reply_frame_len + data_frame_len;
1023 EXPECT_EQ(0, stream->raw_received_bytes());
1024 data.RunFor(1); // SYN
1025 EXPECT_EQ(0, stream->raw_received_bytes());
1026 data.RunFor(1); // REPLY
1027 EXPECT_EQ(reply_frame_len, stream->raw_received_bytes());
1028 data.RunFor(1); // DATA
1029 EXPECT_EQ(response_len, stream->raw_received_bytes());
1030 data.RunFor(1); // FIN
1032 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1035 } // namespace
1037 } // namespace test
1039 } // namespace net