Change HTTP/3 frame type from 1 byte integer to variable length integer, and
allow partial delivery.
gfe-relnote: Used in version 99 only.
PiperOrigin-RevId: 244287295
Change-Id: Ic9a58f2822815006295f47f23f312b1f2c040f4e
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc
index ec0062a..653652f 100644
--- a/quic/core/http/http_decoder.cc
+++ b/quic/core/http/http_decoder.cc
@@ -24,8 +24,6 @@
return (flags >> offset) & GetMaskFromNumBits(num_bits);
}
-// Length of the type field of HTTP/3 frames.
-static const QuicByteCount kFrameTypeLength = 1;
// Length of the weight field of a priority frame.
static const size_t kPriorityWeightLength = 1;
// Length of a priority frame's first byte.
@@ -41,6 +39,8 @@
remaining_length_field_length_(0),
current_frame_length_(0),
remaining_frame_length_(0),
+ current_type_field_length_(0),
+ remaining_type_field_length_(0),
error_(QUIC_NO_ERROR),
error_detail_("") {}
@@ -97,9 +97,39 @@
void HttpDecoder::ReadFrameType(QuicDataReader* reader) {
DCHECK_NE(0u, reader->BytesRemaining());
- if (!reader->ReadUInt8(¤t_frame_type_)) {
- RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame type");
- return;
+ if (current_type_field_length_ == 0) {
+ // A new frame is coming.
+ current_type_field_length_ = reader->PeekVarInt62Length();
+ if (current_type_field_length_ == 0) {
+ RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame type length");
+ visitor_->OnError(this);
+ return;
+ }
+ if (current_type_field_length_ <= reader->BytesRemaining()) {
+ // The reader has all type data needed, so no need to buffer.
+ if (!reader->ReadVarInt62(¤t_frame_type_)) {
+ RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame type");
+ return;
+ }
+ } else {
+ // Buffer a new type field.
+ remaining_type_field_length_ = current_type_field_length_;
+ BufferFrameType(reader);
+ return;
+ }
+ } else {
+ // Buffer the existing type field.
+ BufferFrameType(reader);
+ // The frame is still not buffered completely.
+ if (remaining_type_field_length_ != 0) {
+ return;
+ }
+ QuicDataReader type_reader(type_buffer_.data(), current_type_field_length_);
+ if (!type_reader.ReadVarInt62(¤t_frame_type_)) {
+ RaiseError(QUIC_INTERNAL_ERROR, "Unable to read buffered frame type");
+ visitor_->OnError(this);
+ return;
+ }
}
if (current_frame_length_ > MaxFrameLength(current_frame_type_)) {
@@ -112,13 +142,16 @@
// frame payload.
if (current_frame_type_ == 0x0) {
visitor_->OnDataFrameStart(Http3FrameLengths(
- current_length_field_size_ + kFrameTypeLength, current_frame_length_));
+ current_length_field_size_ + current_type_field_length_,
+ current_frame_length_));
} else if (current_frame_type_ == 0x1) {
visitor_->OnHeadersFrameStart(Http3FrameLengths(
- current_length_field_size_ + kFrameTypeLength, current_frame_length_));
+ current_length_field_size_ + current_type_field_length_,
+ current_frame_length_));
} else if (current_frame_type_ == 0x4) {
visitor_->OnSettingsFrameStart(Http3FrameLengths(
- current_length_field_size_ + kFrameTypeLength, current_frame_length_));
+ current_length_field_size_ + current_type_field_length_,
+ current_frame_length_));
}
state_ = (remaining_frame_length_ == 0) ? STATE_FINISH_PARSING
@@ -331,6 +364,7 @@
}
current_length_field_size_ = 0;
+ current_type_field_length_ = 0;
state_ = STATE_READING_FRAME_LENGTH;
}
@@ -346,6 +380,7 @@
if (remaining_frame_length_ == 0) {
state_ = STATE_READING_FRAME_LENGTH;
current_length_field_size_ = 0;
+ current_type_field_length_ = 0;
}
}
@@ -391,6 +426,22 @@
remaining_length_field_length_ -= bytes_to_read;
}
+void HttpDecoder::BufferFrameType(QuicDataReader* reader) {
+ if (current_type_field_length_ == remaining_type_field_length_) {
+ type_buffer_.fill(0);
+ }
+ QuicByteCount bytes_to_read = std::min<QuicByteCount>(
+ remaining_type_field_length_, reader->BytesRemaining());
+ if (!reader->ReadBytes(type_buffer_.data() + current_type_field_length_ -
+ remaining_type_field_length_,
+ bytes_to_read)) {
+ RaiseError(QUIC_INTERNAL_ERROR, "Unable to buffer frame type bytes.");
+ visitor_->OnError(this);
+ return;
+ }
+ remaining_type_field_length_ -= bytes_to_read;
+}
+
void HttpDecoder::RaiseError(QuicErrorCode error, std::string error_detail) {
state_ = STATE_ERROR;
error_ = error;