Update broken references to image assets
[chromium-blink-merge.git] / net / spdy / spdy_stream_unittest.cc
blobaf606b37c8ce3af2ee8bb583eeb49420720c7fd6
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_14,
115 kProtoHTTP2));
117 TEST_P(SpdyStreamTest, SendDataAfterOpen) {
118 GURL url(kStreamUrl);
120 session_ =
121 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
123 scoped_ptr<SpdyFrame> req(
124 spdy_util_.ConstructSpdyPost(
125 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
126 AddWrite(*req);
128 scoped_ptr<SpdyFrame> resp(
129 spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
130 AddRead(*resp);
132 scoped_ptr<SpdyFrame> msg(
133 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
134 AddWrite(*msg);
136 scoped_ptr<SpdyFrame> echo(
137 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
138 AddRead(*echo);
140 AddReadEOF();
142 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
143 GetNumWrites());
144 MockConnect connect_data(SYNCHRONOUS, OK);
145 data.set_connect_data(connect_data);
147 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
149 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
151 base::WeakPtr<SpdyStream> stream =
152 CreateStreamSynchronously(
153 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
154 ASSERT_TRUE(stream.get() != NULL);
156 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
157 stream->SetDelegate(&delegate);
159 EXPECT_FALSE(stream->HasUrlFromHeaders());
161 scoped_ptr<SpdyHeaderBlock> headers(
162 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
163 EXPECT_EQ(ERR_IO_PENDING,
164 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
165 EXPECT_TRUE(stream->HasUrlFromHeaders());
166 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
168 data.RunFor(GetNumReads() + GetNumWrites());
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(std::string(kPostBody, kPostBodyLength),
174 delegate.TakeReceivedData());
175 EXPECT_TRUE(data.AllWriteDataConsumed());
178 // Delegate that receives trailers.
179 class StreamDelegateWithTrailers : public test::StreamDelegateWithBody {
180 public:
181 StreamDelegateWithTrailers(const base::WeakPtr<SpdyStream>& stream,
182 base::StringPiece data)
183 : StreamDelegateWithBody(stream, data) {}
185 ~StreamDelegateWithTrailers() override {}
187 void OnTrailers(const SpdyHeaderBlock& trailers) override {
188 trailers_ = trailers;
191 const SpdyHeaderBlock& trailers() const { return trailers_; }
193 private:
194 SpdyHeaderBlock trailers_;
197 // Regression test for crbug.com/481033.
198 TEST_P(SpdyStreamTest, Trailers) {
199 GURL url(kStreamUrl);
201 session_ =
202 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
204 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
205 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
206 AddWrite(*req);
208 scoped_ptr<SpdyFrame> msg(
209 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
210 AddWrite(*msg);
212 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
213 AddRead(*resp);
215 scoped_ptr<SpdyFrame> echo(
216 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
217 AddRead(*echo);
219 const char* const kExtraHeaders[] = {"foo", "bar"};
220 scoped_ptr<SpdyFrame> trailers(
221 spdy_util_.ConstructSpdyHeaderFrame(1, kExtraHeaders, 1));
222 AddRead(*trailers);
224 AddReadEOF();
226 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
227 GetNumWrites());
228 MockConnect connect_data(SYNCHRONOUS, OK);
229 data.set_connect_data(connect_data);
231 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
233 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
235 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
236 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
237 ASSERT_TRUE(stream.get() != NULL);
239 StreamDelegateWithTrailers delegate(stream, kPostBodyStringPiece);
240 stream->SetDelegate(&delegate);
242 EXPECT_FALSE(stream->HasUrlFromHeaders());
244 scoped_ptr<SpdyHeaderBlock> headers(
245 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
246 EXPECT_EQ(ERR_IO_PENDING,
247 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
248 EXPECT_TRUE(stream->HasUrlFromHeaders());
249 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
251 data.RunFor(GetNumReads() + GetNumWrites());
252 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
254 EXPECT_TRUE(delegate.send_headers_completed());
255 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
256 const SpdyHeaderBlock& received_trailers = delegate.trailers();
257 SpdyHeaderBlock::const_iterator it = received_trailers.find("foo");
258 EXPECT_EQ("bar", it->second);
259 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
260 delegate.TakeReceivedData());
261 EXPECT_TRUE(data.AllWriteDataConsumed());
264 TEST_P(SpdyStreamTest, PushedStream) {
265 session_ =
266 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
268 AddReadEOF();
270 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
271 GetNumWrites());
272 MockConnect connect_data(SYNCHRONOUS, OK);
273 data.set_connect_data(connect_data);
275 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
277 base::WeakPtr<SpdySession> spdy_session(CreateDefaultSpdySession());
279 // Conjure up a stream.
280 SpdyStream stream(SPDY_PUSH_STREAM, spdy_session, GURL(), DEFAULT_PRIORITY,
281 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31),
282 SpdySession::GetDefaultInitialWindowSize(kProtoSPDY31),
283 BoundNetLog());
284 stream.set_stream_id(2);
285 EXPECT_FALSE(stream.HasUrlFromHeaders());
287 // Set required request headers.
288 SpdyHeaderBlock request_headers;
289 spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &request_headers);
290 stream.OnPushPromiseHeadersReceived(request_headers);
292 // Send some basic response headers.
293 SpdyHeaderBlock response;
294 response[spdy_util_.GetStatusKey()] = "200";
295 response[spdy_util_.GetVersionKey()] = "OK";
296 stream.OnInitialResponseHeadersReceived(
297 response, base::Time::Now(), base::TimeTicks::Now());
299 // And some more headers.
300 // TODO(baranovich): not valid for HTTP 2.
301 SpdyHeaderBlock headers;
302 headers["alpha"] = "beta";
303 stream.OnAdditionalResponseHeadersReceived(headers);
305 EXPECT_TRUE(stream.HasUrlFromHeaders());
306 EXPECT_EQ(kStreamUrl, stream.GetUrlFromHeaders().spec());
308 StreamDelegateDoNothing delegate(stream.GetWeakPtr());
309 stream.SetDelegate(&delegate);
311 data.RunFor(GetNumReads() + GetNumWrites());
313 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
314 EXPECT_EQ("beta", delegate.GetResponseHeaderValue("alpha"));
316 EXPECT_TRUE(spdy_session == NULL);
319 TEST_P(SpdyStreamTest, StreamError) {
320 GURL url(kStreamUrl);
322 session_ =
323 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
325 scoped_ptr<SpdyFrame> req(
326 spdy_util_.ConstructSpdyPost(
327 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
328 AddWrite(*req);
330 scoped_ptr<SpdyFrame> resp(
331 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
332 AddRead(*resp);
334 scoped_ptr<SpdyFrame> msg(
335 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
336 AddWrite(*msg);
338 scoped_ptr<SpdyFrame> echo(
339 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
340 AddRead(*echo);
342 AddReadEOF();
344 BoundTestNetLog log;
346 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
347 GetNumWrites());
348 MockConnect connect_data(SYNCHRONOUS, OK);
349 data.set_connect_data(connect_data);
351 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
353 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
355 base::WeakPtr<SpdyStream> stream =
356 CreateStreamSynchronously(
357 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
358 ASSERT_TRUE(stream.get() != NULL);
360 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
361 stream->SetDelegate(&delegate);
363 EXPECT_FALSE(stream->HasUrlFromHeaders());
365 scoped_ptr<SpdyHeaderBlock> headers(
366 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
367 EXPECT_EQ(ERR_IO_PENDING,
368 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
369 EXPECT_TRUE(stream->HasUrlFromHeaders());
370 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
372 data.RunFor(GetNumReads() + GetNumWrites());
373 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
375 const SpdyStreamId stream_id = delegate.stream_id();
377 EXPECT_TRUE(delegate.send_headers_completed());
378 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
379 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
380 delegate.TakeReceivedData());
381 EXPECT_TRUE(data.AllWriteDataConsumed());
383 // Check that the NetLog was filled reasonably.
384 TestNetLogEntry::List entries;
385 log.GetEntries(&entries);
386 EXPECT_LT(0u, entries.size());
388 // Check that we logged SPDY_STREAM_ERROR correctly.
389 int pos = ExpectLogContainsSomewhere(
390 entries, 0, NetLog::TYPE_HTTP2_STREAM_ERROR, NetLog::PHASE_NONE);
392 int stream_id2;
393 ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2));
394 EXPECT_EQ(static_cast<int>(stream_id), stream_id2);
397 // Make sure that large blocks of data are properly split up into
398 // frame-sized chunks for a request/response (i.e., an HTTP-like)
399 // stream.
400 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
401 GURL url(kStreamUrl);
403 session_ =
404 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
406 scoped_ptr<SpdyFrame> req(
407 spdy_util_.ConstructSpdyPost(
408 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
409 AddWrite(*req);
411 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
412 scoped_ptr<SpdyFrame> chunk(
413 spdy_util_.ConstructSpdyBodyFrame(
414 1, chunk_data.data(), chunk_data.length(), false));
415 AddWrite(*chunk);
416 AddWrite(*chunk);
418 scoped_ptr<SpdyFrame> last_chunk(
419 spdy_util_.ConstructSpdyBodyFrame(
420 1, chunk_data.data(), chunk_data.length(), true));
421 AddWrite(*last_chunk);
423 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
424 AddRead(*resp);
426 AddReadEOF();
428 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
429 GetNumWrites());
430 MockConnect connect_data(SYNCHRONOUS, OK);
431 data.set_connect_data(connect_data);
433 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
435 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
437 base::WeakPtr<SpdyStream> stream =
438 CreateStreamSynchronously(
439 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
440 ASSERT_TRUE(stream.get() != NULL);
442 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
443 StreamDelegateWithBody delegate(stream, body_data);
444 stream->SetDelegate(&delegate);
446 EXPECT_FALSE(stream->HasUrlFromHeaders());
448 scoped_ptr<SpdyHeaderBlock> headers(
449 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
450 EXPECT_EQ(ERR_IO_PENDING,
451 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
452 EXPECT_TRUE(stream->HasUrlFromHeaders());
453 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
455 data.RunFor(GetNumReads() + GetNumWrites());
456 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
458 EXPECT_TRUE(delegate.send_headers_completed());
459 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
460 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
461 EXPECT_TRUE(data.AllWriteDataConsumed());
464 // Make sure that large blocks of data are properly split up into
465 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
466 // stream.
467 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
468 GURL url(kStreamUrl);
470 session_ =
471 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
473 scoped_ptr<SpdyFrame> req(
474 spdy_util_.ConstructSpdyPost(
475 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
476 AddWrite(*req);
478 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
479 AddRead(*resp);
481 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
482 scoped_ptr<SpdyFrame> chunk(
483 spdy_util_.ConstructSpdyBodyFrame(
484 1, chunk_data.data(), chunk_data.length(), false));
485 AddWrite(*chunk);
486 AddWrite(*chunk);
487 AddWrite(*chunk);
489 AddReadEOF();
491 DeterministicSocketData data(GetReads(), GetNumReads(), GetWrites(),
492 GetNumWrites());
493 MockConnect connect_data(SYNCHRONOUS, OK);
494 data.set_connect_data(connect_data);
496 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
498 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
500 base::WeakPtr<SpdyStream> stream =
501 CreateStreamSynchronously(
502 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
503 ASSERT_TRUE(stream.get() != NULL);
505 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
506 StreamDelegateSendImmediate delegate(stream, body_data);
507 stream->SetDelegate(&delegate);
509 EXPECT_FALSE(stream->HasUrlFromHeaders());
511 scoped_ptr<SpdyHeaderBlock> headers(
512 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
513 EXPECT_EQ(ERR_IO_PENDING,
514 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
515 EXPECT_TRUE(stream->HasUrlFromHeaders());
516 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
518 data.RunFor(GetNumReads() + GetNumWrites());
519 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
521 EXPECT_TRUE(delegate.send_headers_completed());
522 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
523 EXPECT_EQ(std::string(), delegate.TakeReceivedData());
524 EXPECT_TRUE(data.AllWriteDataConsumed());
527 // Receiving a header with uppercase ASCII should result in a protocol
528 // error.
529 TEST_P(SpdyStreamTest, UpperCaseHeaders) {
530 GURL url(kStreamUrl);
532 session_ =
533 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
535 scoped_ptr<SpdyFrame> syn(
536 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
537 AddWrite(*syn);
539 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
540 scoped_ptr<SpdyFrame>
541 reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
542 AddRead(*reply);
544 scoped_ptr<SpdyFrame> rst(
545 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
546 AddWrite(*rst);
548 AddReadEOF();
550 DeterministicSocketData data(GetReads(), GetNumReads(),
551 GetWrites(), GetNumWrites());
552 MockConnect connect_data(SYNCHRONOUS, OK);
553 data.set_connect_data(connect_data);
555 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
557 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
559 base::WeakPtr<SpdyStream> stream =
560 CreateStreamSynchronously(
561 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
562 ASSERT_TRUE(stream.get() != NULL);
564 StreamDelegateDoNothing delegate(stream);
565 stream->SetDelegate(&delegate);
567 EXPECT_FALSE(stream->HasUrlFromHeaders());
569 scoped_ptr<SpdyHeaderBlock> headers(
570 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
571 EXPECT_EQ(ERR_IO_PENDING,
572 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
573 EXPECT_TRUE(stream->HasUrlFromHeaders());
574 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
576 data.RunFor(4);
578 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
581 // Receiving a header with uppercase ASCII should result in a protocol
582 // error even for a push stream.
583 TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
584 GURL url(kStreamUrl);
586 session_ =
587 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
589 scoped_ptr<SpdyFrame> syn(
590 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
591 AddWrite(*syn);
593 scoped_ptr<SpdyFrame>
594 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
595 AddRead(*reply);
597 const char* const extra_headers[] = {"X-UpperCase", "yes"};
598 scoped_ptr<SpdyFrame>
599 push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
600 AddRead(*push);
602 scoped_ptr<SpdyFrame> rst(
603 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
604 AddWrite(*rst);
606 AddReadEOF();
608 DeterministicSocketData data(GetReads(), GetNumReads(),
609 GetWrites(), GetNumWrites());
610 MockConnect connect_data(SYNCHRONOUS, OK);
611 data.set_connect_data(connect_data);
613 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
615 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
617 base::WeakPtr<SpdyStream> stream =
618 CreateStreamSynchronously(
619 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
620 ASSERT_TRUE(stream.get() != NULL);
622 StreamDelegateDoNothing delegate(stream);
623 stream->SetDelegate(&delegate);
625 EXPECT_FALSE(stream->HasUrlFromHeaders());
627 scoped_ptr<SpdyHeaderBlock> headers(
628 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
629 EXPECT_EQ(ERR_IO_PENDING,
630 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
631 EXPECT_TRUE(stream->HasUrlFromHeaders());
632 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
634 data.RunFor(4);
636 base::WeakPtr<SpdyStream> push_stream;
637 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
638 EXPECT_FALSE(push_stream);
640 data.RunFor(1);
642 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
645 // Receiving a header with uppercase ASCII in a HEADERS frame should
646 // result in a protocol error.
647 TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
648 GURL url(kStreamUrl);
650 session_ =
651 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
653 scoped_ptr<SpdyFrame> syn(
654 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
655 AddWrite(*syn);
657 scoped_ptr<SpdyFrame>
658 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
659 AddRead(*reply);
661 scoped_ptr<SpdyFrame>
662 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
663 AddRead(*push);
665 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
666 (*late_headers)["X-UpperCase"] = "yes";
667 scoped_ptr<SpdyFrame> headers_frame(
668 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
669 false,
671 LOWEST,
672 HEADERS,
673 CONTROL_FLAG_NONE,
674 0));
675 AddRead(*headers_frame);
677 scoped_ptr<SpdyFrame> rst(
678 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
679 AddWrite(*rst);
681 AddReadEOF();
683 DeterministicSocketData data(GetReads(), GetNumReads(),
684 GetWrites(), GetNumWrites());
685 MockConnect connect_data(SYNCHRONOUS, OK);
686 data.set_connect_data(connect_data);
688 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
690 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
692 base::WeakPtr<SpdyStream> stream =
693 CreateStreamSynchronously(
694 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
695 ASSERT_TRUE(stream.get() != NULL);
697 StreamDelegateDoNothing delegate(stream);
698 stream->SetDelegate(&delegate);
700 EXPECT_FALSE(stream->HasUrlFromHeaders());
702 scoped_ptr<SpdyHeaderBlock> headers(
703 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
704 EXPECT_EQ(ERR_IO_PENDING,
705 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
706 EXPECT_TRUE(stream->HasUrlFromHeaders());
707 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
709 data.RunFor(3);
711 base::WeakPtr<SpdyStream> push_stream;
712 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
713 EXPECT_TRUE(push_stream);
715 data.RunFor(1);
717 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
718 EXPECT_FALSE(push_stream);
720 data.RunFor(2);
722 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
725 // Receiving a duplicate header in a HEADERS frame should result in a
726 // protocol error.
727 TEST_P(SpdyStreamTest, DuplicateHeaders) {
728 GURL url(kStreamUrl);
730 session_ =
731 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
733 scoped_ptr<SpdyFrame> syn(
734 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
735 AddWrite(*syn);
737 scoped_ptr<SpdyFrame>
738 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
739 AddRead(*reply);
741 scoped_ptr<SpdyFrame>
742 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
743 AddRead(*push);
745 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
746 (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error";
747 scoped_ptr<SpdyFrame> headers_frame(
748 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
749 false,
751 LOWEST,
752 HEADERS,
753 CONTROL_FLAG_NONE,
754 0));
755 AddRead(*headers_frame);
757 scoped_ptr<SpdyFrame> rst(
758 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
759 AddWrite(*rst);
761 AddReadEOF();
763 DeterministicSocketData data(GetReads(), GetNumReads(),
764 GetWrites(), GetNumWrites());
765 MockConnect connect_data(SYNCHRONOUS, OK);
766 data.set_connect_data(connect_data);
768 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
770 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
772 base::WeakPtr<SpdyStream> stream =
773 CreateStreamSynchronously(
774 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
775 ASSERT_TRUE(stream.get() != NULL);
777 StreamDelegateDoNothing delegate(stream);
778 stream->SetDelegate(&delegate);
780 EXPECT_FALSE(stream->HasUrlFromHeaders());
782 scoped_ptr<SpdyHeaderBlock> headers(
783 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
784 EXPECT_EQ(ERR_IO_PENDING,
785 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
786 EXPECT_TRUE(stream->HasUrlFromHeaders());
787 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
789 data.RunFor(3);
791 base::WeakPtr<SpdyStream> push_stream;
792 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
793 EXPECT_TRUE(push_stream);
795 data.RunFor(1);
797 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
798 EXPECT_FALSE(push_stream);
800 data.RunFor(2);
802 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
805 // The tests below are only for SPDY/3 and above.
807 // Call IncreaseSendWindowSize on a stream with a large enough delta
808 // to overflow an int32. The SpdyStream should handle that case
809 // gracefully.
810 TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
811 session_ =
812 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
814 scoped_ptr<SpdyFrame> req(
815 spdy_util_.ConstructSpdyPost(
816 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
817 AddWrite(*req);
819 // Triggered by the overflowing call to IncreaseSendWindowSize
820 // below.
821 scoped_ptr<SpdyFrame> rst(
822 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
823 AddWrite(*rst);
825 AddReadEOF();
827 BoundTestNetLog log;
829 DeterministicSocketData data(GetReads(), GetNumReads(),
830 GetWrites(), GetNumWrites());
831 MockConnect connect_data(SYNCHRONOUS, OK);
832 data.set_connect_data(connect_data);
834 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
836 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
837 GURL url(kStreamUrl);
839 base::WeakPtr<SpdyStream> stream =
840 CreateStreamSynchronously(
841 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
842 ASSERT_TRUE(stream.get() != NULL);
843 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
844 stream->SetDelegate(&delegate);
846 scoped_ptr<SpdyHeaderBlock> headers(
847 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
848 EXPECT_EQ(ERR_IO_PENDING,
849 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
850 EXPECT_TRUE(stream->HasUrlFromHeaders());
851 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
853 data.RunFor(1);
855 int32 old_send_window_size = stream->send_window_size();
856 ASSERT_GT(old_send_window_size, 0);
857 int32 delta_window_size = kint32max - old_send_window_size + 1;
858 stream->IncreaseSendWindowSize(delta_window_size);
859 EXPECT_EQ(NULL, stream.get());
861 data.RunFor(2);
863 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
866 // Functions used with
867 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
869 void StallStream(const base::WeakPtr<SpdyStream>& stream) {
870 // Reduce the send window size to 0 to stall.
871 while (stream->send_window_size() > 0) {
872 stream->DecreaseSendWindowSize(
873 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
877 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
878 int32 delta_window_size) {
879 EXPECT_TRUE(stream->send_stalled_by_flow_control());
880 stream->IncreaseSendWindowSize(delta_window_size);
881 EXPECT_FALSE(stream->send_stalled_by_flow_control());
884 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
885 int32 delta_window_size) {
886 // Make sure that negative adjustments are handled properly.
887 EXPECT_TRUE(stream->send_stalled_by_flow_control());
888 stream->AdjustSendWindowSize(-delta_window_size);
889 EXPECT_TRUE(stream->send_stalled_by_flow_control());
890 stream->AdjustSendWindowSize(+delta_window_size);
891 EXPECT_TRUE(stream->send_stalled_by_flow_control());
892 stream->AdjustSendWindowSize(+delta_window_size);
893 EXPECT_FALSE(stream->send_stalled_by_flow_control());
896 // Given an unstall function, runs a test to make sure that a
897 // request/response (i.e., an HTTP-like) stream resumes after a stall
898 // and unstall.
899 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
900 const UnstallFunction& unstall_function) {
901 GURL url(kStreamUrl);
903 session_ =
904 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
906 scoped_ptr<SpdyFrame> req(
907 spdy_util_.ConstructSpdyPost(
908 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
909 AddWrite(*req);
911 scoped_ptr<SpdyFrame> body(
912 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
913 AddWrite(*body);
915 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
916 AddRead(*resp);
918 AddReadEOF();
920 DeterministicSocketData data(GetReads(), GetNumReads(),
921 GetWrites(), GetNumWrites());
922 MockConnect connect_data(SYNCHRONOUS, OK);
923 data.set_connect_data(connect_data);
925 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
927 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
929 base::WeakPtr<SpdyStream> stream =
930 CreateStreamSynchronously(
931 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
932 ASSERT_TRUE(stream.get() != NULL);
934 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
935 stream->SetDelegate(&delegate);
937 EXPECT_FALSE(stream->HasUrlFromHeaders());
938 EXPECT_FALSE(stream->send_stalled_by_flow_control());
940 scoped_ptr<SpdyHeaderBlock> headers(
941 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
942 EXPECT_EQ(ERR_IO_PENDING,
943 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
944 EXPECT_TRUE(stream->HasUrlFromHeaders());
945 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
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(), delegate.TakeReceivedData());
964 EXPECT_TRUE(data.AllWriteDataConsumed());
967 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
968 RunResumeAfterUnstallRequestResponseTest(
969 base::Bind(&IncreaseStreamSendWindowSize));
972 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
973 RunResumeAfterUnstallRequestResponseTest(
974 base::Bind(&AdjustStreamSendWindowSize));
977 // Given an unstall function, runs a test to make sure that a
978 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
979 // and unstall.
980 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
981 const UnstallFunction& unstall_function) {
982 GURL url(kStreamUrl);
984 session_ =
985 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
987 scoped_ptr<SpdyFrame> req(
988 spdy_util_.ConstructSpdyPost(
989 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
990 AddWrite(*req);
992 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
993 AddRead(*resp);
995 scoped_ptr<SpdyFrame> msg(
996 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
997 AddWrite(*msg);
999 scoped_ptr<SpdyFrame> echo(
1000 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
1001 AddRead(*echo);
1003 AddReadEOF();
1005 DeterministicSocketData data(GetReads(), GetNumReads(),
1006 GetWrites(), GetNumWrites());
1007 MockConnect connect_data(SYNCHRONOUS, OK);
1008 data.set_connect_data(connect_data);
1010 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1012 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
1014 base::WeakPtr<SpdyStream> stream =
1015 CreateStreamSynchronously(
1016 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
1017 ASSERT_TRUE(stream.get() != NULL);
1019 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
1020 stream->SetDelegate(&delegate);
1022 EXPECT_FALSE(stream->HasUrlFromHeaders());
1024 scoped_ptr<SpdyHeaderBlock> headers(
1025 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
1026 EXPECT_EQ(ERR_IO_PENDING,
1027 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
1028 EXPECT_TRUE(stream->HasUrlFromHeaders());
1029 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
1031 data.RunFor(1);
1033 EXPECT_FALSE(stream->send_stalled_by_flow_control());
1035 StallStream(stream);
1037 data.RunFor(1);
1039 EXPECT_TRUE(stream->send_stalled_by_flow_control());
1041 unstall_function.Run(stream, kPostBodyLength);
1043 EXPECT_FALSE(stream->send_stalled_by_flow_control());
1045 data.RunFor(3);
1047 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1049 EXPECT_TRUE(delegate.send_headers_completed());
1050 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
1051 EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
1052 delegate.TakeReceivedData());
1053 EXPECT_TRUE(data.AllWriteDataConsumed());
1056 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
1057 RunResumeAfterUnstallBidirectionalTest(
1058 base::Bind(&IncreaseStreamSendWindowSize));
1061 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
1062 RunResumeAfterUnstallBidirectionalTest(
1063 base::Bind(&AdjustStreamSendWindowSize));
1066 // Test calculation of amount of bytes received from network.
1067 TEST_P(SpdyStreamTest, ReceivedBytes) {
1068 GURL url(kStreamUrl);
1070 session_ =
1071 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
1073 scoped_ptr<SpdyFrame> syn(
1074 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
1075 AddWrite(*syn);
1077 scoped_ptr<SpdyFrame>
1078 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
1079 AddRead(*reply);
1081 scoped_ptr<SpdyFrame> msg(
1082 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
1083 AddRead(*msg);
1085 AddReadEOF();
1087 DeterministicSocketData data(GetReads(), GetNumReads(),
1088 GetWrites(), GetNumWrites());
1089 MockConnect connect_data(SYNCHRONOUS, OK);
1090 data.set_connect_data(connect_data);
1092 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
1094 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
1096 base::WeakPtr<SpdyStream> stream =
1097 CreateStreamSynchronously(
1098 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
1099 ASSERT_TRUE(stream.get() != NULL);
1101 StreamDelegateDoNothing delegate(stream);
1102 stream->SetDelegate(&delegate);
1104 EXPECT_FALSE(stream->HasUrlFromHeaders());
1106 scoped_ptr<SpdyHeaderBlock> headers(
1107 spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
1108 EXPECT_EQ(ERR_IO_PENDING,
1109 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
1110 EXPECT_TRUE(stream->HasUrlFromHeaders());
1111 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
1113 int64 reply_frame_len = reply->size();
1114 int64 data_header_len = spdy_util_.CreateFramer(false)
1115 ->GetDataFrameMinimumSize();
1116 int64 data_frame_len = data_header_len + kPostBodyLength;
1117 int64 response_len = reply_frame_len + data_frame_len;
1119 EXPECT_EQ(0, stream->raw_received_bytes());
1120 data.RunFor(1); // SYN
1121 EXPECT_EQ(0, stream->raw_received_bytes());
1122 data.RunFor(1); // REPLY
1123 EXPECT_EQ(reply_frame_len, stream->raw_received_bytes());
1124 data.RunFor(1); // DATA
1125 EXPECT_EQ(response_len, stream->raw_received_bytes());
1126 data.RunFor(1); // FIN
1128 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
1131 } // namespace
1133 } // namespace test
1135 } // namespace net