Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / net / spdy / spdy_stream_unittest.cc
blob3dbe0b17d151f14348cb44124e3eaffa29814c27
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 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 = ExpectLogContainsSomewhere(
302 entries, 0, NetLog::TYPE_HTTP2_STREAM_ERROR, NetLog::PHASE_NONE);
304 int stream_id2;
305 ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2));
306 EXPECT_EQ(static_cast<int>(stream_id), stream_id2);
309 // Make sure that large blocks of data are properly split up into
310 // frame-sized chunks for a request/response (i.e., an HTTP-like)
311 // stream.
312 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
313 GURL url(kStreamUrl);
315 session_ =
316 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
318 scoped_ptr<SpdyFrame> req(
319 spdy_util_.ConstructSpdyPost(
320 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
321 AddWrite(*req);
323 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
324 scoped_ptr<SpdyFrame> chunk(
325 spdy_util_.ConstructSpdyBodyFrame(
326 1, chunk_data.data(), chunk_data.length(), false));
327 AddWrite(*chunk);
328 AddWrite(*chunk);
330 scoped_ptr<SpdyFrame> last_chunk(
331 spdy_util_.ConstructSpdyBodyFrame(
332 1, chunk_data.data(), chunk_data.length(), true));
333 AddWrite(*last_chunk);
335 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
336 AddRead(*resp);
338 AddReadEOF();
340 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
341 GetNumWrites());
342 MockConnect connect_data(SYNCHRONOUS, OK);
343 data.set_connect_data(connect_data);
345 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
347 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
349 base::WeakPtr<SpdyStream> stream =
350 CreateStreamSynchronously(
351 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
352 ASSERT_TRUE(stream.get() != NULL);
354 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
355 StreamDelegateWithBody delegate(stream, body_data);
356 stream->SetDelegate(&delegate);
358 EXPECT_FALSE(stream->HasUrlFromHeaders());
360 scoped_ptr<SpdyHeaderBlock> headers(
361 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
362 EXPECT_EQ(ERR_IO_PENDING,
363 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
364 EXPECT_TRUE(stream->HasUrlFromHeaders());
365 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
367 data.RunFor(GetNumReads() + GetNumWrites());
368 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
370 EXPECT_TRUE(delegate.send_headers_completed());
371 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
372 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
373 EXPECT_TRUE(data.at_write_eof());
376 // Make sure that large blocks of data are properly split up into
377 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
378 // stream.
379 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
380 GURL url(kStreamUrl);
382 session_ =
383 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
385 scoped_ptr<SpdyFrame> req(
386 spdy_util_.ConstructSpdyPost(
387 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
388 AddWrite(*req);
390 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
391 AddRead(*resp);
393 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
394 scoped_ptr<SpdyFrame> chunk(
395 spdy_util_.ConstructSpdyBodyFrame(
396 1, chunk_data.data(), chunk_data.length(), false));
397 AddWrite(*chunk);
398 AddWrite(*chunk);
399 AddWrite(*chunk);
401 AddReadEOF();
403 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
404 GetNumWrites());
405 MockConnect connect_data(SYNCHRONOUS, OK);
406 data.set_connect_data(connect_data);
408 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
410 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
412 base::WeakPtr<SpdyStream> stream =
413 CreateStreamSynchronously(
414 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
415 ASSERT_TRUE(stream.get() != NULL);
417 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
418 StreamDelegateSendImmediate delegate(stream, body_data);
419 stream->SetDelegate(&delegate);
421 EXPECT_FALSE(stream->HasUrlFromHeaders());
423 scoped_ptr<SpdyHeaderBlock> headers(
424 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
425 EXPECT_EQ(ERR_IO_PENDING,
426 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
427 EXPECT_TRUE(stream->HasUrlFromHeaders());
428 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
430 data.RunFor(GetNumReads() + GetNumWrites());
431 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
433 EXPECT_TRUE(delegate.send_headers_completed());
434 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
435 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
436 EXPECT_TRUE(data.at_write_eof());
439 // Receiving a header with uppercase ASCII should result in a protocol
440 // error.
441 TEST_P(SpdyStreamTest, UpperCaseHeaders) {
442 GURL url(kStreamUrl);
444 session_ =
445 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
447 scoped_ptr<SpdyFrame> syn(
448 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
449 AddWrite(*syn);
451 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
452 scoped_ptr<SpdyFrame>
453 reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
454 AddRead(*reply);
456 scoped_ptr<SpdyFrame> rst(
457 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
458 AddWrite(*rst);
460 AddReadEOF();
462 DeterministicSocketData data(GetReads(), GetNumReads(),
463 GetWrites(), GetNumWrites());
464 MockConnect connect_data(SYNCHRONOUS, OK);
465 data.set_connect_data(connect_data);
467 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
469 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
471 base::WeakPtr<SpdyStream> stream =
472 CreateStreamSynchronously(
473 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
474 ASSERT_TRUE(stream.get() != NULL);
476 StreamDelegateDoNothing delegate(stream);
477 stream->SetDelegate(&delegate);
479 EXPECT_FALSE(stream->HasUrlFromHeaders());
481 scoped_ptr<SpdyHeaderBlock> headers(
482 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
483 EXPECT_EQ(ERR_IO_PENDING,
484 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
485 EXPECT_TRUE(stream->HasUrlFromHeaders());
486 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
488 data.RunFor(4);
490 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
493 // Receiving a header with uppercase ASCII should result in a protocol
494 // error even for a push stream.
495 TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
496 GURL url(kStreamUrl);
498 session_ =
499 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
501 scoped_ptr<SpdyFrame> syn(
502 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
503 AddWrite(*syn);
505 scoped_ptr<SpdyFrame>
506 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
507 AddRead(*reply);
509 const char* const extra_headers[] = {"X-UpperCase", "yes"};
510 scoped_ptr<SpdyFrame>
511 push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
512 AddRead(*push);
514 scoped_ptr<SpdyFrame> rst(
515 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
516 AddWrite(*rst);
518 AddReadEOF();
520 DeterministicSocketData data(GetReads(), GetNumReads(),
521 GetWrites(), GetNumWrites());
522 MockConnect connect_data(SYNCHRONOUS, OK);
523 data.set_connect_data(connect_data);
525 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
527 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
529 base::WeakPtr<SpdyStream> stream =
530 CreateStreamSynchronously(
531 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
532 ASSERT_TRUE(stream.get() != NULL);
534 StreamDelegateDoNothing delegate(stream);
535 stream->SetDelegate(&delegate);
537 EXPECT_FALSE(stream->HasUrlFromHeaders());
539 scoped_ptr<SpdyHeaderBlock> headers(
540 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
541 EXPECT_EQ(ERR_IO_PENDING,
542 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
543 EXPECT_TRUE(stream->HasUrlFromHeaders());
544 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
546 data.RunFor(4);
548 base::WeakPtr<SpdyStream> push_stream;
549 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
550 EXPECT_FALSE(push_stream);
552 data.RunFor(1);
554 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
557 // Receiving a header with uppercase ASCII in a HEADERS frame should
558 // result in a protocol error.
559 TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
560 GURL url(kStreamUrl);
562 session_ =
563 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
565 scoped_ptr<SpdyFrame> syn(
566 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
567 AddWrite(*syn);
569 scoped_ptr<SpdyFrame>
570 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
571 AddRead(*reply);
573 scoped_ptr<SpdyFrame>
574 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
575 AddRead(*push);
577 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
578 (*late_headers)["X-UpperCase"] = "yes";
579 scoped_ptr<SpdyFrame> headers_frame(
580 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
581 false,
583 LOWEST,
584 HEADERS,
585 CONTROL_FLAG_NONE,
586 0));
587 AddRead(*headers_frame);
589 scoped_ptr<SpdyFrame> rst(
590 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
591 AddWrite(*rst);
593 AddReadEOF();
595 DeterministicSocketData data(GetReads(), GetNumReads(),
596 GetWrites(), GetNumWrites());
597 MockConnect connect_data(SYNCHRONOUS, OK);
598 data.set_connect_data(connect_data);
600 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
602 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
604 base::WeakPtr<SpdyStream> stream =
605 CreateStreamSynchronously(
606 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
607 ASSERT_TRUE(stream.get() != NULL);
609 StreamDelegateDoNothing delegate(stream);
610 stream->SetDelegate(&delegate);
612 EXPECT_FALSE(stream->HasUrlFromHeaders());
614 scoped_ptr<SpdyHeaderBlock> headers(
615 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
616 EXPECT_EQ(ERR_IO_PENDING,
617 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
618 EXPECT_TRUE(stream->HasUrlFromHeaders());
619 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
621 data.RunFor(3);
623 base::WeakPtr<SpdyStream> push_stream;
624 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
625 EXPECT_TRUE(push_stream);
627 data.RunFor(1);
629 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
630 EXPECT_FALSE(push_stream);
632 data.RunFor(2);
634 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
637 // Receiving a duplicate header in a HEADERS frame should result in a
638 // protocol error.
639 TEST_P(SpdyStreamTest, DuplicateHeaders) {
640 GURL url(kStreamUrl);
642 session_ =
643 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
645 scoped_ptr<SpdyFrame> syn(
646 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
647 AddWrite(*syn);
649 scoped_ptr<SpdyFrame>
650 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
651 AddRead(*reply);
653 scoped_ptr<SpdyFrame>
654 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
655 AddRead(*push);
657 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
658 (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error";
659 scoped_ptr<SpdyFrame> headers_frame(
660 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
661 false,
663 LOWEST,
664 HEADERS,
665 CONTROL_FLAG_NONE,
666 0));
667 AddRead(*headers_frame);
669 scoped_ptr<SpdyFrame> rst(
670 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
671 AddWrite(*rst);
673 AddReadEOF();
675 DeterministicSocketData data(GetReads(), GetNumReads(),
676 GetWrites(), GetNumWrites());
677 MockConnect connect_data(SYNCHRONOUS, OK);
678 data.set_connect_data(connect_data);
680 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
682 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
684 base::WeakPtr<SpdyStream> stream =
685 CreateStreamSynchronously(
686 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
687 ASSERT_TRUE(stream.get() != NULL);
689 StreamDelegateDoNothing delegate(stream);
690 stream->SetDelegate(&delegate);
692 EXPECT_FALSE(stream->HasUrlFromHeaders());
694 scoped_ptr<SpdyHeaderBlock> headers(
695 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
696 EXPECT_EQ(ERR_IO_PENDING,
697 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
698 EXPECT_TRUE(stream->HasUrlFromHeaders());
699 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
701 data.RunFor(3);
703 base::WeakPtr<SpdyStream> push_stream;
704 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
705 EXPECT_TRUE(push_stream);
707 data.RunFor(1);
709 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
710 EXPECT_FALSE(push_stream);
712 data.RunFor(2);
714 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
717 // The tests below are only for SPDY/3 and above.
719 // Call IncreaseSendWindowSize on a stream with a large enough delta
720 // to overflow an int32. The SpdyStream should handle that case
721 // gracefully.
722 TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
723 session_ =
724 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
726 scoped_ptr<SpdyFrame> req(
727 spdy_util_.ConstructSpdyPost(
728 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
729 AddWrite(*req);
731 // Triggered by the overflowing call to IncreaseSendWindowSize
732 // below.
733 scoped_ptr<SpdyFrame> rst(
734 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
735 AddWrite(*rst);
737 AddReadEOF();
739 BoundTestNetLog log;
741 DeterministicSocketData data(GetReads(), GetNumReads(),
742 GetWrites(), GetNumWrites());
743 MockConnect connect_data(SYNCHRONOUS, OK);
744 data.set_connect_data(connect_data);
746 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
748 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
749 GURL url(kStreamUrl);
751 base::WeakPtr<SpdyStream> stream =
752 CreateStreamSynchronously(
753 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
754 ASSERT_TRUE(stream.get() != NULL);
755 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
756 stream->SetDelegate(&delegate);
758 scoped_ptr<SpdyHeaderBlock> headers(
759 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
760 EXPECT_EQ(ERR_IO_PENDING,
761 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
762 EXPECT_TRUE(stream->HasUrlFromHeaders());
763 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
765 data.RunFor(1);
767 int32 old_send_window_size = stream->send_window_size();
768 ASSERT_GT(old_send_window_size, 0);
769 int32 delta_window_size = kint32max - old_send_window_size + 1;
770 stream->IncreaseSendWindowSize(delta_window_size);
771 EXPECT_EQ(NULL, stream.get());
773 data.RunFor(2);
775 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
778 // Functions used with
779 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
781 void StallStream(const base::WeakPtr<SpdyStream>& stream) {
782 // Reduce the send window size to 0 to stall.
783 while (stream->send_window_size() > 0) {
784 stream->DecreaseSendWindowSize(
785 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
789 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
790 int32 delta_window_size) {
791 EXPECT_TRUE(stream->send_stalled_by_flow_control());
792 stream->IncreaseSendWindowSize(delta_window_size);
793 EXPECT_FALSE(stream->send_stalled_by_flow_control());
796 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
797 int32 delta_window_size) {
798 // Make sure that negative adjustments are handled properly.
799 EXPECT_TRUE(stream->send_stalled_by_flow_control());
800 stream->AdjustSendWindowSize(-delta_window_size);
801 EXPECT_TRUE(stream->send_stalled_by_flow_control());
802 stream->AdjustSendWindowSize(+delta_window_size);
803 EXPECT_TRUE(stream->send_stalled_by_flow_control());
804 stream->AdjustSendWindowSize(+delta_window_size);
805 EXPECT_FALSE(stream->send_stalled_by_flow_control());
808 // Given an unstall function, runs a test to make sure that a
809 // request/response (i.e., an HTTP-like) stream resumes after a stall
810 // and unstall.
811 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
812 const UnstallFunction& unstall_function) {
813 GURL url(kStreamUrl);
815 session_ =
816 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
818 scoped_ptr<SpdyFrame> req(
819 spdy_util_.ConstructSpdyPost(
820 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
821 AddWrite(*req);
823 scoped_ptr<SpdyFrame> body(
824 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
825 AddWrite(*body);
827 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
828 AddRead(*resp);
830 AddReadEOF();
832 DeterministicSocketData data(GetReads(), GetNumReads(),
833 GetWrites(), GetNumWrites());
834 MockConnect connect_data(SYNCHRONOUS, OK);
835 data.set_connect_data(connect_data);
837 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
839 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
841 base::WeakPtr<SpdyStream> stream =
842 CreateStreamSynchronously(
843 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
844 ASSERT_TRUE(stream.get() != NULL);
846 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
847 stream->SetDelegate(&delegate);
849 EXPECT_FALSE(stream->HasUrlFromHeaders());
850 EXPECT_FALSE(stream->send_stalled_by_flow_control());
852 scoped_ptr<SpdyHeaderBlock> headers(
853 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
854 EXPECT_EQ(ERR_IO_PENDING,
855 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
856 EXPECT_TRUE(stream->HasUrlFromHeaders());
857 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
859 StallStream(stream);
861 data.RunFor(1);
863 EXPECT_TRUE(stream->send_stalled_by_flow_control());
865 unstall_function.Run(stream, kPostBodyLength);
867 EXPECT_FALSE(stream->send_stalled_by_flow_control());
869 data.RunFor(3);
871 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
873 EXPECT_TRUE(delegate.send_headers_completed());
874 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
875 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
876 EXPECT_TRUE(data.at_write_eof());
879 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
880 RunResumeAfterUnstallRequestResponseTest(
881 base::Bind(&IncreaseStreamSendWindowSize));
884 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
885 RunResumeAfterUnstallRequestResponseTest(
886 base::Bind(&AdjustStreamSendWindowSize));
889 // Given an unstall function, runs a test to make sure that a
890 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
891 // and unstall.
892 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
893 const UnstallFunction& unstall_function) {
894 GURL url(kStreamUrl);
896 session_ =
897 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
899 scoped_ptr<SpdyFrame> req(
900 spdy_util_.ConstructSpdyPost(
901 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
902 AddWrite(*req);
904 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
905 AddRead(*resp);
907 scoped_ptr<SpdyFrame> msg(
908 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
909 AddWrite(*msg);
911 scoped_ptr<SpdyFrame> echo(
912 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
913 AddRead(*echo);
915 AddReadEOF();
917 DeterministicSocketData data(GetReads(), GetNumReads(),
918 GetWrites(), GetNumWrites());
919 MockConnect connect_data(SYNCHRONOUS, OK);
920 data.set_connect_data(connect_data);
922 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
924 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
926 base::WeakPtr<SpdyStream> stream =
927 CreateStreamSynchronously(
928 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
929 ASSERT_TRUE(stream.get() != NULL);
931 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
932 stream->SetDelegate(&delegate);
934 EXPECT_FALSE(stream->HasUrlFromHeaders());
936 scoped_ptr<SpdyHeaderBlock> headers(
937 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
938 EXPECT_EQ(ERR_IO_PENDING,
939 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
940 EXPECT_TRUE(stream->HasUrlFromHeaders());
941 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
943 data.RunFor(1);
945 EXPECT_FALSE(stream->send_stalled_by_flow_control());
947 StallStream(stream);
949 data.RunFor(1);
951 EXPECT_TRUE(stream->send_stalled_by_flow_control());
953 unstall_function.Run(stream, kPostBodyLength);
955 EXPECT_FALSE(stream->send_stalled_by_flow_control());
957 data.RunFor(3);
959 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
961 EXPECT_TRUE(delegate.send_headers_completed());
962 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
963 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
964 delegate.TakeReceivedData());
965 EXPECT_TRUE(data.at_write_eof());
968 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
969 RunResumeAfterUnstallBidirectionalTest(
970 base::Bind(&IncreaseStreamSendWindowSize));
973 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
974 RunResumeAfterUnstallBidirectionalTest(
975 base::Bind(&AdjustStreamSendWindowSize));
978 // Test calculation of amount of bytes received from network.
979 TEST_P(SpdyStreamTest, ReceivedBytes) {
980 GURL url(kStreamUrl);
982 session_ =
983 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
985 scoped_ptr<SpdyFrame> syn(
986 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
987 AddWrite(*syn);
989 scoped_ptr<SpdyFrame>
990 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
991 AddRead(*reply);
993 scoped_ptr<SpdyFrame> msg(
994 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
995 AddRead(*msg);
997 AddReadEOF();
999 DeterministicSocketData data(GetReads(), GetNumReads(),
1000 GetWrites(), GetNumWrites());
1001 MockConnect connect_data(SYNCHRONOUS, OK);
1002 data.set_connect_data(connect_data);
1004 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1006 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
1008 base::WeakPtr<SpdyStream> stream =
1009 CreateStreamSynchronously(
1010 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
1011 ASSERT_TRUE(stream.get() != NULL);
1013 StreamDelegateDoNothing delegate(stream);
1014 stream->SetDelegate(&delegate);
1016 EXPECT_FALSE(stream->HasUrlFromHeaders());
1018 scoped_ptr<SpdyHeaderBlock> headers(
1019 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
1020 EXPECT_EQ(ERR_IO_PENDING,
1021 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
1022 EXPECT_TRUE(stream->HasUrlFromHeaders());
1023 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
1025 int64 reply_frame_len = reply->size();
1026 int64 data_header_len = spdy_util_.CreateFramer(false)
1027 ->GetDataFrameMinimumSize();
1028 int64 data_frame_len = data_header_len + kPostBodyLength;
1029 int64 response_len = reply_frame_len + data_frame_len;
1031 EXPECT_EQ(0, stream->raw_received_bytes());
1032 data.RunFor(1); // SYN
1033 EXPECT_EQ(0, stream->raw_received_bytes());
1034 data.RunFor(1); // REPLY
1035 EXPECT_EQ(reply_frame_len, stream->raw_received_bytes());
1036 data.RunFor(1); // DATA
1037 EXPECT_EQ(response_len, stream->raw_received_bytes());
1038 data.RunFor(1); // FIN
1040 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1043 } // namespace
1045 } // namespace test
1047 } // namespace net