Revert of Update WV test license server config to use portable sdk server. (https...
[chromium-blink-merge.git] / net / spdy / spdy_stream_unittest.cc
blobcc1386dab43cd1a3d2f3dffc262f9367d12b63fb
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 kPrivacyModeDisabled);
57 return CreateInsecureSpdySession(session_, key, BoundNetLog());
60 virtual void TearDown() {
61 base::MessageLoop::current()->RunUntilIdle();
64 void RunResumeAfterUnstallRequestResponseTest(
65 const UnstallFunction& unstall_function);
67 void RunResumeAfterUnstallBidirectionalTest(
68 const UnstallFunction& unstall_function);
70 // Add{Read,Write}() populates lists that are eventually passed to a
71 // SocketData class. |frame| must live for the whole test.
73 void AddRead(const SpdyFrame& frame) {
74 reads_.push_back(CreateMockRead(frame, offset_++));
77 void AddWrite(const SpdyFrame& frame) {
78 writes_.push_back(CreateMockWrite(frame, offset_++));
81 void AddReadEOF() {
82 reads_.push_back(MockRead(ASYNC, 0, offset_++));
85 MockRead* GetReads() {
86 return vector_as_array(&reads_);
89 size_t GetNumReads() const {
90 return reads_.size();
93 MockWrite* GetWrites() {
94 return vector_as_array(&writes_);
97 int GetNumWrites() const {
98 return writes_.size();
101 SpdyTestUtil spdy_util_;
102 SpdySessionDependencies session_deps_;
103 scoped_refptr<HttpNetworkSession> session_;
105 private:
106 // Used by Add{Read,Write}() above.
107 std::vector<MockWrite> writes_;
108 std::vector<MockRead> reads_;
109 int offset_;
112 INSTANTIATE_TEST_CASE_P(
113 NextProto,
114 SpdyStreamTest,
115 testing::Values(kProtoDeprecatedSPDY2,
116 kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
117 kProtoHTTP2Draft04));
119 TEST_P(SpdyStreamTest, SendDataAfterOpen) {
120 GURL url(kStreamUrl);
122 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
124 scoped_ptr<SpdyFrame> req(
125 spdy_util_.ConstructSpdyPost(
126 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
127 AddWrite(*req);
129 scoped_ptr<SpdyFrame> resp(
130 spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
131 AddRead(*resp);
133 scoped_ptr<SpdyFrame> msg(
134 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
135 AddWrite(*msg);
137 scoped_ptr<SpdyFrame> echo(
138 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
139 AddRead(*echo);
141 AddReadEOF();
143 OrderedSocketData data(GetReads(), GetNumReads(),
144 GetWrites(), GetNumWrites());
145 MockConnect connect_data(SYNCHRONOUS, OK);
146 data.set_connect_data(connect_data);
148 session_deps_.socket_factory->AddSocketDataProvider(&data);
150 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
152 base::WeakPtr<SpdyStream> stream =
153 CreateStreamSynchronously(
154 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
155 ASSERT_TRUE(stream.get() != NULL);
157 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
158 stream->SetDelegate(&delegate);
160 EXPECT_FALSE(stream->HasUrlFromHeaders());
162 scoped_ptr<SpdyHeaderBlock> headers(
163 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
164 EXPECT_EQ(ERR_IO_PENDING,
165 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
166 EXPECT_TRUE(stream->HasUrlFromHeaders());
167 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
169 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
171 EXPECT_TRUE(delegate.send_headers_completed());
172 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
173 EXPECT_EQ("HTTP/1.1",
174 delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
175 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
176 delegate.TakeReceivedData());
177 EXPECT_TRUE(data.at_write_eof());
180 TEST_P(SpdyStreamTest, PushedStream) {
181 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
183 AddReadEOF();
185 OrderedSocketData data(GetReads(), GetNumReads(),
186 GetWrites(), GetNumWrites());
187 MockConnect connect_data(SYNCHRONOUS, OK);
188 data.set_connect_data(connect_data);
190 session_deps_.socket_factory->AddSocketDataProvider(&data);
192 base::WeakPtr<SpdySession> spdy_session(CreateDefaultSpdySession());
194 // Conjure up a stream.
195 SpdyStream stream(SPDY_PUSH_STREAM,
196 spdy_session,
197 GURL(),
198 DEFAULT_PRIORITY,
199 kSpdyStreamInitialWindowSize,
200 kSpdyStreamInitialWindowSize,
201 BoundNetLog());
202 stream.set_stream_id(2);
203 EXPECT_FALSE(stream.HasUrlFromHeaders());
205 // Set a couple of headers.
206 SpdyHeaderBlock response;
207 spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &response);
208 stream.OnInitialResponseHeadersReceived(
209 response, base::Time::Now(), base::TimeTicks::Now());
211 // Send some basic headers.
212 SpdyHeaderBlock headers;
213 headers[spdy_util_.GetStatusKey()] = "200";
214 headers[spdy_util_.GetVersionKey()] = "OK";
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 base::MessageLoop::current()->RunUntilIdle();
225 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
227 EXPECT_TRUE(spdy_session == NULL);
230 TEST_P(SpdyStreamTest, StreamError) {
231 GURL url(kStreamUrl);
233 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
235 scoped_ptr<SpdyFrame> req(
236 spdy_util_.ConstructSpdyPost(
237 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
238 AddWrite(*req);
240 scoped_ptr<SpdyFrame> resp(
241 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
242 AddRead(*resp);
244 scoped_ptr<SpdyFrame> msg(
245 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
246 AddWrite(*msg);
248 scoped_ptr<SpdyFrame> echo(
249 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
250 AddRead(*echo);
252 AddReadEOF();
254 CapturingBoundNetLog log;
256 OrderedSocketData data(GetReads(), GetNumReads(),
257 GetWrites(), GetNumWrites());
258 MockConnect connect_data(SYNCHRONOUS, OK);
259 data.set_connect_data(connect_data);
261 session_deps_.socket_factory->AddSocketDataProvider(&data);
263 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
265 base::WeakPtr<SpdyStream> stream =
266 CreateStreamSynchronously(
267 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
268 ASSERT_TRUE(stream.get() != NULL);
270 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
271 stream->SetDelegate(&delegate);
273 EXPECT_FALSE(stream->HasUrlFromHeaders());
275 scoped_ptr<SpdyHeaderBlock> headers(
276 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
277 EXPECT_EQ(ERR_IO_PENDING,
278 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
279 EXPECT_TRUE(stream->HasUrlFromHeaders());
280 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
282 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
284 const SpdyStreamId stream_id = delegate.stream_id();
286 EXPECT_TRUE(delegate.send_headers_completed());
287 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
288 EXPECT_EQ("HTTP/1.1",
289 delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
290 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
291 delegate.TakeReceivedData());
292 EXPECT_TRUE(data.at_write_eof());
294 // Check that the NetLog was filled reasonably.
295 net::CapturingNetLog::CapturedEntryList entries;
296 log.GetEntries(&entries);
297 EXPECT_LT(0u, entries.size());
299 // Check that we logged SPDY_STREAM_ERROR correctly.
300 int pos = net::ExpectLogContainsSomewhere(
301 entries, 0,
302 net::NetLog::TYPE_SPDY_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_ = SpdySessionDependencies::SpdyCreateSession(&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 OrderedSocketData data(GetReads(), GetNumReads(),
341 GetWrites(), GetNumWrites());
342 MockConnect connect_data(SYNCHRONOUS, OK);
343 data.set_connect_data(connect_data);
345 session_deps_.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 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
369 EXPECT_TRUE(delegate.send_headers_completed());
370 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
371 EXPECT_EQ("HTTP/1.1",
372 delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
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_ = SpdySessionDependencies::SpdyCreateSession(&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 OrderedSocketData data(GetReads(), GetNumReads(),
404 GetWrites(), GetNumWrites());
405 MockConnect connect_data(SYNCHRONOUS, OK);
406 data.set_connect_data(connect_data);
408 session_deps_.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 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
432 EXPECT_TRUE(delegate.send_headers_completed());
433 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
434 EXPECT_EQ("HTTP/1.1",
435 delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
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 if (spdy_util_.protocol() < kProtoSPDY3)
725 return;
727 session_ =
728 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
730 scoped_ptr<SpdyFrame> req(
731 spdy_util_.ConstructSpdyPost(
732 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
733 AddWrite(*req);
735 // Triggered by the overflowing call to IncreaseSendWindowSize
736 // below.
737 scoped_ptr<SpdyFrame> rst(
738 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
739 AddWrite(*rst);
741 AddReadEOF();
743 CapturingBoundNetLog log;
745 DeterministicSocketData data(GetReads(), GetNumReads(),
746 GetWrites(), GetNumWrites());
747 MockConnect connect_data(SYNCHRONOUS, OK);
748 data.set_connect_data(connect_data);
750 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
752 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
753 GURL url(kStreamUrl);
755 base::WeakPtr<SpdyStream> stream =
756 CreateStreamSynchronously(
757 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
758 ASSERT_TRUE(stream.get() != NULL);
759 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
760 stream->SetDelegate(&delegate);
762 scoped_ptr<SpdyHeaderBlock> headers(
763 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
764 EXPECT_EQ(ERR_IO_PENDING,
765 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
766 EXPECT_TRUE(stream->HasUrlFromHeaders());
767 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
769 data.RunFor(1);
771 int32 old_send_window_size = stream->send_window_size();
772 ASSERT_GT(old_send_window_size, 0);
773 int32 delta_window_size = kint32max - old_send_window_size + 1;
774 stream->IncreaseSendWindowSize(delta_window_size);
775 EXPECT_EQ(NULL, stream.get());
777 data.RunFor(2);
779 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
782 // Functions used with
783 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
785 void StallStream(const base::WeakPtr<SpdyStream>& stream) {
786 // Reduce the send window size to 0 to stall.
787 while (stream->send_window_size() > 0) {
788 stream->DecreaseSendWindowSize(
789 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
793 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
794 int32 delta_window_size) {
795 EXPECT_TRUE(stream->send_stalled_by_flow_control());
796 stream->IncreaseSendWindowSize(delta_window_size);
797 EXPECT_FALSE(stream->send_stalled_by_flow_control());
800 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
801 int32 delta_window_size) {
802 // Make sure that negative adjustments are handled properly.
803 EXPECT_TRUE(stream->send_stalled_by_flow_control());
804 stream->AdjustSendWindowSize(-delta_window_size);
805 EXPECT_TRUE(stream->send_stalled_by_flow_control());
806 stream->AdjustSendWindowSize(+delta_window_size);
807 EXPECT_TRUE(stream->send_stalled_by_flow_control());
808 stream->AdjustSendWindowSize(+delta_window_size);
809 EXPECT_FALSE(stream->send_stalled_by_flow_control());
812 // Given an unstall function, runs a test to make sure that a
813 // request/response (i.e., an HTTP-like) stream resumes after a stall
814 // and unstall.
815 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
816 const UnstallFunction& unstall_function) {
817 GURL url(kStreamUrl);
819 session_ =
820 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
822 scoped_ptr<SpdyFrame> req(
823 spdy_util_.ConstructSpdyPost(
824 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
825 AddWrite(*req);
827 scoped_ptr<SpdyFrame> body(
828 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
829 AddWrite(*body);
831 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
832 AddRead(*resp);
834 AddReadEOF();
836 DeterministicSocketData data(GetReads(), GetNumReads(),
837 GetWrites(), GetNumWrites());
838 MockConnect connect_data(SYNCHRONOUS, OK);
839 data.set_connect_data(connect_data);
841 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
843 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
845 base::WeakPtr<SpdyStream> stream =
846 CreateStreamSynchronously(
847 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
848 ASSERT_TRUE(stream.get() != NULL);
850 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
851 stream->SetDelegate(&delegate);
853 EXPECT_FALSE(stream->HasUrlFromHeaders());
854 EXPECT_FALSE(stream->send_stalled_by_flow_control());
856 scoped_ptr<SpdyHeaderBlock> headers(
857 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
858 EXPECT_EQ(ERR_IO_PENDING,
859 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
860 EXPECT_TRUE(stream->HasUrlFromHeaders());
861 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
863 StallStream(stream);
865 data.RunFor(1);
867 EXPECT_TRUE(stream->send_stalled_by_flow_control());
869 unstall_function.Run(stream, kPostBodyLength);
871 EXPECT_FALSE(stream->send_stalled_by_flow_control());
873 data.RunFor(3);
875 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
877 EXPECT_TRUE(delegate.send_headers_completed());
878 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
879 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
880 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
881 EXPECT_TRUE(data.at_write_eof());
884 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
885 if (spdy_util_.protocol() < kProtoSPDY3)
886 return;
888 RunResumeAfterUnstallRequestResponseTest(
889 base::Bind(&IncreaseStreamSendWindowSize));
892 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
893 if (spdy_util_.protocol() < kProtoSPDY3)
894 return;
896 RunResumeAfterUnstallRequestResponseTest(
897 base::Bind(&AdjustStreamSendWindowSize));
900 // Given an unstall function, runs a test to make sure that a
901 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
902 // and unstall.
903 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
904 const UnstallFunction& unstall_function) {
905 GURL url(kStreamUrl);
907 session_ =
908 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
910 scoped_ptr<SpdyFrame> req(
911 spdy_util_.ConstructSpdyPost(
912 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
913 AddWrite(*req);
915 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
916 AddRead(*resp);
918 scoped_ptr<SpdyFrame> msg(
919 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
920 AddWrite(*msg);
922 scoped_ptr<SpdyFrame> echo(
923 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
924 AddRead(*echo);
926 AddReadEOF();
928 DeterministicSocketData data(GetReads(), GetNumReads(),
929 GetWrites(), GetNumWrites());
930 MockConnect connect_data(SYNCHRONOUS, OK);
931 data.set_connect_data(connect_data);
933 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
935 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
937 base::WeakPtr<SpdyStream> stream =
938 CreateStreamSynchronously(
939 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
940 ASSERT_TRUE(stream.get() != NULL);
942 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
943 stream->SetDelegate(&delegate);
945 EXPECT_FALSE(stream->HasUrlFromHeaders());
947 scoped_ptr<SpdyHeaderBlock> headers(
948 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
949 EXPECT_EQ(ERR_IO_PENDING,
950 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
951 EXPECT_TRUE(stream->HasUrlFromHeaders());
952 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
954 data.RunFor(1);
956 EXPECT_FALSE(stream->send_stalled_by_flow_control());
958 StallStream(stream);
960 data.RunFor(1);
962 EXPECT_TRUE(stream->send_stalled_by_flow_control());
964 unstall_function.Run(stream, kPostBodyLength);
966 EXPECT_FALSE(stream->send_stalled_by_flow_control());
968 data.RunFor(3);
970 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
972 EXPECT_TRUE(delegate.send_headers_completed());
973 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
974 EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
975 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
976 delegate.TakeReceivedData());
977 EXPECT_TRUE(data.at_write_eof());
980 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
981 if (spdy_util_.protocol() < kProtoSPDY3)
982 return;
984 RunResumeAfterUnstallBidirectionalTest(
985 base::Bind(&IncreaseStreamSendWindowSize));
988 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
989 if (spdy_util_.protocol() < kProtoSPDY3)
990 return;
992 RunResumeAfterUnstallBidirectionalTest(
993 base::Bind(&AdjustStreamSendWindowSize));
996 // Test calculation of amount of bytes received from network.
997 TEST_P(SpdyStreamTest, ReceivedBytes) {
998 GURL url(kStreamUrl);
1000 session_ =
1001 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
1003 scoped_ptr<SpdyFrame> syn(
1004 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1005 AddWrite(*syn);
1007 scoped_ptr<SpdyFrame>
1008 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1009 AddRead(*reply);
1011 scoped_ptr<SpdyFrame> msg(
1012 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
1013 AddRead(*msg);
1015 AddReadEOF();
1017 DeterministicSocketData data(GetReads(), GetNumReads(),
1018 GetWrites(), GetNumWrites());
1019 MockConnect connect_data(SYNCHRONOUS, OK);
1020 data.set_connect_data(connect_data);
1022 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1024 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
1026 base::WeakPtr<SpdyStream> stream =
1027 CreateStreamSynchronously(
1028 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
1029 ASSERT_TRUE(stream.get() != NULL);
1031 StreamDelegateDoNothing delegate(stream);
1032 stream->SetDelegate(&delegate);
1034 EXPECT_FALSE(stream->HasUrlFromHeaders());
1036 scoped_ptr<SpdyHeaderBlock> headers(
1037 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
1038 EXPECT_EQ(ERR_IO_PENDING,
1039 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
1040 EXPECT_TRUE(stream->HasUrlFromHeaders());
1041 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
1043 int64 reply_frame_len = reply->size();
1044 int64 data_header_len = spdy_util_.CreateFramer()->GetDataFrameMinimumSize();
1045 int64 data_frame_len = data_header_len + kPostBodyLength;
1046 int64 response_len = reply_frame_len + data_frame_len;
1048 EXPECT_EQ(0, stream->raw_received_bytes());
1049 data.RunFor(1); // SYN
1050 EXPECT_EQ(0, stream->raw_received_bytes());
1051 data.RunFor(1); // REPLY
1052 EXPECT_EQ(reply_frame_len, stream->raw_received_bytes());
1053 data.RunFor(1); // DATA
1054 EXPECT_EQ(response_len, stream->raw_received_bytes());
1055 data.RunFor(1); // FIN
1057 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1060 } // namespace
1062 } // namespace test
1064 } // namespace net