Make writing Prioritized Element ID and Element Dependency ID optional when handling priority.
These fields are specified to be absent when priority type or dependency type is ROOT_OF_TREE.
On the decoding side, the absent fields will be parsed as 0 for default value. Those fields won't be used when later the frame is processed.
gfe-relnote: v99 only, not flag protected.
PiperOrigin-RevId: 254072432
Change-Id: I336e06b39d89ff01507e54818dafa67923e96e4c
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc
index f08d2ff..4513f04 100644
--- a/quic/core/http/http_decoder.cc
+++ b/quic/core/http/http_decoder.cc
@@ -519,11 +519,13 @@
frame->dependency_type =
static_cast<PriorityElementType>(ExtractBits(flags, 2, 4));
frame->exclusive = flags % 2 == 1;
- if (!reader->ReadVarInt62(&frame->prioritized_element_id)) {
+ if (frame->prioritized_type != ROOT_OF_TREE &&
+ !reader->ReadVarInt62(&frame->prioritized_element_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read prioritized_element_id");
return false;
}
- if (!reader->ReadVarInt62(&frame->element_dependency_id)) {
+ if (frame->dependency_type != ROOT_OF_TREE &&
+ !reader->ReadVarInt62(&frame->element_dependency_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read element_dependency_id");
return false;
}
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc
index b99689f..c25d086 100644
--- a/quic/core/http/http_decoder_test.cc
+++ b/quic/core/http/http_decoder_test.cc
@@ -343,6 +343,26 @@
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
EXPECT_EQ("", decoder_.error_detail());
+ char input2[] = {// type (PRIORITY)
+ 0x2,
+ // length
+ 0x2,
+ // root of tree, root of tree, exclusive
+ 0xf1,
+ // weight
+ 0xFF};
+ PriorityFrame frame2;
+ frame2.prioritized_type = ROOT_OF_TREE;
+ frame2.dependency_type = ROOT_OF_TREE;
+ frame2.exclusive = true;
+ frame2.weight = 0xFF;
+
+ EXPECT_CALL(visitor_, OnPriorityFrame(frame2));
+ EXPECT_EQ(QUIC_ARRAYSIZE(input2),
+ decoder_.ProcessInput(input2, QUIC_ARRAYSIZE(input2)));
+ EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
+ EXPECT_EQ("", decoder_.error_detail());
+
// Test on the situation when the visitor wants to stop processing.
EXPECT_CALL(visitor_, OnPriorityFrame(frame)).WillOnce(Return(false));
EXPECT_EQ(0u, decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
diff --git a/quic/core/http/http_encoder.cc b/quic/core/http/http_encoder.cc
index 4505dc7..2b8be8e 100644
--- a/quic/core/http/http_encoder.cc
+++ b/quic/core/http/http_encoder.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/core/http/http_encoder.h"
+
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
namespace quic {
@@ -43,6 +44,8 @@
static const size_t kPriorityWeightLength = 1;
// Length of a priority frame's first byte.
static const size_t kPriorityFirstByteLength = 1;
+// The bit that indicates Priority frame is exclusive.
+static const uint8_t kPriorityExclusiveBit = 1;
} // namespace
@@ -95,8 +98,12 @@
std::unique_ptr<char[]>* output) {
QuicByteCount payload_length =
kPriorityFirstByteLength +
- QuicDataWriter::GetVarInt62Len(priority.prioritized_element_id) +
- QuicDataWriter::GetVarInt62Len(priority.element_dependency_id) +
+ (priority.prioritized_type == ROOT_OF_TREE
+ ? 0
+ : QuicDataWriter::GetVarInt62Len(priority.prioritized_element_id)) +
+ (priority.dependency_type == ROOT_OF_TREE
+ ? 0
+ : QuicDataWriter::GetVarInt62Len(priority.element_dependency_id)) +
kPriorityWeightLength;
QuicByteCount total_length =
GetTotalLength(payload_length, HttpFrameType::PRIORITY);
@@ -111,16 +118,14 @@
}
// Set the first byte of the payload.
- uint8_t bits = 0;
- bits = SetPriorityFields(bits, priority.prioritized_type, true);
- bits = SetPriorityFields(bits, priority.dependency_type, false);
+ uint8_t firstByte = 0;
+ firstByte = SetPriorityFields(firstByte, priority.prioritized_type, true);
+ firstByte = SetPriorityFields(firstByte, priority.dependency_type, false);
if (priority.exclusive) {
- bits |= 1;
+ firstByte |= kPriorityExclusiveBit;
}
- if (writer.WriteUInt8(bits) &&
- writer.WriteVarInt62(priority.prioritized_element_id) &&
- writer.WriteVarInt62(priority.element_dependency_id) &&
+ if (writer.WriteUInt8(firstByte) && MaybeWriteIds(priority, &writer) &&
writer.WriteUInt8(priority.weight)) {
return total_length;
}
@@ -282,4 +287,27 @@
payload_length;
}
+bool HttpEncoder::MaybeWriteIds(const PriorityFrame& priority,
+ QuicDataWriter* writer) {
+ if (priority.prioritized_type != ROOT_OF_TREE) {
+ if (!writer->WriteVarInt62(priority.prioritized_element_id)) {
+ return false;
+ }
+ } else {
+ DCHECK_EQ(0u, priority.prioritized_element_id)
+ << "Prioritized element id should be 0 when prioritized type is "
+ "ROOT_OF_TREE";
+ }
+ if (priority.dependency_type != ROOT_OF_TREE) {
+ if (!writer->WriteVarInt62(priority.element_dependency_id)) {
+ return false;
+ }
+ } else {
+ DCHECK_EQ(0u, priority.element_dependency_id)
+ << "Element dependency id should be 0 when dependency type is "
+ "ROOT_OF_TREE";
+ }
+ return true;
+}
+
} // namespace quic
diff --git a/quic/core/http/http_encoder.h b/quic/core/http/http_encoder.h
index a3c1f4c..12c5bab 100644
--- a/quic/core/http/http_encoder.h
+++ b/quic/core/http/http_encoder.h
@@ -76,6 +76,9 @@
QuicByteCount GetTotalLength(QuicByteCount payload_length,
HttpFrameType type);
+
+ // Write prioritized element id and element dependency id if needed.
+ bool MaybeWriteIds(const PriorityFrame& priority, QuicDataWriter* writer);
};
} // namespace quic
diff --git a/quic/core/http/http_encoder_test.cc b/quic/core/http/http_encoder_test.cc
index 6a029d8..d0696ed 100644
--- a/quic/core/http/http_encoder_test.cc
+++ b/quic/core/http/http_encoder_test.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/core/http/http_encoder.h"
+
#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
@@ -68,6 +69,45 @@
EXPECT_EQ(QUIC_ARRAYSIZE(output), length);
CompareCharArraysWithHexError("PRIORITY", buffer.get(), length, output,
QUIC_ARRAYSIZE(output));
+
+ PriorityFrame priority2;
+ priority2.prioritized_type = ROOT_OF_TREE;
+ priority2.dependency_type = REQUEST_STREAM;
+ priority2.exclusive = true;
+ priority2.element_dependency_id = 0x04;
+ priority2.weight = 0xFF;
+ char output2[] = {// type (PRIORIRTY)
+ 0x2,
+ // length
+ 0x3,
+ // root of tree, request stream, exclusive
+ 0xc1,
+ // element_dependency_id
+ 0x04,
+ // weight
+ 0xff};
+ length = encoder_.SerializePriorityFrame(priority2, &buffer);
+ EXPECT_EQ(QUIC_ARRAYSIZE(output2), length);
+ CompareCharArraysWithHexError("PRIORITY", buffer.get(), length, output2,
+ QUIC_ARRAYSIZE(output2));
+
+ PriorityFrame priority3;
+ priority3.prioritized_type = ROOT_OF_TREE;
+ priority3.dependency_type = ROOT_OF_TREE;
+ priority3.exclusive = true;
+ priority3.weight = 0xFF;
+ char output3[] = {// type (PRIORITY)
+ 0x2,
+ // length
+ 0x2,
+ // root of tree, root of tree, exclusive
+ 0xf1,
+ // weight
+ 0xff};
+ length = encoder_.SerializePriorityFrame(priority3, &buffer);
+ EXPECT_EQ(QUIC_ARRAYSIZE(output3), length);
+ CompareCharArraysWithHexError("PRIORITY", buffer.get(), length, output3,
+ QUIC_ARRAYSIZE(output3));
}
TEST_F(HttpEncoderTest, SerializeCancelPushFrame) {
diff --git a/quic/core/http/http_frames.h b/quic/core/http/http_frames.h
index f1aa7ff..ff59614 100644
--- a/quic/core/http/http_frames.h
+++ b/quic/core/http/http_frames.h
@@ -53,12 +53,12 @@
};
struct PriorityFrame {
- PriorityElementType prioritized_type;
- PriorityElementType dependency_type;
- bool exclusive;
- uint64_t prioritized_element_id;
- uint64_t element_dependency_id;
- uint8_t weight;
+ PriorityElementType prioritized_type = REQUEST_STREAM;
+ PriorityElementType dependency_type = REQUEST_STREAM;
+ bool exclusive = false;
+ uint64_t prioritized_element_id = 0;
+ uint64_t element_dependency_id = 0;
+ uint8_t weight = 0;
bool operator==(const PriorityFrame& rhs) const {
return prioritized_type == rhs.prioritized_type &&