| Index: net/spdy/spdy_stream_unittest.cc
|
| diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc
|
| index df3c372c8b93cf1b5533f0759d3122ad3d8917f2..c27ad2ebc1c028e74b6adc69120b9439d789c0a6 100644
|
| --- a/net/spdy/spdy_stream_unittest.cc
|
| +++ b/net/spdy/spdy_stream_unittest.cc
|
| @@ -206,11 +206,17 @@ TEST_P(SpdyStreamTest, PushedStream) {
|
| session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
|
| scoped_refptr<SpdySession> spdy_session(CreateSpdySession());
|
|
|
| - MockRead reads[] = {
|
| - MockRead(ASYNC, 0, 0), // EOF
|
| - };
|
| + scoped_ptr<SpdyFrame> initial_window_update(
|
| + spdy_util_.ConstructSpdyWindowUpdate(
|
| + kSessionFlowControlStreamId,
|
| + kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
|
| + if (spdy_util_.protocol() >= kProtoSPDY31)
|
| + AddWrite(*initial_window_update);
|
| +
|
| + AddReadEOF();
|
|
|
| - OrderedSocketData data(reads, arraysize(reads), NULL, 0);
|
| + OrderedSocketData data(GetReads(), GetNumReads(),
|
| + GetWrites(), GetNumWrites());
|
| MockConnect connect_data(SYNCHRONOUS, OK);
|
| data.set_connect_data(connect_data);
|
|
|
| @@ -228,25 +234,30 @@ TEST_P(SpdyStreamTest, PushedStream) {
|
| kSpdyStreamInitialWindowSize,
|
| net_log);
|
| stream.set_stream_id(2);
|
| - EXPECT_FALSE(stream.response_received());
|
| EXPECT_FALSE(stream.HasUrl());
|
|
|
| // Set a couple of headers.
|
| SpdyHeaderBlock response;
|
| spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &response);
|
| - stream.OnResponseHeadersReceived(response);
|
| + stream.OnInitialResponseHeadersReceived(
|
| + response, base::Time::Now(), base::TimeTicks::Now());
|
|
|
| // Send some basic headers.
|
| SpdyHeaderBlock headers;
|
| - response[spdy_util_.GetStatusKey()] = "200";
|
| - response[spdy_util_.GetVersionKey()] = "OK";
|
| - stream.OnHeaders(headers);
|
| + headers[spdy_util_.GetStatusKey()] = "200";
|
| + headers[spdy_util_.GetVersionKey()] = "OK";
|
| + stream.OnAdditionalResponseHeadersReceived(headers);
|
|
|
| - stream.set_response_received();
|
| - EXPECT_TRUE(stream.response_received());
|
| EXPECT_TRUE(stream.HasUrl());
|
| EXPECT_EQ(kStreamUrl, stream.GetUrl().spec());
|
|
|
| + StreamDelegateDoNothing delegate(stream.GetWeakPtr());
|
| + stream.SetDelegate(&delegate);
|
| +
|
| + base::MessageLoop::current()->RunUntilIdle();
|
| +
|
| + EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
|
| +
|
| spdy_session->CloseSessionOnError(
|
| ERR_CONNECTION_CLOSED, true, "Closing session");
|
| }
|
| @@ -488,6 +499,336 @@ TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
|
| EXPECT_TRUE(data.at_write_eof());
|
| }
|
|
|
| +// Receiving a header with uppercase ASCII should result in a protocol
|
| +// error.
|
| +TEST_P(SpdyStreamTest, UpperCaseHeaders) {
|
| + GURL url(kStreamUrl);
|
| +
|
| + session_ =
|
| + SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
|
| +
|
| + scoped_ptr<SpdyFrame> initial_window_update(
|
| + spdy_util_.ConstructSpdyWindowUpdate(
|
| + kSessionFlowControlStreamId,
|
| + kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
|
| + if (spdy_util_.protocol() >= kProtoSPDY31)
|
| + AddWrite(*initial_window_update);
|
| +
|
| + scoped_ptr<SpdyFrame> syn(
|
| + spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
|
| + AddWrite(*syn);
|
| +
|
| + const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
|
| + scoped_ptr<SpdyFrame>
|
| + reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
|
| + AddRead(*reply);
|
| +
|
| + scoped_ptr<SpdyFrame> rst(
|
| + spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
|
| + AddWrite(*rst);
|
| +
|
| + AddReadEOF();
|
| +
|
| + DeterministicSocketData data(GetReads(), GetNumReads(),
|
| + GetWrites(), GetNumWrites());
|
| + MockConnect connect_data(SYNCHRONOUS, OK);
|
| + data.set_connect_data(connect_data);
|
| +
|
| + session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
|
| +
|
| + scoped_refptr<SpdySession> session(CreateSpdySession());
|
| +
|
| + InitializeSpdySession(session, host_port_pair_);
|
| +
|
| + base::WeakPtr<SpdyStream> stream =
|
| + CreateStreamSynchronously(
|
| + SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
|
| + ASSERT_TRUE(stream.get() != NULL);
|
| +
|
| + StreamDelegateDoNothing delegate(stream);
|
| + stream->SetDelegate(&delegate);
|
| +
|
| + EXPECT_FALSE(stream->HasUrl());
|
| +
|
| + scoped_ptr<SpdyHeaderBlock> headers(
|
| + spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
|
| + EXPECT_EQ(ERR_IO_PENDING,
|
| + stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
|
| + EXPECT_TRUE(stream->HasUrl());
|
| + EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
|
| +
|
| + // For the initial window update.
|
| + if (spdy_util_.protocol() >= kProtoSPDY31)
|
| + data.RunFor(1);
|
| +
|
| + data.RunFor(4);
|
| +
|
| + EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
|
| +}
|
| +
|
| +// Receiving a header with uppercase ASCII should result in a protocol
|
| +// error even for a push stream.
|
| +TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
|
| + GURL url(kStreamUrl);
|
| +
|
| + session_ =
|
| + SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
|
| +
|
| + scoped_ptr<SpdyFrame> initial_window_update(
|
| + spdy_util_.ConstructSpdyWindowUpdate(
|
| + kSessionFlowControlStreamId,
|
| + kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
|
| + if (spdy_util_.protocol() >= kProtoSPDY31)
|
| + AddWrite(*initial_window_update);
|
| +
|
| + scoped_ptr<SpdyFrame> syn(
|
| + spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
|
| + AddWrite(*syn);
|
| +
|
| + scoped_ptr<SpdyFrame>
|
| + reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
|
| + AddRead(*reply);
|
| +
|
| + const char* const extra_headers[] = {"X-UpperCase", "yes"};
|
| + scoped_ptr<SpdyFrame>
|
| + push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
|
| + AddRead(*push);
|
| +
|
| + scoped_ptr<SpdyFrame> rst(
|
| + spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
|
| + AddWrite(*rst);
|
| +
|
| + AddReadEOF();
|
| +
|
| + DeterministicSocketData data(GetReads(), GetNumReads(),
|
| + GetWrites(), GetNumWrites());
|
| + MockConnect connect_data(SYNCHRONOUS, OK);
|
| + data.set_connect_data(connect_data);
|
| +
|
| + session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
|
| +
|
| + scoped_refptr<SpdySession> session(CreateSpdySession());
|
| +
|
| + InitializeSpdySession(session, host_port_pair_);
|
| +
|
| + base::WeakPtr<SpdyStream> stream =
|
| + CreateStreamSynchronously(
|
| + SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
|
| + ASSERT_TRUE(stream.get() != NULL);
|
| +
|
| + StreamDelegateDoNothing delegate(stream);
|
| + stream->SetDelegate(&delegate);
|
| +
|
| + EXPECT_FALSE(stream->HasUrl());
|
| +
|
| + scoped_ptr<SpdyHeaderBlock> headers(
|
| + spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
|
| + EXPECT_EQ(ERR_IO_PENDING,
|
| + stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
|
| + EXPECT_TRUE(stream->HasUrl());
|
| + EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
|
| +
|
| + // For the initial window update.
|
| + if (spdy_util_.protocol() >= kProtoSPDY31)
|
| + data.RunFor(1);
|
| +
|
| + data.RunFor(4);
|
| +
|
| + base::WeakPtr<SpdyStream> push_stream;
|
| + EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
|
| + EXPECT_FALSE(push_stream);
|
| +
|
| + data.RunFor(1);
|
| +
|
| + EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
|
| +}
|
| +
|
| +// Receiving a header with uppercase ASCII in a HEADERS frame should
|
| +// result in a protocol error.
|
| +TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
|
| + GURL url(kStreamUrl);
|
| +
|
| + session_ =
|
| + SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
|
| +
|
| + scoped_ptr<SpdyFrame> initial_window_update(
|
| + spdy_util_.ConstructSpdyWindowUpdate(
|
| + kSessionFlowControlStreamId,
|
| + kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
|
| + if (spdy_util_.protocol() >= kProtoSPDY31)
|
| + AddWrite(*initial_window_update);
|
| +
|
| + scoped_ptr<SpdyFrame> syn(
|
| + spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
|
| + AddWrite(*syn);
|
| +
|
| + scoped_ptr<SpdyFrame>
|
| + reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
|
| + AddRead(*reply);
|
| +
|
| + scoped_ptr<SpdyFrame>
|
| + push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
|
| + AddRead(*push);
|
| +
|
| + scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
|
| + (*late_headers)["X-UpperCase"] = "yes";
|
| + scoped_ptr<SpdyFrame> headers_frame(
|
| + spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
|
| + false,
|
| + 2,
|
| + LOWEST,
|
| + HEADERS,
|
| + CONTROL_FLAG_NONE,
|
| + 0));
|
| + AddRead(*headers_frame);
|
| +
|
| + scoped_ptr<SpdyFrame> rst(
|
| + spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
|
| + AddWrite(*rst);
|
| +
|
| + AddReadEOF();
|
| +
|
| + DeterministicSocketData data(GetReads(), GetNumReads(),
|
| + GetWrites(), GetNumWrites());
|
| + MockConnect connect_data(SYNCHRONOUS, OK);
|
| + data.set_connect_data(connect_data);
|
| +
|
| + session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
|
| +
|
| + scoped_refptr<SpdySession> session(CreateSpdySession());
|
| +
|
| + InitializeSpdySession(session, host_port_pair_);
|
| +
|
| + base::WeakPtr<SpdyStream> stream =
|
| + CreateStreamSynchronously(
|
| + SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
|
| + ASSERT_TRUE(stream.get() != NULL);
|
| +
|
| + StreamDelegateDoNothing delegate(stream);
|
| + stream->SetDelegate(&delegate);
|
| +
|
| + EXPECT_FALSE(stream->HasUrl());
|
| +
|
| + scoped_ptr<SpdyHeaderBlock> headers(
|
| + spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
|
| + EXPECT_EQ(ERR_IO_PENDING,
|
| + stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
|
| + EXPECT_TRUE(stream->HasUrl());
|
| + EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
|
| +
|
| + // For the initial window update.
|
| + if (spdy_util_.protocol() >= kProtoSPDY31)
|
| + data.RunFor(1);
|
| +
|
| + data.RunFor(3);
|
| +
|
| + base::WeakPtr<SpdyStream> push_stream;
|
| + EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
|
| + EXPECT_TRUE(push_stream);
|
| +
|
| + data.RunFor(1);
|
| +
|
| + EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
|
| + EXPECT_FALSE(push_stream);
|
| +
|
| + data.RunFor(2);
|
| +
|
| + EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
|
| +}
|
| +
|
| +// Receiving a duplicate header in a HEADERS frame should result in a
|
| +// protocol error.
|
| +TEST_P(SpdyStreamTest, DuplicateHeaders) {
|
| + GURL url(kStreamUrl);
|
| +
|
| + session_ =
|
| + SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
|
| +
|
| + scoped_ptr<SpdyFrame> initial_window_update(
|
| + spdy_util_.ConstructSpdyWindowUpdate(
|
| + kSessionFlowControlStreamId,
|
| + kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
|
| + if (spdy_util_.protocol() >= kProtoSPDY31)
|
| + AddWrite(*initial_window_update);
|
| +
|
| + scoped_ptr<SpdyFrame> syn(
|
| + spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
|
| + AddWrite(*syn);
|
| +
|
| + scoped_ptr<SpdyFrame>
|
| + reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
|
| + AddRead(*reply);
|
| +
|
| + scoped_ptr<SpdyFrame>
|
| + push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
|
| + AddRead(*push);
|
| +
|
| + scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
|
| + (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error";
|
| + scoped_ptr<SpdyFrame> headers_frame(
|
| + spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
|
| + false,
|
| + 2,
|
| + LOWEST,
|
| + HEADERS,
|
| + CONTROL_FLAG_NONE,
|
| + 0));
|
| + AddRead(*headers_frame);
|
| +
|
| + scoped_ptr<SpdyFrame> rst(
|
| + spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
|
| + AddWrite(*rst);
|
| +
|
| + AddReadEOF();
|
| +
|
| + DeterministicSocketData data(GetReads(), GetNumReads(),
|
| + GetWrites(), GetNumWrites());
|
| + MockConnect connect_data(SYNCHRONOUS, OK);
|
| + data.set_connect_data(connect_data);
|
| +
|
| + session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
|
| +
|
| + scoped_refptr<SpdySession> session(CreateSpdySession());
|
| +
|
| + InitializeSpdySession(session, host_port_pair_);
|
| +
|
| + base::WeakPtr<SpdyStream> stream =
|
| + CreateStreamSynchronously(
|
| + SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
|
| + ASSERT_TRUE(stream.get() != NULL);
|
| +
|
| + StreamDelegateDoNothing delegate(stream);
|
| + stream->SetDelegate(&delegate);
|
| +
|
| + EXPECT_FALSE(stream->HasUrl());
|
| +
|
| + scoped_ptr<SpdyHeaderBlock> headers(
|
| + spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
|
| + EXPECT_EQ(ERR_IO_PENDING,
|
| + stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
|
| + EXPECT_TRUE(stream->HasUrl());
|
| + EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
|
| +
|
| + // For the initial window update.
|
| + if (spdy_util_.protocol() >= kProtoSPDY31)
|
| + data.RunFor(1);
|
| +
|
| + data.RunFor(3);
|
| +
|
| + base::WeakPtr<SpdyStream> push_stream;
|
| + EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
|
| + EXPECT_TRUE(push_stream);
|
| +
|
| + data.RunFor(1);
|
| +
|
| + EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
|
| + EXPECT_FALSE(push_stream);
|
| +
|
| + data.RunFor(2);
|
| +
|
| + EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
|
| +}
|
| +
|
| // The tests below are only for SPDY/3 and above.
|
|
|
| // Call IncreaseSendWindowSize on a stream with a large enough delta
|
|
|