Commit 087d4ba0 authored by Bence Béky's avatar Bence Béky Committed by Commit Bot

Prevent crash in SpdyHttpStream::OnDataSent() when sending greased frames.

Do not call HasUploadData() from OnDataSent() if |request_info_| is
already reset when response headers are received.

Bug: 1082196
Change-Id: I2bfac8ba5eb9d4694f2eb1078275713176fc86dc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2198544
Commit-Queue: David Schinazi <dschinazi@chromium.org>
Auto-Submit: Bence Béky <bnc@chromium.org>
Reviewed-by: default avatarDavid Schinazi <dschinazi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#768519}
parent 6059c240
...@@ -452,7 +452,7 @@ void SpdyHttpStream::OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) { ...@@ -452,7 +452,7 @@ void SpdyHttpStream::OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) {
} }
void SpdyHttpStream::OnDataSent() { void SpdyHttpStream::OnDataSent() {
if (HasUploadData()) { if (request_info_ && HasUploadData()) {
request_body_buf_size_ = 0; request_body_buf_size_ = 0;
ReadAndSendRequestBodyData(); ReadAndSendRequestBodyData();
} else { } else {
......
...@@ -10372,4 +10372,70 @@ TEST_F(SpdyNetworkTransactionTest, DoNotGreaseFrameTypeWithConnect) { ...@@ -10372,4 +10372,70 @@ TEST_F(SpdyNetworkTransactionTest, DoNotGreaseFrameTypeWithConnect) {
EXPECT_EQ("hello", response_data); EXPECT_EQ("hello", response_data);
} }
// Regression test for https://crbug.com/1081955.
// Greasing frame types is enabled, the outgoing HEADERS frame is followed by a
// frame of reserved type, then an empty DATA frame to close the stream.
// Response arrives before reserved frame and DATA frame can be sent.
// SpdyHttpStream::OnDataSent() must not crash.
TEST_F(SpdyNetworkTransactionTest, OnDataSentDoesNotCrashWithGreasedFrameType) {
auto session_deps = std::make_unique<SpdySessionDependencies>();
const uint8_t type = 0x0b;
const uint8_t flags = 0xcc;
const std::string payload("foo");
session_deps->greased_http2_frame =
base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
{type, flags, payload});
NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
std::move(session_deps));
spdy::SpdyHeaderBlock headers(
spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy::SpdySerializedFrame req(
spdy_util_.ConstructSpdyHeaders(1, std::move(headers), DEFAULT_PRIORITY,
/* fin = */ false));
const char kRawFrameData[] = {
0x00, 0x00, 0x03, // length
0x0b, // type
0xcc, // flags
0x00, 0x00, 0x00, 0x01, // stream ID
'f', 'o', 'o' // payload
};
spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
base::size(kRawFrameData),
/* owns_buffer = */ false);
spdy::SpdySerializedFrame empty_body(
spdy_util_.ConstructSpdyDataFrame(1, "", true));
MockWrite writes[] = {
CreateMockWrite(req, 0), MockWrite(ASYNC, ERR_IO_PENDING, 2),
CreateMockWrite(grease, 3), CreateMockWrite(empty_body, 4)};
spdy::SpdySerializedFrame resp(
spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
spdy::SpdySerializedFrame response_body(
spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(response_body, 5),
MockRead(ASYNC, 0, 6)};
SequencedSocketData data(reads, writes);
helper.RunPreTestSetup();
helper.AddData(&data);
TestCompletionCallback callback;
int rv = helper.trans()->Start(&request_, callback.callback(), log_);
base::RunLoop().RunUntilIdle();
// Response headers received. Resume sending |grease| and |empty_body|.
data.Resume();
EXPECT_THAT(callback.GetResult(rv), IsOk());
base::RunLoop().RunUntilIdle();
helper.VerifyDataConsumed();
}
} // namespace net } // namespace net
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment