Make QuicSpdyStreamBodyBuffer manage consuming HEADERS frame header and payload.
Rename QuicSpdyStreamBodyBuffer::OnDataHeader(), update documentation, and rely
on it to calculate when HEADERS frame header and payload bytes need to be
consumed (but still call QuicStreamSequencer::MarkConsumed() from
QuicSpdyStream). Rip out MaybeMarkHeadersBytesConsumed() and
headers_bytes_to_be_marked_consumed_ from QuicSpdyStream, which are hacky and
cannot be extended to take care of PUSH_PROMISE frames and unknown frames.
gfe-relnote: n/a, change to QUIC v99-only code. Protected by existing disabled gfe2_reloadable_flag_quic_enable_version_99.
PiperOrigin-RevId: 260059055
Change-Id: I0b457e57e81a12693726a82050dafcefb08e96c8
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc
index c577225..ca1345d 100644
--- a/quic/core/http/quic_spdy_stream.cc
+++ b/quic/core/http/quic_spdy_stream.cc
@@ -185,7 +185,6 @@
trailers_decompressed_(false),
trailers_consumed_(false),
priority_sent_(false),
- headers_bytes_to_be_marked_consumed_(0),
http_decoder_visitor_(QuicMakeUnique<HttpDecoderVisitor>(this)),
decoder_(http_decoder_visitor_.get()),
sequencer_offset_(0),
@@ -221,7 +220,6 @@
trailers_decompressed_(false),
trailers_consumed_(false),
priority_sent_(false),
- headers_bytes_to_be_marked_consumed_(0),
http_decoder_visitor_(QuicMakeUnique<HttpDecoderVisitor>(this)),
decoder_(http_decoder_visitor_.get()),
sequencer_offset_(sequencer()->NumBytesConsumed()),
@@ -398,12 +396,6 @@
size_t bytes_read = 0;
sequencer()->MarkConsumed(body_buffer_.ReadBody(iov, iov_len, &bytes_read));
- if (VersionUsesQpack(transport_version())) {
- // Maybe all DATA frame bytes have been read and some trailing HEADERS had
- // already been processed, in which case MarkConsumed() should be called.
- MaybeMarkHeadersBytesConsumed();
- }
-
return bytes_read;
}
@@ -421,13 +413,8 @@
sequencer()->MarkConsumed(num_bytes);
return;
}
- sequencer()->MarkConsumed(body_buffer_.OnBodyConsumed(num_bytes));
- if (VersionUsesQpack(transport_version())) {
- // Maybe all DATA frame bytes have been read and some trailing HEADERS had
- // already been processed, in which case MarkConsumed() should be called.
- MaybeMarkHeadersBytesConsumed();
- }
+ sequencer()->MarkConsumed(body_buffer_.OnBodyConsumed(num_bytes));
}
bool QuicSpdyStream::IsDoneReading() const {
@@ -772,7 +759,7 @@
}
sequencer()->MarkConsumed(
- body_buffer_.OnDataHeader(frame_lengths.header_length));
+ body_buffer_.OnNonBody(frame_lengths.header_length));
return true;
}
@@ -780,7 +767,7 @@
bool QuicSpdyStream::OnDataFramePayload(QuicStringPiece payload) {
DCHECK(VersionHasDataFrameHeader(transport_version()));
- body_buffer_.OnDataPayload(payload);
+ body_buffer_.OnBody(payload);
return true;
}
@@ -827,16 +814,6 @@
}
}
-void QuicSpdyStream::MaybeMarkHeadersBytesConsumed() {
- DCHECK(VersionUsesQpack(transport_version()));
-
- if (!body_buffer_.HasBytesToRead() && !reading_stopped() &&
- headers_bytes_to_be_marked_consumed_ > 0) {
- sequencer()->MarkConsumed(headers_bytes_to_be_marked_consumed_);
- headers_bytes_to_be_marked_consumed_ = 0;
- }
-}
-
QuicByteCount QuicSpdyStream::GetNumFrameHeadersInInterval(
QuicStreamOffset offset,
QuicByteCount data_length) const {
@@ -862,6 +839,8 @@
return false;
}
+ sequencer()->MarkConsumed(body_buffer_.OnNonBody(frame_length.header_length));
+
if (headers_decompressed_) {
trailers_payload_length_ = frame_length.payload_length;
} else {
@@ -873,10 +852,6 @@
id(), spdy_session_->qpack_decoder(), this,
spdy_session_->max_inbound_header_list_size());
- // Do not call MaybeMarkHeadersBytesConsumed() yet, because
- // HEADERS frame header bytes might not have been parsed completely.
- headers_bytes_to_be_marked_consumed_ += frame_length.header_length;
-
return true;
}
@@ -885,8 +860,7 @@
const bool success = qpack_decoded_headers_accumulator_->Decode(payload);
- headers_bytes_to_be_marked_consumed_ += payload.size();
- MaybeMarkHeadersBytesConsumed();
+ sequencer()->MarkConsumed(body_buffer_.OnNonBody(payload.size()));
if (!success) {
// TODO(124216424): Use HTTP_QPACK_DECOMPRESSION_FAILED error code.
diff --git a/quic/core/http/quic_spdy_stream.h b/quic/core/http/quic_spdy_stream.h
index e030e93..bb111a9 100644
--- a/quic/core/http/quic_spdy_stream.h
+++ b/quic/core/http/quic_spdy_stream.h
@@ -259,10 +259,6 @@
// Called internally when headers are decoded.
void ProcessDecodedHeaders(const QuicHeaderList& headers);
- // Call QuicStreamSequencer::MarkConsumed() with
- // |headers_bytes_to_be_marked_consumed_| if appropriate.
- void MaybeMarkHeadersBytesConsumed();
-
// Given the interval marked by [|offset|, |offset| + |data_length|), return
// the number of frame header bytes contained in it.
QuicByteCount GetNumFrameHeadersInInterval(QuicStreamOffset offset,
@@ -295,9 +291,6 @@
// True if the stream has already sent an priority frame.
bool priority_sent_;
- // Number of bytes consumed while decoding HEADERS frames that cannot be
- // marked consumed in QuicStreamSequencer until later.
- QuicByteCount headers_bytes_to_be_marked_consumed_;
// The parsed trailers received from the peer.
spdy::SpdyHeaderBlock received_trailers_;
diff --git a/quic/core/http/quic_spdy_stream_body_buffer.cc b/quic/core/http/quic_spdy_stream_body_buffer.cc
index 2ae72b5..2c54167 100644
--- a/quic/core/http/quic_spdy_stream_body_buffer.cc
+++ b/quic/core/http/quic_spdy_stream_body_buffer.cc
@@ -13,25 +13,25 @@
QuicSpdyStreamBodyBuffer::QuicSpdyStreamBodyBuffer()
: total_body_bytes_received_(0) {}
-size_t QuicSpdyStreamBodyBuffer::OnDataHeader(QuicByteCount length) {
+size_t QuicSpdyStreamBodyBuffer::OnNonBody(QuicByteCount length) {
DCHECK_NE(0u, length);
if (fragments_.empty()) {
- // DATA frame header can be consumed immediately, because all previously
- // received DATA frame payload bytes have been read.
+ // Non-body bytes can be consumed immediately, because all previously
+ // received body bytes have been read.
return length;
}
- // DATA frame header length will be consumed after last fragment is read.
- fragments_.back().trailing_consumable_bytes += length;
+ // Non-body bytes will be consumed after last body fragment is read.
+ fragments_.back().trailing_non_body_byte_count += length;
return 0;
}
-void QuicSpdyStreamBodyBuffer::OnDataPayload(QuicStringPiece payload) {
- DCHECK(!payload.empty());
+void QuicSpdyStreamBodyBuffer::OnBody(QuicStringPiece body) {
+ DCHECK(!body.empty());
- fragments_.push_back({payload, 0});
- total_body_bytes_received_ += payload.length();
+ fragments_.push_back({body, 0});
+ total_body_bytes_received_ += body.length();
}
size_t QuicSpdyStreamBodyBuffer::OnBodyConsumed(size_t num_bytes) {
@@ -55,9 +55,9 @@
}
// Consume entire fragment and the following
- // |trailing_consumable_bytes| bytes.
+ // |trailing_non_body_byte_count| bytes.
remaining_bytes -= body.length();
- bytes_to_consume += body.length() + fragment.trailing_consumable_bytes;
+ bytes_to_consume += body.length() + fragment.trailing_non_body_byte_count;
fragments_.pop_front();
}
@@ -111,7 +111,7 @@
if (bytes_to_copy == body.length()) {
// Entire fragment read.
- bytes_to_consume += fragment.trailing_consumable_bytes;
+ bytes_to_consume += fragment.trailing_non_body_byte_count;
fragments_.pop_front();
} else {
// Consume leading |bytes_to_copy| bytes of body.
diff --git a/quic/core/http/quic_spdy_stream_body_buffer.h b/quic/core/http/quic_spdy_stream_body_buffer.h
index 77c17b8..c1a907a 100644
--- a/quic/core/http/quic_spdy_stream_body_buffer.h
+++ b/quic/core/http/quic_spdy_stream_body_buffer.h
@@ -15,33 +15,41 @@
namespace quic {
-// "Body" means DATA frame payload.
+// All data that a request stream receives falls into one of two categories:
+// * "body", that is, DATA frame payload, which the QuicStreamSequencer must
+// buffer until it is read;
+// * everything else, which QuicSpdyStream immediately processes and thus could
+// be marked as consumed with QuicStreamSequencer, unless there is some piece
+// of body received prior that still needs to be buffered.
// QuicSpdyStreamBodyBuffer does two things: it keeps references to body
// fragments (owned by QuicStreamSequencer) and offers methods to read them; and
-// calculates the total number of bytes (including DATA frame headers) the
-// caller needs to mark consumed (with QuicStreamSequencer) whenever DATA frame
-// headers are received or body bytes are read.
+// it calculates the total number of bytes (including non-body bytes) the caller
+// needs to mark consumed (with QuicStreamSequencer) when non-body bytes are
+// received or when body is consumed.
// TODO(bnc): Rename to QuicSpdyStreamBodyManager or similar.
class QUIC_EXPORT_PRIVATE QuicSpdyStreamBodyBuffer {
public:
QuicSpdyStreamBodyBuffer();
~QuicSpdyStreamBodyBuffer() = default;
- // Called when DATA frame header bytes are received. |length| must be
- // positive. Returns number of bytes the caller shall mark consumed, which
- // might be zero.
- QUIC_MUST_USE_RESULT size_t OnDataHeader(QuicByteCount length);
+ // One of the following two methods must be called every time data is received
+ // on the request stream.
- // Called when DATA frame payload is received. |payload| is added to
- // |fragments_|. The data pointed to by |payload| must be kept alive until an
- // OnBodyConsumed() or ReadBody() call consumes it. |payload| must not be
- // empty.
- void OnDataPayload(QuicStringPiece payload);
+ // Called when data that could immediately be marked consumed with the
+ // sequencer (provided that all previous body fragments are consumed) is
+ // received. |length| must be positive. Returns number of bytes the caller
+ // must mark consumed, which might be zero.
+ QUIC_MUST_USE_RESULT size_t OnNonBody(QuicByteCount length);
- // Internally marks |num_bytes| of DATA frame payload consumed. |num_bytes|
- // might be zero. Returns the number of bytes that the caller should mark
- // consumed with the sequencer, which is the sum of |num_bytes| for payload
- // and additional DATA frame header bytes, if any.
+ // Called when body is received. |body| is added to |fragments_|. The data
+ // pointed to by |body| must be kept alive until an OnBodyConsumed() or
+ // ReadBody() call consumes it. |body| must not be empty.
+ void OnBody(QuicStringPiece body);
+
+ // Internally marks |num_bytes| of body consumed. |num_bytes| might be zero.
+ // Returns the number of bytes that the caller should mark consumed with the
+ // sequencer, which is the sum of |num_bytes| for body, and the number of any
+ // interleaving or immediately trailing non-body bytes.
QUIC_MUST_USE_RESULT size_t OnBodyConsumed(size_t num_bytes);
// Set up to |iov_len| elements of iov[] to point to available bodies: each
@@ -51,11 +59,11 @@
int PeekBody(iovec* iov, size_t iov_len) const;
// Copies data from available bodies into at most |iov_len| elements of iov[].
- // Internally consumes copied payload bytes as well as all interleaving and
- // immediately following DATA frame header bytes. |iov.iov_base| and
- // |iov.iov_len| are preassigned and will not be changed. Returns the total
- // number of bytes the caller shall mark consumed. Sets
- // |*total_bytes_read| to the total number of DATA payload bytes read.
+ // Internally consumes copied body bytes as well as all interleaving and
+ // immediately trailing non-body bytes. |iov.iov_base| and |iov.iov_len| are
+ // preassigned and will not be changed. Returns the total number of bytes the
+ // caller shall mark consumed. Sets |*total_bytes_read| to the total number
+ // of body bytes read.
QUIC_MUST_USE_RESULT size_t ReadBody(const struct iovec* iov,
size_t iov_len,
size_t* total_bytes_read);
@@ -74,9 +82,9 @@
// |body| must not be empty.
QuicStringPiece body;
// Might be zero.
- QuicByteCount trailing_consumable_bytes;
+ QuicByteCount trailing_non_body_byte_count;
};
- // Queue of DATA frame payload fragments and byte counts.
+ // Queue of body fragments and trailing non-body byte counts.
QuicDeque<Fragment> fragments_;
// Total body bytes received.
QuicByteCount total_body_bytes_received_;
diff --git a/quic/core/http/quic_spdy_stream_body_buffer_test.cc b/quic/core/http/quic_spdy_stream_body_buffer_test.cc
index 7c4787d..ef9dfe2 100644
--- a/quic/core/http/quic_spdy_stream_body_buffer_test.cc
+++ b/quic/core/http/quic_spdy_stream_body_buffer_test.cc
@@ -29,13 +29,13 @@
EXPECT_EQ(0u, body_buffer_.total_body_bytes_received());
const QuicByteCount header_length = 3;
- EXPECT_EQ(header_length, body_buffer_.OnDataHeader(header_length));
+ EXPECT_EQ(header_length, body_buffer_.OnNonBody(header_length));
EXPECT_FALSE(body_buffer_.HasBytesToRead());
EXPECT_EQ(0u, body_buffer_.total_body_bytes_received());
std::string body(1024, 'a');
- body_buffer_.OnDataPayload(body);
+ body_buffer_.OnBody(body);
EXPECT_TRUE(body_buffer_.HasBytesToRead());
EXPECT_EQ(1024u, body_buffer_.total_body_bytes_received());
@@ -43,7 +43,7 @@
TEST_F(QuicSpdyStreamBodyBufferTest, ConsumeMoreThanAvailable) {
std::string body(1024, 'a');
- body_buffer_.OnDataPayload(body);
+ body_buffer_.OnBody(body);
size_t bytes_to_consume = 0;
EXPECT_QUIC_BUG(bytes_to_consume = body_buffer_.OnBodyConsumed(2048),
"Not enough available body to consume.");
@@ -91,8 +91,8 @@
// other frames. Each test case start with an empty
// QuicSpdyStreamBodyBuffer.
EXPECT_EQ(frame_index == 0 ? frame_header_lengths[frame_index] : 0u,
- body_buffer_.OnDataHeader(frame_header_lengths[frame_index]));
- body_buffer_.OnDataPayload(frame_payloads[frame_index]);
+ body_buffer_.OnNonBody(frame_header_lengths[frame_index]));
+ body_buffer_.OnBody(frame_payloads[frame_index]);
}
for (size_t call_index = 0; call_index < body_bytes_to_read.size();
@@ -141,8 +141,8 @@
// other frames. Each test case uses a new QuicSpdyStreamBodyBuffer
// instance.
EXPECT_EQ(frame_index == 0 ? frame_header_lengths[frame_index] : 0u,
- body_buffer.OnDataHeader(frame_header_lengths[frame_index]));
- body_buffer.OnDataPayload(frame_payloads[frame_index]);
+ body_buffer.OnNonBody(frame_header_lengths[frame_index]));
+ body_buffer.OnBody(frame_payloads[frame_index]);
}
std::vector<iovec> iovecs;
@@ -238,8 +238,8 @@
// other frames. Each test case uses a new QuicSpdyStreamBodyBuffer
// instance.
EXPECT_EQ(frame_index == 0 ? frame_header_lengths[frame_index] : 0u,
- body_buffer.OnDataHeader(frame_header_lengths[frame_index]));
- body_buffer.OnDataPayload(frame_payloads[frame_index]);
+ body_buffer.OnNonBody(frame_header_lengths[frame_index]));
+ body_buffer.OnBody(frame_payloads[frame_index]);
received_body.append(frame_payloads[frame_index]);
}
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc
index 20c1b65..5b2ca81 100644
--- a/quic/core/http/quic_spdy_stream_test.cc
+++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -2098,8 +2098,7 @@
HeadersFrame(QuicTextUtils::HexDecode("00002a94e703626172"));
// All HEADERS frame bytes are consumed even if the frame is not received
- // completely (as long as at least some of the payload is received, which is
- // an implementation detail that should not be tested).
+ // completely.
OnStreamFrame(QuicStringPiece(headers).substr(0, headers.size() - 1));
EXPECT_EQ(headers.size() - 1, NewlyConsumedBytes());