| Index: net/spdy/spdy_stream_unittest.cc
|
| diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc
|
| index 53452bed815728c3daa08c97c6a7fd93b0a9e5c7..64d0f8e0ffdd030d03d3112c1297ae0d2b1a21a7 100644
|
| --- a/net/spdy/spdy_stream_unittest.cc
|
| +++ b/net/spdy/spdy_stream_unittest.cc
|
| @@ -553,8 +553,8 @@ TEST_F(SpdyStreamTest, UpperCaseHeaders) {
|
| AddWrite(req);
|
|
|
| const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
|
| - SpdySerializedFrame reply(
|
| - spdy_util_.ConstructSpdyGetReply(kExtraHeaders, 1, 1));
|
| + SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(
|
| + kExtraHeaders, arraysize(kExtraHeaders) / 2, 1));
|
| AddRead(reply);
|
|
|
| SpdySerializedFrame rst(
|
| @@ -589,6 +589,9 @@ TEST_F(SpdyStreamTest, UpperCaseHeaders) {
|
| EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec());
|
|
|
| EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR));
|
| +
|
| + EXPECT_TRUE(data.AllWriteDataConsumed());
|
| + EXPECT_TRUE(data.AllReadDataConsumed());
|
| }
|
|
|
| // Receiving a header with uppercase ASCII should result in a protocol error
|
| @@ -601,9 +604,9 @@ TEST_F(SpdyStreamTest, UpperCaseHeadersOnPush) {
|
| SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
|
| AddRead(reply);
|
|
|
| - const char* const extra_headers[] = {"X-UpperCase", "yes"};
|
| - SpdySerializedFrame push(
|
| - spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kPushUrl));
|
| + const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
|
| + SpdySerializedFrame push(spdy_util_.ConstructSpdyPush(
|
| + kExtraHeaders, arraysize(kExtraHeaders) / 2, 2, 1, kPushUrl));
|
| AddRead(push);
|
|
|
| SpdySerializedFrame rst(
|
| @@ -650,36 +653,92 @@ TEST_F(SpdyStreamTest, UpperCaseHeadersOnPush) {
|
| data.Resume();
|
|
|
| EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
|
| +
|
| + EXPECT_TRUE(data.AllWriteDataConsumed());
|
| + EXPECT_TRUE(data.AllReadDataConsumed());
|
| }
|
|
|
| -// Receiving a header with uppercase ASCII in a HEADERS frame should result in a
|
| -// protocol error.
|
| -TEST_F(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
|
| +TEST_F(SpdyStreamTest, HeadersMustHaveStatus) {
|
| SpdySerializedFrame req(
|
| spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
|
| AddWrite(req);
|
|
|
| - SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
|
| + // Response headers without ":status" header field: protocol error.
|
| + SpdyHeaderBlock header_block_without_status;
|
| + header_block_without_status[spdy_util_.GetMethodKey()] = "GET";
|
| + header_block_without_status[spdy_util_.GetHostKey()] = "www.example.org";
|
| + header_block_without_status[spdy_util_.GetSchemeKey()] = "https";
|
| + header_block_without_status[spdy_util_.GetPathKey()] = "/";
|
| + SpdySerializedFrame reply(
|
| + spdy_util_.ConstructSpdyReply(1, std::move(header_block_without_status)));
|
| AddRead(reply);
|
|
|
| - SpdySerializedFrame push(
|
| - spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushUrl));
|
| - AddRead(push);
|
| + SpdySerializedFrame rst(
|
| + spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
|
| + AddWrite(rst);
|
|
|
| - AddReadPause();
|
| + AddReadEOF();
|
|
|
| - SpdyHeaderBlock late_headers;
|
| - late_headers["X-UpperCase"] = "yes";
|
| - SpdySerializedFrame headers_frame(
|
| - spdy_util_.ConstructSpdyReply(2, std::move(late_headers)));
|
| - AddRead(headers_frame);
|
| + SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(),
|
| + GetNumWrites());
|
| + MockConnect connect_data(SYNCHRONOUS, OK);
|
| + data.set_connect_data(connect_data);
|
| + session_deps_.socket_factory->AddSocketDataProvider(&data);
|
| +
|
| + AddSSLSocketData();
|
| +
|
| + base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
|
| +
|
| + base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
|
| + SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource());
|
| + ASSERT_TRUE(stream);
|
| +
|
| + StreamDelegateDoNothing delegate(stream);
|
| + stream->SetDelegate(&delegate);
|
|
|
| - AddWritePause();
|
| + EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
|
| +
|
| + SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
|
| + EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers),
|
| + NO_MORE_DATA_TO_SEND));
|
| + EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec());
|
| +
|
| + EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR));
|
| +
|
| + EXPECT_TRUE(data.AllWriteDataConsumed());
|
| + EXPECT_TRUE(data.AllReadDataConsumed());
|
| +}
|
| +
|
| +TEST_F(SpdyStreamTest, HeadersMustHaveStatusOnPushedStream) {
|
| + SpdySerializedFrame req(
|
| + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
|
| + AddWrite(req);
|
| +
|
| + SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
|
| + AddRead(reply);
|
| +
|
| + SpdySerializedFrame push_promise(spdy_util_.ConstructInitialSpdyPushFrame(
|
| + spdy_util_.ConstructGetHeaderBlock(kPushUrl), 2, 1));
|
| + AddRead(push_promise);
|
| +
|
| + // Response headers without ":status" header field: protocol error.
|
| + SpdyHeaderBlock header_block_without_status;
|
| + header_block_without_status[spdy_util_.GetMethodKey()] = "GET";
|
| + header_block_without_status[spdy_util_.GetHostKey()] = "www.example.org";
|
| + header_block_without_status[spdy_util_.GetSchemeKey()] = "https";
|
| + header_block_without_status[spdy_util_.GetPathKey()] = "/";
|
| + SpdySerializedFrame pushed_reply(
|
| + spdy_util_.ConstructSpdyReply(2, std::move(header_block_without_status)));
|
| + AddRead(pushed_reply);
|
|
|
| SpdySerializedFrame rst(
|
| spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
|
| AddWrite(rst);
|
|
|
| + SpdySerializedFrame body(
|
| + spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true));
|
| + AddRead(body);
|
| +
|
| AddReadEOF();
|
|
|
| SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(),
|
| @@ -707,30 +766,59 @@ TEST_F(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
|
| IsError(ERR_IO_PENDING));
|
| EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec());
|
|
|
| - data.RunUntilPaused();
|
| + EXPECT_THAT(delegate.WaitForClose(), IsOk());
|
| + EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
|
| + EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
|
| + delegate.TakeReceivedData());
|
|
|
| - base::WeakPtr<SpdyStream> push_stream;
|
| - EXPECT_THAT(
|
| - session->GetPushStream(GURL(kPushUrl), &push_stream, NetLogWithSource()),
|
| - IsOk());
|
| - EXPECT_TRUE(push_stream);
|
| + EXPECT_TRUE(data.AllWriteDataConsumed());
|
| + EXPECT_TRUE(data.AllReadDataConsumed());
|
| +}
|
|
|
| - data.Resume();
|
| - data.RunUntilPaused();
|
| +TEST_F(SpdyStreamTest, HeadersMustPreceedData) {
|
| + SpdySerializedFrame req(
|
| + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
|
| + AddWrite(req);
|
|
|
| - EXPECT_THAT(
|
| - session->GetPushStream(GURL(kPushUrl), &push_stream, NetLogWithSource()),
|
| - IsOk());
|
| - EXPECT_FALSE(push_stream);
|
| + // Response body not preceeded by headers: protocol error.
|
| + SpdySerializedFrame body(
|
| + spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true));
|
| + AddRead(body);
|
|
|
| - data.Resume();
|
| + SpdySerializedFrame rst(
|
| + spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
|
| + AddWrite(rst);
|
|
|
| - EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
|
| + AddReadEOF();
|
| +
|
| + SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(),
|
| + GetNumWrites());
|
| + MockConnect connect_data(SYNCHRONOUS, OK);
|
| + data.set_connect_data(connect_data);
|
| + session_deps_.socket_factory->AddSocketDataProvider(&data);
|
| +
|
| + AddSSLSocketData();
|
| +
|
| + base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
|
| +
|
| + base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
|
| + SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource());
|
| + ASSERT_TRUE(stream);
|
| +
|
| + StreamDelegateDoNothing delegate(stream);
|
| + stream->SetDelegate(&delegate);
|
| +
|
| + EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
|
| +
|
| + SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
|
| + EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers),
|
| + NO_MORE_DATA_TO_SEND));
|
| + EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec());
|
| +
|
| + EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR));
|
| }
|
|
|
| -// Receiving a duplicate header in a HEADERS frame should result in a protocol
|
| -// error.
|
| -TEST_F(SpdyStreamTest, DuplicateHeaders) {
|
| +TEST_F(SpdyStreamTest, HeadersMustPreceedDataOnPushedStream) {
|
| SpdySerializedFrame req(
|
| spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
|
| AddWrite(req);
|
| @@ -738,24 +826,22 @@ TEST_F(SpdyStreamTest, DuplicateHeaders) {
|
| SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
|
| AddRead(reply);
|
|
|
| - SpdySerializedFrame push(
|
| - spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushUrl));
|
| - AddRead(push);
|
| -
|
| - AddReadPause();
|
| -
|
| - SpdyHeaderBlock late_headers;
|
| - late_headers[spdy_util_.GetStatusKey()] = "500 Server Error";
|
| - SpdySerializedFrame headers_frame(
|
| - spdy_util_.ConstructSpdyReply(2, std::move(late_headers)));
|
| - AddRead(headers_frame);
|
| + SpdySerializedFrame push_promise(spdy_util_.ConstructInitialSpdyPushFrame(
|
| + spdy_util_.ConstructGetHeaderBlock(kPushUrl), 2, 1));
|
| + AddRead(push_promise);
|
|
|
| - AddReadPause();
|
| + SpdySerializedFrame pushed_body(
|
| + spdy_util_.ConstructSpdyDataFrame(2, kPostBody, kPostBodyLength, true));
|
| + AddRead(pushed_body);
|
|
|
| SpdySerializedFrame rst(
|
| spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
|
| AddWrite(rst);
|
|
|
| + SpdySerializedFrame body(
|
| + spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true));
|
| + AddRead(body);
|
| +
|
| AddReadEOF();
|
|
|
| SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(),
|
| @@ -783,25 +869,129 @@ TEST_F(SpdyStreamTest, DuplicateHeaders) {
|
| IsError(ERR_IO_PENDING));
|
| EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec());
|
|
|
| - data.RunUntilPaused();
|
| + EXPECT_THAT(delegate.WaitForClose(), IsOk());
|
| + EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
|
| + EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
|
| + delegate.TakeReceivedData());
|
|
|
| - base::WeakPtr<SpdyStream> push_stream;
|
| - EXPECT_THAT(
|
| - session->GetPushStream(GURL(kPushUrl), &push_stream, NetLogWithSource()),
|
| - IsOk());
|
| - EXPECT_TRUE(push_stream);
|
| + EXPECT_TRUE(data.AllWriteDataConsumed());
|
| + EXPECT_TRUE(data.AllReadDataConsumed());
|
| +}
|
|
|
| - data.Resume();
|
| - data.RunUntilPaused();
|
| +TEST_F(SpdyStreamTest, TrailersMustNotFollowTrailers) {
|
| + SpdySerializedFrame req(
|
| + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
|
| + AddWrite(req);
|
|
|
| - EXPECT_THAT(
|
| - session->GetPushStream(GURL(kPushUrl), &push_stream, NetLogWithSource()),
|
| - IsOk());
|
| - EXPECT_FALSE(push_stream);
|
| + SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
|
| + AddRead(reply);
|
|
|
| - data.Resume();
|
| + SpdySerializedFrame body(
|
| + spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false));
|
| + AddRead(body);
|
|
|
| - EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
|
| + SpdyHeaderBlock trailers_block;
|
| + trailers_block["foo"] = "bar";
|
| + SpdySerializedFrame first_trailers(spdy_util_.ConstructSpdyResponseHeaders(
|
| + 1, std::move(trailers_block), false));
|
| + AddRead(first_trailers);
|
| +
|
| + // Trailers following trailers: procotol error.
|
| + SpdySerializedFrame second_trailers(spdy_util_.ConstructSpdyResponseHeaders(
|
| + 1, std::move(trailers_block), true));
|
| + AddRead(second_trailers);
|
| +
|
| + SpdySerializedFrame rst(
|
| + spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
|
| + AddWrite(rst);
|
| +
|
| + AddReadEOF();
|
| +
|
| + SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(),
|
| + GetNumWrites());
|
| + MockConnect connect_data(SYNCHRONOUS, OK);
|
| + data.set_connect_data(connect_data);
|
| + session_deps_.socket_factory->AddSocketDataProvider(&data);
|
| +
|
| + AddSSLSocketData();
|
| +
|
| + base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
|
| +
|
| + base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
|
| + SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource());
|
| + ASSERT_TRUE(stream);
|
| +
|
| + StreamDelegateDoNothing delegate(stream);
|
| + stream->SetDelegate(&delegate);
|
| +
|
| + EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
|
| +
|
| + SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
|
| + EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers),
|
| + NO_MORE_DATA_TO_SEND));
|
| + EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec());
|
| +
|
| + EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR));
|
| +
|
| + EXPECT_TRUE(data.AllWriteDataConsumed());
|
| + EXPECT_TRUE(data.AllReadDataConsumed());
|
| +}
|
| +
|
| +TEST_F(SpdyStreamTest, DataMustNotFollowTrailers) {
|
| + SpdySerializedFrame req(
|
| + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
|
| + AddWrite(req);
|
| +
|
| + SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
|
| + AddRead(reply);
|
| +
|
| + SpdySerializedFrame body(
|
| + spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false));
|
| + AddRead(body);
|
| +
|
| + SpdyHeaderBlock trailers_block;
|
| + trailers_block["foo"] = "bar";
|
| + SpdySerializedFrame trailers(spdy_util_.ConstructSpdyResponseHeaders(
|
| + 1, std::move(trailers_block), false));
|
| + AddRead(trailers);
|
| +
|
| + // DATA frame following trailers: protocol error.
|
| + AddRead(body);
|
| +
|
| + SpdySerializedFrame rst(
|
| + spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
|
| + AddWrite(rst);
|
| +
|
| + AddReadEOF();
|
| +
|
| + SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(),
|
| + GetNumWrites());
|
| + MockConnect connect_data(SYNCHRONOUS, OK);
|
| + data.set_connect_data(connect_data);
|
| + session_deps_.socket_factory->AddSocketDataProvider(&data);
|
| +
|
| + AddSSLSocketData();
|
| +
|
| + base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
|
| +
|
| + base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
|
| + SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource());
|
| + ASSERT_TRUE(stream);
|
| +
|
| + StreamDelegateDoNothing delegate(stream);
|
| + stream->SetDelegate(&delegate);
|
| +
|
| + EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
|
| +
|
| + SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
|
| + EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers),
|
| + NO_MORE_DATA_TO_SEND));
|
| + EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec());
|
| +
|
| + EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR));
|
| +
|
| + EXPECT_TRUE(data.AllWriteDataConsumed());
|
| + EXPECT_TRUE(data.AllReadDataConsumed());
|
| }
|
|
|
| // Call IncreaseSendWindowSize on a stream with a large enough delta to overflow
|
|
|