Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / spdy / spdy_stream_unittest.cc
blob044be4bd238561d48eb8451fcbb8a9be95bb71fe
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/test_net_log.h"
16 #include "net/log/test_net_log_entry.h"
17 #include "net/log/test_net_log_util.h"
18 #include "net/socket/next_proto.h"
19 #include "net/socket/socket_test_util.h"
20 #include "net/spdy/buffered_spdy_framer.h"
21 #include "net/spdy/spdy_http_utils.h"
22 #include "net/spdy/spdy_protocol.h"
23 #include "net/spdy/spdy_session.h"
24 #include "net/spdy/spdy_stream.h"
25 #include "net/spdy/spdy_stream_test_util.h"
26 #include "net/spdy/spdy_test_util_common.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
31 namespace net {
33 namespace test {
35 namespace {
37 const char kStreamUrl[] = "http://www.example.org/";
38 const char kPostBody[] = "\0hello!\xff";
39 const size_t kPostBodyLength = arraysize(kPostBody);
40 const base::StringPiece kPostBodyStringPiece(kPostBody, kPostBodyLength);
42 class SpdyStreamTest : public ::testing::Test,
43 public ::testing::WithParamInterface<NextProto> {
44 protected:
45 // A function that takes a SpdyStream and the number of bytes which
46 // will unstall the next frame completely.
47 typedef base::Callback<void(const base::WeakPtr<SpdyStream>&, int32)>
48 UnstallFunction;
50 SpdyStreamTest()
51 : spdy_util_(GetParam()),
52 session_deps_(GetParam()),
53 offset_(0) {}
55 base::WeakPtr<SpdySession> CreateDefaultSpdySession() {
56 SpdySessionKey key(HostPortPair("www.example.org", 80),
57 ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
58 return CreateInsecureSpdySession(session_, key, BoundNetLog());
61 void TearDown() override { base::MessageLoop::current()->RunUntilIdle(); }
63 void RunResumeAfterUnstallRequestResponseTest(
64 const UnstallFunction& unstall_function);
66 void RunResumeAfterUnstallBidirectionalTest(
67 const UnstallFunction& unstall_function);
69 // Add{Read,Write}() populates lists that are eventually passed to a
70 // SocketData class. |frame| must live for the whole test.
72 void AddRead(const SpdyFrame& frame) {
73 reads_.push_back(CreateMockRead(frame, offset_++));
76 void AddWrite(const SpdyFrame& frame) {
77 writes_.push_back(CreateMockWrite(frame, offset_++));
80 void AddReadEOF() {
81 reads_.push_back(MockRead(ASYNC, 0, offset_++));
84 MockRead* GetReads() {
85 return vector_as_array(&reads_);
88 size_t GetNumReads() const {
89 return reads_.size();
92 MockWrite* GetWrites() {
93 return vector_as_array(&writes_);
96 int GetNumWrites() const {
97 return writes_.size();
100 SpdyTestUtil spdy_util_;
101 SpdySessionDependencies session_deps_;
102 scoped_refptr<HttpNetworkSession> session_;
104 private:
105 // Used by Add{Read,Write}() above.
106 std::vector<MockWrite> writes_;
107 std::vector<MockRead> reads_;
108 int offset_;
111 INSTANTIATE_TEST_CASE_P(NextProto,
112 SpdyStreamTest,
113 testing::Values(kProtoSPDY31,
114 kProtoHTTP2));
116 TEST_P(SpdyStreamTest, SendDataAfterOpen) {
117 GURL url(kStreamUrl);
119 session_ =
120 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
122 scoped_ptr<SpdyFrame> req(
123 spdy_util_.ConstructSpdyPost(
124 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
125 AddWrite(*req);
127 scoped_ptr<SpdyFrame> resp(
128 spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
129 AddRead(*resp);
131 scoped_ptr<SpdyFrame> msg(
132 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
133 AddWrite(*msg);
135 scoped_ptr<SpdyFrame> echo(
136 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
137 AddRead(*echo);
139 AddReadEOF();
141 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
142 GetNumWrites());
143 MockConnect connect_data(SYNCHRONOUS, OK);
144 data.set_connect_data(connect_data);
146 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
148 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
150 base::WeakPtr<SpdyStream> stream =
151 CreateStreamSynchronously(
152 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
153 ASSERT_TRUE(stream.get() != NULL);
155 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
156 stream->SetDelegate(&delegate);
158 EXPECT_FALSE(stream->HasUrlFromHeaders());
160 scoped_ptr<SpdyHeaderBlock> headers(
161 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
162 EXPECT_EQ(ERR_IO_PENDING,
163 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
164 EXPECT_TRUE(stream->HasUrlFromHeaders());
165 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
167 data.RunFor(GetNumReads() + GetNumWrites());
168 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
170 EXPECT_TRUE(delegate.send_headers_completed());
171 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
172 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
173 delegate.TakeReceivedData());
174 EXPECT_TRUE(data.AllWriteDataConsumed());
177 // Delegate that receives trailers.
178 class StreamDelegateWithTrailers : public test::StreamDelegateWithBody {
179 public:
180 StreamDelegateWithTrailers(const base::WeakPtr<SpdyStream>& stream,
181 base::StringPiece data)
182 : StreamDelegateWithBody(stream, data) {}
184 ~StreamDelegateWithTrailers() override {}
186 void OnTrailers(const SpdyHeaderBlock& trailers) override {
187 trailers_ = trailers;
190 const SpdyHeaderBlock& trailers() const { return trailers_; }
192 private:
193 SpdyHeaderBlock trailers_;
196 // Regression test for crbug.com/481033.
197 TEST_P(SpdyStreamTest, Trailers) {
198 GURL url(kStreamUrl);
200 session_ =
201 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
203 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
204 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
205 AddWrite(*req);
207 scoped_ptr<SpdyFrame> msg(
208 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
209 AddWrite(*msg);
211 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
212 AddRead(*resp);
214 scoped_ptr<SpdyFrame> echo(
215 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
216 AddRead(*echo);
218 const char* const kExtraHeaders[] = {"foo", "bar"};
219 scoped_ptr<SpdyFrame> trailers(
220 spdy_util_.ConstructSpdyHeaderFrame(1, kExtraHeaders, 1));
221 AddRead(*trailers);
223 AddReadEOF();
225 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
226 GetNumWrites());
227 MockConnect connect_data(SYNCHRONOUS, OK);
228 data.set_connect_data(connect_data);
230 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
232 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
234 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
235 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
236 ASSERT_TRUE(stream.get() != NULL);
238 StreamDelegateWithTrailers delegate(stream, kPostBodyStringPiece);
239 stream->SetDelegate(&delegate);
241 EXPECT_FALSE(stream->HasUrlFromHeaders());
243 scoped_ptr<SpdyHeaderBlock> headers(
244 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
245 EXPECT_EQ(ERR_IO_PENDING,
246 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
247 EXPECT_TRUE(stream->HasUrlFromHeaders());
248 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
250 data.RunFor(GetNumReads() + GetNumWrites());
251 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
253 EXPECT_TRUE(delegate.send_headers_completed());
254 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
255 const SpdyHeaderBlock& received_trailers = delegate.trailers();
256 SpdyHeaderBlock::const_iterator it = received_trailers.find("foo");
257 EXPECT_EQ("bar", it->second);
258 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
259 delegate.TakeReceivedData());
260 EXPECT_TRUE(data.AllWriteDataConsumed());
263 TEST_P(SpdyStreamTest, PushedStream) {
264 session_ =
265 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
267 AddReadEOF();
269 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
270 GetNumWrites());
271 MockConnect connect_data(SYNCHRONOUS, OK);
272 data.set_connect_data(connect_data);
274 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
276 base::WeakPtr<SpdySession> spdy_session(CreateDefaultSpdySession());
278 // Conjure up a stream.
279 SpdyStream stream(SPDY_PUSH_STREAM, spdy_session, GURL(), DEFAULT_PRIORITY,
280 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31),
281 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31),
282 BoundNetLog());
283 stream.set_stream_id(2);
284 EXPECT_FALSE(stream.HasUrlFromHeaders());
286 // Set required request headers.
287 SpdyHeaderBlock request_headers;
288 spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &request_headers);
289 stream.OnPushPromiseHeadersReceived(request_headers);
291 // Send some basic response headers.
292 SpdyHeaderBlock response;
293 response[spdy_util_.GetStatusKey()] = "200";
294 response[spdy_util_.GetVersionKey()] = "OK";
295 stream.OnInitialResponseHeadersReceived(
296 response, base::Time::Now(), base::TimeTicks::Now());
298 // And some more headers.
299 // TODO(baranovich): not valid for HTTP 2.
300 SpdyHeaderBlock headers;
301 headers["alpha"] = "beta";
302 stream.OnAdditionalResponseHeadersReceived(headers);
304 EXPECT_TRUE(stream.HasUrlFromHeaders());
305 EXPECT_EQ(kStreamUrl, stream.GetUrlFromHeaders().spec());
307 StreamDelegateDoNothing delegate(stream.GetWeakPtr());
308 stream.SetDelegate(&delegate);
310 data.RunFor(GetNumReads() + GetNumWrites());
312 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
313 EXPECT_EQ("beta", delegate.GetResponseHeaderValue("alpha"));
315 EXPECT_TRUE(spdy_session == NULL);
318 TEST_P(SpdyStreamTest, StreamError) {
319 GURL url(kStreamUrl);
321 session_ =
322 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
324 scoped_ptr<SpdyFrame> req(
325 spdy_util_.ConstructSpdyPost(
326 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
327 AddWrite(*req);
329 scoped_ptr<SpdyFrame> resp(
330 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
331 AddRead(*resp);
333 scoped_ptr<SpdyFrame> msg(
334 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
335 AddWrite(*msg);
337 scoped_ptr<SpdyFrame> echo(
338 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
339 AddRead(*echo);
341 AddReadEOF();
343 BoundTestNetLog log;
345 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
346 GetNumWrites());
347 MockConnect connect_data(SYNCHRONOUS, OK);
348 data.set_connect_data(connect_data);
350 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
352 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
354 base::WeakPtr<SpdyStream> stream =
355 CreateStreamSynchronously(
356 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
357 ASSERT_TRUE(stream.get() != NULL);
359 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
360 stream->SetDelegate(&delegate);
362 EXPECT_FALSE(stream->HasUrlFromHeaders());
364 scoped_ptr<SpdyHeaderBlock> headers(
365 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
366 EXPECT_EQ(ERR_IO_PENDING,
367 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
368 EXPECT_TRUE(stream->HasUrlFromHeaders());
369 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
371 data.RunFor(GetNumReads() + GetNumWrites());
372 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
374 const SpdyStreamId stream_id = delegate.stream_id();
376 EXPECT_TRUE(delegate.send_headers_completed());
377 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
378 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
379 delegate.TakeReceivedData());
380 EXPECT_TRUE(data.AllWriteDataConsumed());
382 // Check that the NetLog was filled reasonably.
383 TestNetLogEntry::List entries;
384 log.GetEntries(&entries);
385 EXPECT_LT(0u, entries.size());
387 // Check that we logged SPDY_STREAM_ERROR correctly.
388 int pos = ExpectLogContainsSomewhere(
389 entries, 0, NetLog::TYPE_HTTP2_STREAM_ERROR, NetLog::PHASE_NONE);
391 int stream_id2;
392 ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2));
393 EXPECT_EQ(static_cast<int>(stream_id), stream_id2);
396 // Make sure that large blocks of data are properly split up into
397 // frame-sized chunks for a request/response (i.e., an HTTP-like)
398 // stream.
399 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
400 GURL url(kStreamUrl);
402 session_ =
403 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
405 scoped_ptr<SpdyFrame> req(
406 spdy_util_.ConstructSpdyPost(
407 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
408 AddWrite(*req);
410 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
411 scoped_ptr<SpdyFrame> chunk(
412 spdy_util_.ConstructSpdyBodyFrame(
413 1, chunk_data.data(), chunk_data.length(), false));
414 AddWrite(*chunk);
415 AddWrite(*chunk);
417 scoped_ptr<SpdyFrame> last_chunk(
418 spdy_util_.ConstructSpdyBodyFrame(
419 1, chunk_data.data(), chunk_data.length(), true));
420 AddWrite(*last_chunk);
422 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
423 AddRead(*resp);
425 AddReadEOF();
427 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
428 GetNumWrites());
429 MockConnect connect_data(SYNCHRONOUS, OK);
430 data.set_connect_data(connect_data);
432 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
434 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
436 base::WeakPtr<SpdyStream> stream =
437 CreateStreamSynchronously(
438 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
439 ASSERT_TRUE(stream.get() != NULL);
441 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
442 StreamDelegateWithBody delegate(stream, body_data);
443 stream->SetDelegate(&delegate);
445 EXPECT_FALSE(stream->HasUrlFromHeaders());
447 scoped_ptr<SpdyHeaderBlock> headers(
448 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
449 EXPECT_EQ(ERR_IO_PENDING,
450 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
451 EXPECT_TRUE(stream->HasUrlFromHeaders());
452 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
454 data.RunFor(GetNumReads() + GetNumWrites());
455 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
457 EXPECT_TRUE(delegate.send_headers_completed());
458 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
459 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
460 EXPECT_TRUE(data.AllWriteDataConsumed());
463 // Make sure that large blocks of data are properly split up into
464 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
465 // stream.
466 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
467 GURL url(kStreamUrl);
469 session_ =
470 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
472 scoped_ptr<SpdyFrame> req(
473 spdy_util_.ConstructSpdyPost(
474 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
475 AddWrite(*req);
477 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
478 AddRead(*resp);
480 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
481 scoped_ptr<SpdyFrame> chunk(
482 spdy_util_.ConstructSpdyBodyFrame(
483 1, chunk_data.data(), chunk_data.length(), false));
484 AddWrite(*chunk);
485 AddWrite(*chunk);
486 AddWrite(*chunk);
488 AddReadEOF();
490 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
491 GetNumWrites());
492 MockConnect connect_data(SYNCHRONOUS, OK);
493 data.set_connect_data(connect_data);
495 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
497 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
499 base::WeakPtr<SpdyStream> stream =
500 CreateStreamSynchronously(
501 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
502 ASSERT_TRUE(stream.get() != NULL);
504 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
505 StreamDelegateSendImmediate delegate(stream, body_data);
506 stream->SetDelegate(&delegate);
508 EXPECT_FALSE(stream->HasUrlFromHeaders());
510 scoped_ptr<SpdyHeaderBlock> headers(
511 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
512 EXPECT_EQ(ERR_IO_PENDING,
513 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
514 EXPECT_TRUE(stream->HasUrlFromHeaders());
515 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
517 data.RunFor(GetNumReads() + GetNumWrites());
518 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
520 EXPECT_TRUE(delegate.send_headers_completed());
521 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
522 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
523 EXPECT_TRUE(data.AllWriteDataConsumed());
526 // Receiving a header with uppercase ASCII should result in a protocol
527 // error.
528 TEST_P(SpdyStreamTest, UpperCaseHeaders) {
529 GURL url(kStreamUrl);
531 session_ =
532 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
534 scoped_ptr<SpdyFrame> syn(
535 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
536 AddWrite(*syn);
538 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
539 scoped_ptr<SpdyFrame>
540 reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
541 AddRead(*reply);
543 scoped_ptr<SpdyFrame> rst(
544 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
545 AddWrite(*rst);
547 AddReadEOF();
549 DeterministicSocketData data(GetReads(), GetNumReads(),
550 GetWrites(), GetNumWrites());
551 MockConnect connect_data(SYNCHRONOUS, OK);
552 data.set_connect_data(connect_data);
554 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
556 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
558 base::WeakPtr<SpdyStream> stream =
559 CreateStreamSynchronously(
560 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
561 ASSERT_TRUE(stream.get() != NULL);
563 StreamDelegateDoNothing delegate(stream);
564 stream->SetDelegate(&delegate);
566 EXPECT_FALSE(stream->HasUrlFromHeaders());
568 scoped_ptr<SpdyHeaderBlock> headers(
569 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
570 EXPECT_EQ(ERR_IO_PENDING,
571 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
572 EXPECT_TRUE(stream->HasUrlFromHeaders());
573 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
575 data.RunFor(4);
577 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
580 // Receiving a header with uppercase ASCII should result in a protocol
581 // error even for a push stream.
582 TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
583 GURL url(kStreamUrl);
585 session_ =
586 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
588 scoped_ptr<SpdyFrame> syn(
589 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
590 AddWrite(*syn);
592 scoped_ptr<SpdyFrame>
593 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
594 AddRead(*reply);
596 const char* const extra_headers[] = {"X-UpperCase", "yes"};
597 scoped_ptr<SpdyFrame>
598 push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
599 AddRead(*push);
601 scoped_ptr<SpdyFrame> rst(
602 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
603 AddWrite(*rst);
605 AddReadEOF();
607 DeterministicSocketData data(GetReads(), GetNumReads(),
608 GetWrites(), GetNumWrites());
609 MockConnect connect_data(SYNCHRONOUS, OK);
610 data.set_connect_data(connect_data);
612 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
614 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
616 base::WeakPtr<SpdyStream> stream =
617 CreateStreamSynchronously(
618 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
619 ASSERT_TRUE(stream.get() != NULL);
621 StreamDelegateDoNothing delegate(stream);
622 stream->SetDelegate(&delegate);
624 EXPECT_FALSE(stream->HasUrlFromHeaders());
626 scoped_ptr<SpdyHeaderBlock> headers(
627 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
628 EXPECT_EQ(ERR_IO_PENDING,
629 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
630 EXPECT_TRUE(stream->HasUrlFromHeaders());
631 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
633 data.RunFor(4);
635 base::WeakPtr<SpdyStream> push_stream;
636 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
637 EXPECT_FALSE(push_stream);
639 data.RunFor(1);
641 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
644 // Receiving a header with uppercase ASCII in a HEADERS frame should
645 // result in a protocol error.
646 TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
647 GURL url(kStreamUrl);
649 session_ =
650 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
652 scoped_ptr<SpdyFrame> syn(
653 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
654 AddWrite(*syn);
656 scoped_ptr<SpdyFrame>
657 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
658 AddRead(*reply);
660 scoped_ptr<SpdyFrame>
661 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
662 AddRead(*push);
664 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
665 (*late_headers)["X-UpperCase"] = "yes";
666 scoped_ptr<SpdyFrame> headers_frame(
667 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
668 false,
670 LOWEST,
671 HEADERS,
672 CONTROL_FLAG_NONE,
673 0));
674 AddRead(*headers_frame);
676 scoped_ptr<SpdyFrame> rst(
677 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
678 AddWrite(*rst);
680 AddReadEOF();
682 DeterministicSocketData data(GetReads(), GetNumReads(),
683 GetWrites(), GetNumWrites());
684 MockConnect connect_data(SYNCHRONOUS, OK);
685 data.set_connect_data(connect_data);
687 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
689 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
691 base::WeakPtr<SpdyStream> stream =
692 CreateStreamSynchronously(
693 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
694 ASSERT_TRUE(stream.get() != NULL);
696 StreamDelegateDoNothing delegate(stream);
697 stream->SetDelegate(&delegate);
699 EXPECT_FALSE(stream->HasUrlFromHeaders());
701 scoped_ptr<SpdyHeaderBlock> headers(
702 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
703 EXPECT_EQ(ERR_IO_PENDING,
704 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
705 EXPECT_TRUE(stream->HasUrlFromHeaders());
706 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
708 data.RunFor(3);
710 base::WeakPtr<SpdyStream> push_stream;
711 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
712 EXPECT_TRUE(push_stream);
714 data.RunFor(1);
716 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
717 EXPECT_FALSE(push_stream);
719 data.RunFor(2);
721 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
724 // Receiving a duplicate header in a HEADERS frame should result in a
725 // protocol error.
726 TEST_P(SpdyStreamTest, DuplicateHeaders) {
727 GURL url(kStreamUrl);
729 session_ =
730 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
732 scoped_ptr<SpdyFrame> syn(
733 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
734 AddWrite(*syn);
736 scoped_ptr<SpdyFrame>
737 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
738 AddRead(*reply);
740 scoped_ptr<SpdyFrame>
741 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
742 AddRead(*push);
744 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
745 (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error";
746 scoped_ptr<SpdyFrame> headers_frame(
747 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
748 false,
750 LOWEST,
751 HEADERS,
752 CONTROL_FLAG_NONE,
753 0));
754 AddRead(*headers_frame);
756 scoped_ptr<SpdyFrame> rst(
757 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
758 AddWrite(*rst);
760 AddReadEOF();
762 DeterministicSocketData data(GetReads(), GetNumReads(),
763 GetWrites(), GetNumWrites());
764 MockConnect connect_data(SYNCHRONOUS, OK);
765 data.set_connect_data(connect_data);
767 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
769 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
771 base::WeakPtr<SpdyStream> stream =
772 CreateStreamSynchronously(
773 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
774 ASSERT_TRUE(stream.get() != NULL);
776 StreamDelegateDoNothing delegate(stream);
777 stream->SetDelegate(&delegate);
779 EXPECT_FALSE(stream->HasUrlFromHeaders());
781 scoped_ptr<SpdyHeaderBlock> headers(
782 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
783 EXPECT_EQ(ERR_IO_PENDING,
784 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
785 EXPECT_TRUE(stream->HasUrlFromHeaders());
786 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
788 data.RunFor(3);
790 base::WeakPtr<SpdyStream> push_stream;
791 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
792 EXPECT_TRUE(push_stream);
794 data.RunFor(1);
796 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
797 EXPECT_FALSE(push_stream);
799 data.RunFor(2);
801 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
804 // The tests below are only for SPDY/3 and above.
806 // Call IncreaseSendWindowSize on a stream with a large enough delta
807 // to overflow an int32. The SpdyStream should handle that case
808 // gracefully.
809 TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
810 session_ =
811 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
813 scoped_ptr<SpdyFrame> req(
814 spdy_util_.ConstructSpdyPost(
815 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
816 AddWrite(*req);
818 // Triggered by the overflowing call to IncreaseSendWindowSize
819 // below.
820 scoped_ptr<SpdyFrame> rst(
821 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
822 AddWrite(*rst);
824 AddReadEOF();
826 BoundTestNetLog log;
828 DeterministicSocketData data(GetReads(), GetNumReads(),
829 GetWrites(), GetNumWrites());
830 MockConnect connect_data(SYNCHRONOUS, OK);
831 data.set_connect_data(connect_data);
833 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
835 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
836 GURL url(kStreamUrl);
838 base::WeakPtr<SpdyStream> stream =
839 CreateStreamSynchronously(
840 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
841 ASSERT_TRUE(stream.get() != NULL);
842 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
843 stream->SetDelegate(&delegate);
845 scoped_ptr<SpdyHeaderBlock> headers(
846 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
847 EXPECT_EQ(ERR_IO_PENDING,
848 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
849 EXPECT_TRUE(stream->HasUrlFromHeaders());
850 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
852 data.RunFor(1);
854 int32 old_send_window_size = stream->send_window_size();
855 ASSERT_GT(old_send_window_size, 0);
856 int32 delta_window_size = kint32max - old_send_window_size + 1;
857 stream->IncreaseSendWindowSize(delta_window_size);
858 EXPECT_EQ(NULL, stream.get());
860 data.RunFor(2);
862 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
865 // Functions used with
866 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
868 void StallStream(const base::WeakPtr<SpdyStream>& stream) {
869 // Reduce the send window size to 0 to stall.
870 while (stream->send_window_size() > 0) {
871 stream->DecreaseSendWindowSize(
872 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
876 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
877 int32 delta_window_size) {
878 EXPECT_TRUE(stream->send_stalled_by_flow_control());
879 stream->IncreaseSendWindowSize(delta_window_size);
880 EXPECT_FALSE(stream->send_stalled_by_flow_control());
883 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
884 int32 delta_window_size) {
885 // Make sure that negative adjustments are handled properly.
886 EXPECT_TRUE(stream->send_stalled_by_flow_control());
887 stream->AdjustSendWindowSize(-delta_window_size);
888 EXPECT_TRUE(stream->send_stalled_by_flow_control());
889 stream->AdjustSendWindowSize(+delta_window_size);
890 EXPECT_TRUE(stream->send_stalled_by_flow_control());
891 stream->AdjustSendWindowSize(+delta_window_size);
892 EXPECT_FALSE(stream->send_stalled_by_flow_control());
895 // Given an unstall function, runs a test to make sure that a
896 // request/response (i.e., an HTTP-like) stream resumes after a stall
897 // and unstall.
898 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
899 const UnstallFunction& unstall_function) {
900 GURL url(kStreamUrl);
902 session_ =
903 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
905 scoped_ptr<SpdyFrame> req(
906 spdy_util_.ConstructSpdyPost(
907 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
908 AddWrite(*req);
910 scoped_ptr<SpdyFrame> body(
911 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
912 AddWrite(*body);
914 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
915 AddRead(*resp);
917 AddReadEOF();
919 DeterministicSocketData data(GetReads(), GetNumReads(),
920 GetWrites(), GetNumWrites());
921 MockConnect connect_data(SYNCHRONOUS, OK);
922 data.set_connect_data(connect_data);
924 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
926 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
928 base::WeakPtr<SpdyStream> stream =
929 CreateStreamSynchronously(
930 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
931 ASSERT_TRUE(stream.get() != NULL);
933 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
934 stream->SetDelegate(&delegate);
936 EXPECT_FALSE(stream->HasUrlFromHeaders());
937 EXPECT_FALSE(stream->send_stalled_by_flow_control());
939 scoped_ptr<SpdyHeaderBlock> headers(
940 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
941 EXPECT_EQ(ERR_IO_PENDING,
942 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
943 EXPECT_TRUE(stream->HasUrlFromHeaders());
944 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
946 StallStream(stream);
948 data.RunFor(1);
950 EXPECT_TRUE(stream->send_stalled_by_flow_control());
952 unstall_function.Run(stream, kPostBodyLength);
954 EXPECT_FALSE(stream->send_stalled_by_flow_control());
956 data.RunFor(3);
958 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
960 EXPECT_TRUE(delegate.send_headers_completed());
961 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
962 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
963 EXPECT_TRUE(data.AllWriteDataConsumed());
966 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
967 RunResumeAfterUnstallRequestResponseTest(
968 base::Bind(&IncreaseStreamSendWindowSize));
971 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
972 RunResumeAfterUnstallRequestResponseTest(
973 base::Bind(&AdjustStreamSendWindowSize));
976 // Given an unstall function, runs a test to make sure that a
977 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
978 // and unstall.
979 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
980 const UnstallFunction& unstall_function) {
981 GURL url(kStreamUrl);
983 session_ =
984 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
986 scoped_ptr<SpdyFrame> req(
987 spdy_util_.ConstructSpdyPost(
988 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
989 AddWrite(*req);
991 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
992 AddRead(*resp);
994 scoped_ptr<SpdyFrame> msg(
995 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
996 AddWrite(*msg);
998 scoped_ptr<SpdyFrame> echo(
999 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
1000 AddRead(*echo);
1002 AddReadEOF();
1004 DeterministicSocketData data(GetReads(), GetNumReads(),
1005 GetWrites(), GetNumWrites());
1006 MockConnect connect_data(SYNCHRONOUS, OK);
1007 data.set_connect_data(connect_data);
1009 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1011 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
1013 base::WeakPtr<SpdyStream> stream =
1014 CreateStreamSynchronously(
1015 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
1016 ASSERT_TRUE(stream.get() != NULL);
1018 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
1019 stream->SetDelegate(&delegate);
1021 EXPECT_FALSE(stream->HasUrlFromHeaders());
1023 scoped_ptr<SpdyHeaderBlock> headers(
1024 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
1025 EXPECT_EQ(ERR_IO_PENDING,
1026 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
1027 EXPECT_TRUE(stream->HasUrlFromHeaders());
1028 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
1030 data.RunFor(1);
1032 EXPECT_FALSE(stream->send_stalled_by_flow_control());
1034 StallStream(stream);
1036 data.RunFor(1);
1038 EXPECT_TRUE(stream->send_stalled_by_flow_control());
1040 unstall_function.Run(stream, kPostBodyLength);
1042 EXPECT_FALSE(stream->send_stalled_by_flow_control());
1044 data.RunFor(3);
1046 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1048 EXPECT_TRUE(delegate.send_headers_completed());
1049 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
1050 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
1051 delegate.TakeReceivedData());
1052 EXPECT_TRUE(data.AllWriteDataConsumed());
1055 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
1056 RunResumeAfterUnstallBidirectionalTest(
1057 base::Bind(&IncreaseStreamSendWindowSize));
1060 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
1061 RunResumeAfterUnstallBidirectionalTest(
1062 base::Bind(&AdjustStreamSendWindowSize));
1065 // Test calculation of amount of bytes received from network.
1066 TEST_P(SpdyStreamTest, ReceivedBytes) {
1067 GURL url(kStreamUrl);
1069 session_ =
1070 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
1072 scoped_ptr<SpdyFrame> syn(
1073 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1074 AddWrite(*syn);
1076 scoped_ptr<SpdyFrame>
1077 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1078 AddRead(*reply);
1080 scoped_ptr<SpdyFrame> msg(
1081 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
1082 AddRead(*msg);
1084 AddReadEOF();
1086 DeterministicSocketData data(GetReads(), GetNumReads(),
1087 GetWrites(), GetNumWrites());
1088 MockConnect connect_data(SYNCHRONOUS, OK);
1089 data.set_connect_data(connect_data);
1091 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1093 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
1095 base::WeakPtr<SpdyStream> stream =
1096 CreateStreamSynchronously(
1097 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
1098 ASSERT_TRUE(stream.get() != NULL);
1100 StreamDelegateDoNothing delegate(stream);
1101 stream->SetDelegate(&delegate);
1103 EXPECT_FALSE(stream->HasUrlFromHeaders());
1105 scoped_ptr<SpdyHeaderBlock> headers(
1106 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
1107 EXPECT_EQ(ERR_IO_PENDING,
1108 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
1109 EXPECT_TRUE(stream->HasUrlFromHeaders());
1110 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
1112 int64 reply_frame_len = reply->size();
1113 int64 data_header_len = spdy_util_.CreateFramer(false)
1114 ->GetDataFrameMinimumSize();
1115 int64 data_frame_len = data_header_len + kPostBodyLength;
1116 int64 response_len = reply_frame_len + data_frame_len;
1118 EXPECT_EQ(0, stream->raw_received_bytes());
1119 data.RunFor(1); // SYN
1120 EXPECT_EQ(0, stream->raw_received_bytes());
1121 data.RunFor(1); // REPLY
1122 EXPECT_EQ(reply_frame_len, stream->raw_received_bytes());
1123 data.RunFor(1); // DATA
1124 EXPECT_EQ(response_len, stream->raw_received_bytes());
1125 data.RunFor(1); // FIN
1127 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1130 } // namespace
1132 } // namespace test
1134 } // namespace net