Use GetReadableRegion() instead of PeekRegion() in QuicReceiveControlStream::OnDataAvailable().
This has been recommended at https://crbug.com/982648#c8.
gfe-relnote: n/a, change in QUIC v99-only class.
PiperOrigin-RevId: 258251582
Change-Id: If7343673d8ec17b668059bac25aa05859551ed96
diff --git a/quic/core/http/quic_receive_control_stream.cc b/quic/core/http/quic_receive_control_stream.cc
index ee92720..c01040b 100644
--- a/quic/core/http/quic_receive_control_stream.cc
+++ b/quic/core/http/quic_receive_control_stream.cc
@@ -133,11 +133,9 @@
QuicReceiveControlStream::QuicReceiveControlStream(PendingStream* pending)
: QuicStream(pending, READ_UNIDIRECTIONAL, /*is_static=*/true),
- current_priority_length_(0),
- received_settings_length_(0),
+ settings_frame_received_(false),
http_decoder_visitor_(QuicMakeUnique<HttpDecoderVisitor>(this)),
- decoder_(http_decoder_visitor_.get()),
- sequencer_offset_(sequencer()->NumBytesConsumed()) {
+ decoder_(http_decoder_visitor_.get()) {
sequencer()->set_level_triggered(true);
}
@@ -154,31 +152,36 @@
void QuicReceiveControlStream::OnDataAvailable() {
iovec iov;
- while (session()->connection()->connected() && !reading_stopped() &&
- decoder_.error() == QUIC_NO_ERROR) {
- DCHECK_GE(sequencer_offset_, sequencer()->NumBytesConsumed());
- if (!sequencer()->PeekRegion(sequencer_offset_, &iov)) {
- break;
- }
-
+ while (!reading_stopped() && decoder_.error() == QUIC_NO_ERROR &&
+ sequencer()->GetReadableRegion(&iov)) {
DCHECK(!sequencer()->IsClosed());
+
QuicByteCount processed_bytes = decoder_.ProcessInput(
reinterpret_cast<const char*>(iov.iov_base), iov.iov_len);
- sequencer_offset_ += processed_bytes;
+ sequencer()->MarkConsumed(processed_bytes);
+
+ if (!session()->connection()->connected()) {
+ return;
+ }
+
+ // The only reason QuicReceiveControlStream pauses HttpDecoder is an error,
+ // in which case the connection would have already been closed.
+ DCHECK_EQ(iov.iov_len, processed_bytes);
}
}
bool QuicReceiveControlStream::OnSettingsFrameStart(
- Http3FrameLengths frame_lengths) {
- if (received_settings_length_ != 0) {
+ Http3FrameLengths /* frame_lengths */) {
+ if (settings_frame_received_) {
// TODO(renjietang): Change error code to HTTP_UNEXPECTED_FRAME.
session()->connection()->CloseConnection(
QUIC_INVALID_STREAM_ID, "Settings frames are received twice.",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return false;
}
- received_settings_length_ +=
- frame_lengths.header_length + frame_lengths.payload_length;
+
+ settings_frame_received_ = true;
+
return true;
}
@@ -199,16 +202,12 @@
break;
}
}
- sequencer()->MarkConsumed(received_settings_length_);
return true;
}
bool QuicReceiveControlStream::OnPriorityFrameStart(
- Http3FrameLengths frame_lengths) {
+ Http3FrameLengths /* frame_lengths */) {
DCHECK_EQ(Perspective::IS_SERVER, session()->perspective());
- DCHECK_EQ(0u, current_priority_length_);
- current_priority_length_ =
- frame_lengths.header_length + frame_lengths.payload_length;
return true;
}
@@ -222,8 +221,6 @@
if (stream) {
stream->SetPriority(priority.weight);
}
- sequencer()->MarkConsumed(current_priority_length_);
- current_priority_length_ = 0;
return true;
}
diff --git a/quic/core/http/quic_receive_control_stream.h b/quic/core/http/quic_receive_control_stream.h
index 1bd13fe..f83b980 100644
--- a/quic/core/http/quic_receive_control_stream.h
+++ b/quic/core/http/quic_receive_control_stream.h
@@ -41,21 +41,12 @@
// TODO(renjietang): Decode Priority in HTTP/3 style.
bool OnPriorityFrame(const PriorityFrame& priority);
- // Track the current priority frame length.
- QuicByteCount current_priority_length_;
-
- // Track the number of settings bytes received.
- size_t received_settings_length_;
+ // False until a SETTINGS frame is received.
+ bool settings_frame_received_;
// HttpDecoder and its visitor.
std::unique_ptr<HttpDecoderVisitor> http_decoder_visitor_;
HttpDecoder decoder_;
-
- // Sequencer offset keeping track of how much data HttpDecoder has processed.
- // Initial value is sequencer()->NumBytesConsumed() at time of
- // QuicReceiveControlStream construction: that is the length of the
- // unidirectional stream type at the beginning of the stream.
- QuicStreamOffset sequencer_offset_;
};
} // namespace quic
diff --git a/quic/core/http/quic_receive_control_stream_test.cc b/quic/core/http/quic_receive_control_stream_test.cc
index 49c31d1..412ee0c 100644
--- a/quic/core/http/quic_receive_control_stream_test.cc
+++ b/quic/core/http/quic_receive_control_stream_test.cc
@@ -135,20 +135,45 @@
EXPECT_EQ(5u, session_.max_outbound_header_list_size());
}
+// Regression test for https://crbug.com/982648.
+// QuicReceiveControlStream::OnDataAvailable() must stop processing input as
+// soon as OnSettingsFrameStart() is called by HttpDecoder for the second frame.
TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsTwice) {
SettingsFrame settings;
- settings.values[3] = 2;
- settings.values[kSettingsMaxHeaderListSize] = 5;
- std::string data = EncodeSettings(settings);
- QuicStreamFrame frame(receive_control_stream_->id(), false, 0,
- QuicStringPiece(data));
- QuicStreamFrame frame2(receive_control_stream_->id(), false, data.length(),
- QuicStringPiece(data));
- receive_control_stream_->OnStreamFrame(frame);
+ // Reserved identifiers, must be ignored.
+ settings.values[0x21] = 100;
+ settings.values[0x40] = 200;
+
+ std::string settings_frame = EncodeSettings(settings);
+
+ EXPECT_EQ(0u, NumBytesConsumed());
+
+ // Receive first SETTINGS frame.
+ receive_control_stream_->OnStreamFrame(
+ QuicStreamFrame(receive_control_stream_->id(), /* fin = */ false,
+ /* offset = */ 0, settings_frame));
+
+ // First SETTINGS frame is consumed.
+ EXPECT_EQ(settings_frame.size(), NumBytesConsumed());
+
+ // Second SETTINGS frame causes the connection to be closed.
EXPECT_CALL(*connection_,
CloseConnection(QUIC_INVALID_STREAM_ID,
- "Settings frames are received twice.", _));
- receive_control_stream_->OnStreamFrame(frame2);
+ "Settings frames are received twice.", _))
+ .WillOnce(
+ Invoke(connection_, &MockQuicConnection::ReallyCloseConnection));
+ EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _));
+ EXPECT_CALL(session_, OnConnectionClosed(_, _));
+
+ // Receive second SETTINGS frame.
+ receive_control_stream_->OnStreamFrame(
+ QuicStreamFrame(receive_control_stream_->id(), /* fin = */ false,
+ /* offset = */ settings_frame.size(), settings_frame));
+
+ // Frame header of second SETTINGS frame is consumed, but not frame payload.
+ QuicByteCount settings_frame_header_length = 2;
+ EXPECT_EQ(settings_frame.size() + settings_frame_header_length,
+ NumBytesConsumed());
}
TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsFragments) {
@@ -217,43 +242,6 @@
receive_control_stream_->OnStreamFrame(frame);
}
-// Regression test for https://crbug.com/982648.
-// QuicReceiveControlStream::OnDataAvailable() must stop processing input as
-// soon as OnSettingsFrameStart() is called by HttpDecoder for the second frame.
-TEST_P(QuicReceiveControlStreamTest, StopProcessingIfConnectionClosed) {
- SettingsFrame settings;
- // Reserved identifiers, must be ignored.
- settings.values[0x21] = 100;
- settings.values[0x40] = 200;
-
- std::string settings_frame = EncodeSettings(settings);
-
- EXPECT_EQ(0u, NumBytesConsumed());
-
- // Receive first SETTINGS frame.
- receive_control_stream_->OnStreamFrame(
- QuicStreamFrame(receive_control_stream_->id(), /* fin = */ false,
- /* offset = */ 0, settings_frame));
-
- // First SETTINGS frame is consumed.
- EXPECT_EQ(settings_frame.size(), NumBytesConsumed());
-
- // Second SETTINGS frame causes the connection to be closed.
- EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _))
- .WillOnce(
- Invoke(connection_, &MockQuicConnection::ReallyCloseConnection));
- EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _));
- EXPECT_CALL(session_, OnConnectionClosed(_, _));
-
- // Receive second SETTINGS frame.
- receive_control_stream_->OnStreamFrame(
- QuicStreamFrame(receive_control_stream_->id(), /* fin = */ false,
- /* offset = */ settings_frame.size(), settings_frame));
-
- // No new data is consumed.
- EXPECT_EQ(settings_frame.size(), NumBytesConsumed());
-}
-
} // namespace
} // namespace test
} // namespace quic