Modify QpackInstructionEncoder API.
QpackInstructionEncoder does not need to support progressive encoding. This CL
modifies the API, a follow-up CL will clean up internals.
Taking |&output| and appending is more performant than returning std::string
when encoding headers, which involve concatenating a large number of
instructions.
gfe-relnote: n/a, QUIC v99-only change.
PiperOrigin-RevId: 254497735
Change-Id: I62d74a0523220e5730ffc85ea66ab071345fc8fb
diff --git a/quic/core/qpack/qpack_decoder_stream_sender.cc b/quic/core/qpack/qpack_decoder_stream_sender.cc
index a38c6d5..4586fd3 100644
--- a/quic/core/qpack/qpack_decoder_stream_sender.cc
+++ b/quic/core/qpack/qpack_decoder_stream_sender.cc
@@ -22,13 +22,8 @@
void QpackDecoderStreamSender::SendInsertCountIncrement(uint64_t increment) {
instruction_encoder_.set_varint(increment);
- instruction_encoder_.Encode(InsertCountIncrementInstruction());
-
std::string output;
-
- instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
- DCHECK(!instruction_encoder_.HasNext());
-
+ instruction_encoder_.Encode(InsertCountIncrementInstruction(), &output);
delegate_->WriteStreamData(output);
}
@@ -36,26 +31,16 @@
QuicStreamId stream_id) {
instruction_encoder_.set_varint(stream_id);
- instruction_encoder_.Encode(HeaderAcknowledgementInstruction());
-
std::string output;
-
- instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
- DCHECK(!instruction_encoder_.HasNext());
-
+ instruction_encoder_.Encode(HeaderAcknowledgementInstruction(), &output);
delegate_->WriteStreamData(output);
}
void QpackDecoderStreamSender::SendStreamCancellation(QuicStreamId stream_id) {
instruction_encoder_.set_varint(stream_id);
- instruction_encoder_.Encode(StreamCancellationInstruction());
-
std::string output;
-
- instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
- DCHECK(!instruction_encoder_.HasNext());
-
+ instruction_encoder_.Encode(StreamCancellationInstruction(), &output);
delegate_->WriteStreamData(output);
}
diff --git a/quic/core/qpack/qpack_encoder.cc b/quic/core/qpack/qpack_encoder.cc
index d5bea0d..c5997b1 100644
--- a/quic/core/qpack/qpack_encoder.cc
+++ b/quic/core/qpack/qpack_encoder.cc
@@ -38,11 +38,7 @@
instruction_encoder.set_varint2(0);
instruction_encoder.set_s_bit(false);
- instruction_encoder.Encode(QpackPrefixInstruction());
- DCHECK(instruction_encoder.HasNext());
- instruction_encoder.Next(std::numeric_limits<size_t>::max(),
- &encoded_headers);
- DCHECK(!instruction_encoder.HasNext());
+ instruction_encoder.Encode(QpackPrefixInstruction(), &encoded_headers);
for (const auto& header : ValueSplittingHeaderList(header_list)) {
QuicStringPiece name = header.first;
@@ -61,7 +57,8 @@
instruction_encoder.set_s_bit(is_static);
instruction_encoder.set_varint(index);
- instruction_encoder.Encode(QpackIndexedHeaderFieldInstruction());
+ instruction_encoder.Encode(QpackIndexedHeaderFieldInstruction(),
+ &encoded_headers);
break;
case QpackHeaderTable::MatchType::kName:
@@ -72,22 +69,19 @@
instruction_encoder.set_value(value);
instruction_encoder.Encode(
- QpackLiteralHeaderFieldNameReferenceInstruction());
+ QpackLiteralHeaderFieldNameReferenceInstruction(),
+ &encoded_headers);
break;
case QpackHeaderTable::MatchType::kNoMatch:
instruction_encoder.set_name(name);
instruction_encoder.set_value(value);
- instruction_encoder.Encode(QpackLiteralHeaderFieldInstruction());
+ instruction_encoder.Encode(QpackLiteralHeaderFieldInstruction(),
+ &encoded_headers);
break;
}
-
- DCHECK(instruction_encoder.HasNext());
- instruction_encoder.Next(std::numeric_limits<size_t>::max(),
- &encoded_headers);
- DCHECK(!instruction_encoder.HasNext());
}
return encoded_headers;
diff --git a/quic/core/qpack/qpack_encoder_stream_sender.cc b/quic/core/qpack/qpack_encoder_stream_sender.cc
index e4299ed..ca1da4f 100644
--- a/quic/core/qpack/qpack_encoder_stream_sender.cc
+++ b/quic/core/qpack/qpack_encoder_stream_sender.cc
@@ -27,13 +27,8 @@
instruction_encoder_.set_varint(name_index);
instruction_encoder_.set_value(value);
- instruction_encoder_.Encode(InsertWithNameReferenceInstruction());
-
std::string output;
-
- instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
- DCHECK(!instruction_encoder_.HasNext());
-
+ instruction_encoder_.Encode(InsertWithNameReferenceInstruction(), &output);
delegate_->WriteStreamData(output);
}
@@ -43,39 +38,24 @@
instruction_encoder_.set_name(name);
instruction_encoder_.set_value(value);
- instruction_encoder_.Encode(InsertWithoutNameReferenceInstruction());
-
std::string output;
-
- instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
- DCHECK(!instruction_encoder_.HasNext());
-
+ instruction_encoder_.Encode(InsertWithoutNameReferenceInstruction(), &output);
delegate_->WriteStreamData(output);
}
void QpackEncoderStreamSender::SendDuplicate(uint64_t index) {
instruction_encoder_.set_varint(index);
- instruction_encoder_.Encode(DuplicateInstruction());
-
std::string output;
-
- instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
- DCHECK(!instruction_encoder_.HasNext());
-
+ instruction_encoder_.Encode(DuplicateInstruction(), &output);
delegate_->WriteStreamData(output);
}
void QpackEncoderStreamSender::SendSetDynamicTableCapacity(uint64_t capacity) {
instruction_encoder_.set_varint(capacity);
- instruction_encoder_.Encode(SetDynamicTableCapacityInstruction());
-
std::string output;
-
- instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
- DCHECK(!instruction_encoder_.HasNext());
-
+ instruction_encoder_.Encode(SetDynamicTableCapacityInstruction(), &output);
delegate_->WriteStreamData(output);
}
diff --git a/quic/core/qpack/qpack_instruction_encoder.cc b/quic/core/qpack/qpack_instruction_encoder.cc
index 0da9567..1e00d96 100644
--- a/quic/core/qpack/qpack_instruction_encoder.cc
+++ b/quic/core/qpack/qpack_instruction_encoder.cc
@@ -4,6 +4,8 @@
#include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h"
+#include <limits>
+
#include "net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_utils.h"
@@ -18,7 +20,16 @@
state_(State::kOpcode),
instruction_(nullptr) {}
-void QpackInstructionEncoder::Encode(const QpackInstruction* instruction) {
+void QpackInstructionEncoder::Encode(const QpackInstruction* instruction,
+ std::string* output) {
+ StartEncode(instruction);
+ DCHECK(HasNext());
+
+ Next(std::numeric_limits<size_t>::max(), output);
+ DCHECK(!HasNext());
+}
+
+void QpackInstructionEncoder::StartEncode(const QpackInstruction* instruction) {
DCHECK(!HasNext());
state_ = State::kOpcode;
diff --git a/quic/core/qpack/qpack_instruction_encoder.h b/quic/core/qpack/qpack_instruction_encoder.h
index 917378e..1da850f 100644
--- a/quic/core/qpack/qpack_instruction_encoder.h
+++ b/quic/core/qpack/qpack_instruction_encoder.h
@@ -33,9 +33,13 @@
void set_name(QuicStringPiece name) { name_ = name; }
void set_value(QuicStringPiece value) { value_ = value; }
+ // Append encoded instruction to |output|.
+ void Encode(const QpackInstruction* instruction, std::string* output);
+
+ private:
// Start encoding an instruction. Must only be called after the previous
// instruction has been completely encoded.
- void Encode(const QpackInstruction* instruction);
+ void StartEncode(const QpackInstruction* instruction);
// Returns true iff more data remains to be encoded for the current
// instruction. Returns false if there is no current instruction, that is, if
@@ -47,7 +51,6 @@
// returns true. |max_encoded_bytes| must be positive.
void Next(size_t max_encoded_bytes, std::string* output);
- private:
enum class State {
// Write instruction opcode to |byte_|.
kOpcode,
diff --git a/quic/core/qpack/qpack_instruction_encoder_test.cc b/quic/core/qpack/qpack_instruction_encoder_test.cc
index 738a1b7..d921fa6 100644
--- a/quic/core/qpack/qpack_instruction_encoder_test.cc
+++ b/quic/core/qpack/qpack_instruction_encoder_test.cc
@@ -4,7 +4,6 @@
#include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
@@ -15,49 +14,46 @@
namespace test {
namespace {
-class QpackInstructionEncoderTest : public QuicTestWithParam<FragmentMode> {
+class QpackInstructionEncoderTest : public QuicTest {
protected:
- QpackInstructionEncoderTest() : fragment_mode_(GetParam()) {}
+ QpackInstructionEncoderTest() : verified_position_(0) {}
~QpackInstructionEncoderTest() override = default;
- // Encode |instruction| with fragment sizes dictated by |fragment_mode_|.
- std::string EncodeInstruction(const QpackInstruction* instruction) {
- EXPECT_FALSE(encoder_.HasNext());
+ // Append encoded |instruction| to |output_|.
+ void EncodeInstruction(const QpackInstruction* instruction) {
+ encoder_.Encode(instruction, &output_);
+ }
- FragmentSizeGenerator fragment_size_generator =
- FragmentModeToFragmentSizeGenerator(fragment_mode_);
- std::string output;
- encoder_.Encode(instruction);
- while (encoder_.HasNext()) {
- encoder_.Next(fragment_size_generator(), &output);
- }
-
- return output;
+ // Compare substring appended to |output_| since last EncodedSegmentMatches()
+ // call against hex-encoded argument.
+ bool EncodedSegmentMatches(QuicStringPiece hex_encoded_expected_substring) {
+ auto recently_encoded = QuicStringPiece(output_).substr(verified_position_);
+ auto expected = QuicTextUtils::HexDecode(hex_encoded_expected_substring);
+ verified_position_ = output_.size();
+ return recently_encoded == expected;
}
QpackInstructionEncoder encoder_;
private:
- const FragmentMode fragment_mode_;
+ std::string output_;
+ std::string::size_type verified_position_;
};
-INSTANTIATE_TEST_SUITE_P(,
- QpackInstructionEncoderTest,
- Values(FragmentMode::kSingleChunk,
- FragmentMode::kOctetByOctet));
-
-TEST_P(QpackInstructionEncoderTest, Varint) {
+TEST_F(QpackInstructionEncoderTest, Varint) {
const QpackInstruction instruction{QpackInstructionOpcode{0x00, 0x80},
{{QpackInstructionFieldType::kVarint, 7}}};
encoder_.set_varint(5);
- EXPECT_EQ(QuicTextUtils::HexDecode("05"), EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("05"));
encoder_.set_varint(127);
- EXPECT_EQ(QuicTextUtils::HexDecode("7f00"), EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("7f00"));
}
-TEST_P(QpackInstructionEncoderTest, SBitAndTwoVarint2) {
+TEST_F(QpackInstructionEncoderTest, SBitAndTwoVarint2) {
const QpackInstruction instruction{
QpackInstructionOpcode{0x80, 0xc0},
{{QpackInstructionFieldType::kSbit, 0x20},
@@ -67,16 +63,17 @@
encoder_.set_s_bit(true);
encoder_.set_varint(5);
encoder_.set_varint2(200);
- EXPECT_EQ(QuicTextUtils::HexDecode("a5c8"), EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("a5c8"));
encoder_.set_s_bit(false);
encoder_.set_varint(31);
encoder_.set_varint2(356);
- EXPECT_EQ(QuicTextUtils::HexDecode("9f00ff65"),
- EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("9f00ff65"));
}
-TEST_P(QpackInstructionEncoderTest, SBitAndVarintAndValue) {
+TEST_F(QpackInstructionEncoderTest, SBitAndVarintAndValue) {
const QpackInstruction instruction{QpackInstructionOpcode{0xc0, 0xc0},
{{QpackInstructionFieldType::kSbit, 0x20},
{QpackInstructionFieldType::kVarint, 5},
@@ -85,49 +82,51 @@
encoder_.set_s_bit(true);
encoder_.set_varint(100);
encoder_.set_value("foo");
- EXPECT_EQ(QuicTextUtils::HexDecode("ff458294e7"),
- EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("ff458294e7"));
encoder_.set_s_bit(false);
encoder_.set_varint(3);
encoder_.set_value("bar");
- EXPECT_EQ(QuicTextUtils::HexDecode("c303626172"),
- EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("c303626172"));
}
-TEST_P(QpackInstructionEncoderTest, Name) {
+TEST_F(QpackInstructionEncoderTest, Name) {
const QpackInstruction instruction{QpackInstructionOpcode{0xe0, 0xe0},
{{QpackInstructionFieldType::kName, 4}}};
encoder_.set_name("");
- EXPECT_EQ(QuicTextUtils::HexDecode("e0"), EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("e0"));
encoder_.set_name("foo");
- EXPECT_EQ(QuicTextUtils::HexDecode("f294e7"),
- EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("f294e7"));
encoder_.set_name("bar");
- EXPECT_EQ(QuicTextUtils::HexDecode("e3626172"),
- EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("e3626172"));
}
-TEST_P(QpackInstructionEncoderTest, Value) {
+TEST_F(QpackInstructionEncoderTest, Value) {
const QpackInstruction instruction{QpackInstructionOpcode{0xf0, 0xf0},
{{QpackInstructionFieldType::kValue, 3}}};
encoder_.set_value("");
- EXPECT_EQ(QuicTextUtils::HexDecode("f0"), EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("f0"));
encoder_.set_value("foo");
- EXPECT_EQ(QuicTextUtils::HexDecode("fa94e7"),
- EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("fa94e7"));
encoder_.set_value("bar");
- EXPECT_EQ(QuicTextUtils::HexDecode("f3626172"),
- EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("f3626172"));
}
-TEST_P(QpackInstructionEncoderTest, SBitAndNameAndValue) {
+TEST_F(QpackInstructionEncoderTest, SBitAndNameAndValue) {
const QpackInstruction instruction{QpackInstructionOpcode{0xf0, 0xf0},
{{QpackInstructionFieldType::kSbit, 0x08},
{QpackInstructionFieldType::kName, 2},
@@ -136,13 +135,14 @@
encoder_.set_s_bit(false);
encoder_.set_name("");
encoder_.set_value("");
- EXPECT_EQ(QuicTextUtils::HexDecode("f000"), EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("f000"));
encoder_.set_s_bit(true);
encoder_.set_name("foo");
encoder_.set_value("bar");
- EXPECT_EQ(QuicTextUtils::HexDecode("fe94e703626172"),
- EncodeInstruction(&instruction));
+ EncodeInstruction(&instruction);
+ EXPECT_TRUE(EncodedSegmentMatches("fe94e703626172"));
}
} // namespace