Disable Huffman encoding for QPACK headers sent over Hyperloop.
Add a DisableHuffmanEncoding() to QuicSpdySession which must be
called before Initialize(), which causes the QpackEncoder and
MetadataManager to be created with Huffman encoding disabled.
Both GfeQuicClientSession and GfeQuicBackendServerSession call
this method in their constructors, when the flag is true.
The actual behavior change is in QpackInstructionEncoder. The
rest of the changes are merely plumbing.
Protected by FLAGS_gfe2_reloadable_flag_disable_huffman_for_hyperloop.
PiperOrigin-RevId: 603097044
diff --git a/quiche/quic/core/http/end_to_end_test.cc b/quiche/quic/core/http/end_to_end_test.cc
index 83ab26a..6024569 100644
--- a/quiche/quic/core/http/end_to_end_test.cc
+++ b/quiche/quic/core/http/end_to_end_test.cc
@@ -3929,7 +3929,8 @@
// Determine size of headers after QPACK compression.
NoopDecoderStreamErrorDelegate decoder_stream_error_delegate;
NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
- QpackEncoder qpack_encoder(&decoder_stream_error_delegate);
+ QpackEncoder qpack_encoder(&decoder_stream_error_delegate,
+ HuffmanEncoding::kEnabled);
qpack_encoder.set_qpack_stream_sender_delegate(
&encoder_stream_sender_delegate);
diff --git a/quiche/quic/core/http/quic_spdy_server_stream_base_test.cc b/quiche/quic/core/http/quic_spdy_server_stream_base_test.cc
index 1b2f486..5864c61 100644
--- a/quiche/quic/core/http/quic_spdy_server_stream_base_test.cc
+++ b/quiche/quic/core/http/quic_spdy_server_stream_base_test.cc
@@ -301,8 +301,8 @@
spdy::Http2HeaderBlock empty_header;
quic::test::NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
NoopDecoderStreamErrorDelegate decoder_stream_error_delegate;
- auto qpack_encoder =
- std::make_unique<quic::QpackEncoder>(&decoder_stream_error_delegate);
+ auto qpack_encoder = std::make_unique<quic::QpackEncoder>(
+ &decoder_stream_error_delegate, HuffmanEncoding::kEnabled);
qpack_encoder->set_qpack_stream_sender_delegate(
&encoder_stream_sender_delegate);
std::string payload =
diff --git a/quiche/quic/core/http/quic_spdy_session.cc b/quiche/quic/core/http/quic_spdy_session.cc
index d88951a..48c363a 100644
--- a/quiche/quic/core/http/quic_spdy_session.cc
+++ b/quiche/quic/core/http/quic_spdy_session.cc
@@ -522,7 +522,7 @@
headers_stream_ = headers_stream.get();
ActivateStream(std::move(headers_stream));
} else {
- qpack_encoder_ = std::make_unique<QpackEncoder>(this);
+ qpack_encoder_ = std::make_unique<QpackEncoder>(this, huffman_encoding_);
qpack_decoder_ =
std::make_unique<QpackDecoder>(qpack_maximum_dynamic_table_capacity_,
qpack_maximum_blocked_streams_, this);
diff --git a/quiche/quic/core/http/quic_spdy_session.h b/quiche/quic/core/http/quic_spdy_session.h
index 4c01b18..4bf9e16 100644
--- a/quiche/quic/core/http/quic_spdy_session.h
+++ b/quiche/quic/core/http/quic_spdy_session.h
@@ -555,6 +555,11 @@
// is always bundled opportunistically.
bool CheckStreamWriteBlocked(QuicStream* stream) const override;
+ // Disables the use of Huffman encoding for QPACK headers.
+ void DisableHuffmanEncoding() {
+ huffman_encoding_ = HuffmanEncoding::kDisabled;
+ }
+
private:
friend class test::QuicSpdySessionPeer;
@@ -602,6 +607,7 @@
bool ValidateWebTransportSettingsConsistency();
+ HuffmanEncoding huffman_encoding_ = HuffmanEncoding::kEnabled;
std::unique_ptr<QpackEncoder> qpack_encoder_;
std::unique_ptr<QpackDecoder> qpack_decoder_;
diff --git a/quiche/quic/core/http/quic_spdy_stream_test.cc b/quiche/quic/core/http/quic_spdy_stream_test.cc
index 42ca430..2e08a5c 100644
--- a/quiche/quic/core/http/quic_spdy_stream_test.cc
+++ b/quiche/quic/core/http/quic_spdy_stream_test.cc
@@ -391,7 +391,8 @@
// Return QPACK-encoded header block without using the dynamic table.
std::string EncodeQpackHeaders(const Http2HeaderBlock& header) {
NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
- auto qpack_encoder = std::make_unique<QpackEncoder>(session_.get());
+ auto qpack_encoder = std::make_unique<QpackEncoder>(
+ session_.get(), HuffmanEncoding::kEnabled);
qpack_encoder->set_qpack_stream_sender_delegate(
&encoder_stream_sender_delegate);
// QpackEncoder does not use the dynamic table by default,
diff --git a/quiche/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc b/quiche/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
index 5109f61..e7a1758 100644
--- a/quiche/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
+++ b/quiche/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
@@ -17,11 +17,14 @@
// This fuzzer exercises QpackEncoderStreamSender.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider provider(data, size);
+
NoopQpackStreamSenderDelegate delegate;
- QpackEncoderStreamSender sender;
+ QpackEncoderStreamSender sender(provider.ConsumeBool()
+ ? HuffmanEncoding::kEnabled
+ : HuffmanEncoding::kDisabled);
sender.set_qpack_stream_sender_delegate(&delegate);
- FuzzedDataProvider provider(data, size);
// Limit string literal length to 2 kB for efficiency.
const uint16_t kMaxStringLength = 2048;
diff --git a/quiche/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc b/quiche/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc
index 31367b3..36f7fef 100644
--- a/quiche/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc
+++ b/quiche/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc
@@ -44,8 +44,9 @@
class EncodingEndpoint {
public:
EncodingEndpoint(uint64_t maximum_dynamic_table_capacity,
- uint64_t maximum_blocked_streams)
- : encoder_(&decoder_stream_error_delegate) {
+ uint64_t maximum_blocked_streams,
+ HuffmanEncoding huffman_encoding)
+ : encoder_(&decoder_stream_error_delegate, huffman_encoding) {
encoder_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
encoder_.SetMaximumBlockedStreams(maximum_blocked_streams);
}
@@ -600,7 +601,9 @@
// Set up encoder.
EncodingEndpoint encoder(maximum_dynamic_table_capacity,
- maximum_blocked_streams);
+ maximum_blocked_streams,
+ provider.ConsumeBool() ? HuffmanEncoding::kEnabled
+ : HuffmanEncoding::kDisabled);
// Set up decoder.
DecodingEndpoint decoder(maximum_dynamic_table_capacity,
diff --git a/quiche/quic/core/qpack/qpack_decoder_stream_sender.cc b/quiche/quic/core/qpack/qpack_decoder_stream_sender.cc
index 3be61cb..da33bd3 100644
--- a/quiche/quic/core/qpack/qpack_decoder_stream_sender.cc
+++ b/quiche/quic/core/qpack/qpack_decoder_stream_sender.cc
@@ -16,7 +16,11 @@
namespace quic {
-QpackDecoderStreamSender::QpackDecoderStreamSender() : delegate_(nullptr) {}
+QpackDecoderStreamSender::QpackDecoderStreamSender()
+ : delegate_(nullptr),
+ // None of the instructions sent by the QpackDecoderStreamSender
+ // are strings, so huffman encoding is not relevant.
+ instruction_encoder_(HuffmanEncoding::kEnabled) {}
void QpackDecoderStreamSender::SendInsertCountIncrement(uint64_t increment) {
instruction_encoder_.Encode(
diff --git a/quiche/quic/core/qpack/qpack_encoder.cc b/quiche/quic/core/qpack/qpack_encoder.cc
index 9ee5226..a4b48fe 100644
--- a/quiche/quic/core/qpack/qpack_encoder.cc
+++ b/quiche/quic/core/qpack/qpack_encoder.cc
@@ -33,9 +33,12 @@
} // anonymous namespace
QpackEncoder::QpackEncoder(
- DecoderStreamErrorDelegate* decoder_stream_error_delegate)
- : decoder_stream_error_delegate_(decoder_stream_error_delegate),
+ DecoderStreamErrorDelegate* decoder_stream_error_delegate,
+ HuffmanEncoding huffman_encoding)
+ : huffman_encoding_(huffman_encoding),
+ decoder_stream_error_delegate_(decoder_stream_error_delegate),
decoder_stream_receiver_(this),
+ encoder_stream_sender_(huffman_encoding),
maximum_blocked_streams_(0),
header_list_count_(0) {
QUICHE_DCHECK(decoder_stream_error_delegate_);
@@ -346,7 +349,7 @@
std::string QpackEncoder::SecondPassEncode(
QpackEncoder::Representations representations,
uint64_t required_insert_count) const {
- QpackInstructionEncoder instruction_encoder;
+ QpackInstructionEncoder instruction_encoder(huffman_encoding_);
std::string encoded_headers;
// Header block prefix.
diff --git a/quiche/quic/core/qpack/qpack_encoder.h b/quiche/quic/core/qpack/qpack_encoder.h
index bb34b20..0c2ffbf 100644
--- a/quiche/quic/core/qpack/qpack_encoder.h
+++ b/quiche/quic/core/qpack/qpack_encoder.h
@@ -44,7 +44,8 @@
absl::string_view error_message) = 0;
};
- QpackEncoder(DecoderStreamErrorDelegate* decoder_stream_error_delegate);
+ QpackEncoder(DecoderStreamErrorDelegate* decoder_stream_error_delegate,
+ HuffmanEncoding huffman_encoding);
~QpackEncoder() override;
// Encode a header list. If |encoder_stream_sent_byte_count| is not null,
@@ -145,6 +146,7 @@
std::string SecondPassEncode(Representations representations,
uint64_t required_insert_count) const;
+ const HuffmanEncoding huffman_encoding_;
DecoderStreamErrorDelegate* const decoder_stream_error_delegate_;
QpackDecoderStreamReceiver decoder_stream_receiver_;
QpackEncoderStreamSender encoder_stream_sender_;
diff --git a/quiche/quic/core/qpack/qpack_encoder_stream_sender.cc b/quiche/quic/core/qpack/qpack_encoder_stream_sender.cc
index 574b3bb..2c25c22 100644
--- a/quiche/quic/core/qpack/qpack_encoder_stream_sender.cc
+++ b/quiche/quic/core/qpack/qpack_encoder_stream_sender.cc
@@ -22,7 +22,9 @@
} // anonymous namespace
-QpackEncoderStreamSender::QpackEncoderStreamSender() : delegate_(nullptr) {}
+QpackEncoderStreamSender::QpackEncoderStreamSender(
+ HuffmanEncoding huffman_encoding)
+ : delegate_(nullptr), instruction_encoder_(huffman_encoding) {}
void QpackEncoderStreamSender::SendInsertWithNameReference(
bool is_static, uint64_t name_index, absl::string_view value) {
diff --git a/quiche/quic/core/qpack/qpack_encoder_stream_sender.h b/quiche/quic/core/qpack/qpack_encoder_stream_sender.h
index a8c0bbc..958da7e 100644
--- a/quiche/quic/core/qpack/qpack_encoder_stream_sender.h
+++ b/quiche/quic/core/qpack/qpack_encoder_stream_sender.h
@@ -19,7 +19,7 @@
// Serialized instructions are buffered until Flush() is called.
class QUICHE_EXPORT QpackEncoderStreamSender {
public:
- QpackEncoderStreamSender();
+ QpackEncoderStreamSender(HuffmanEncoding huffman_encoding);
QpackEncoderStreamSender(const QpackEncoderStreamSender&) = delete;
QpackEncoderStreamSender& operator=(const QpackEncoderStreamSender&) = delete;
diff --git a/quiche/quic/core/qpack/qpack_encoder_stream_sender_test.cc b/quiche/quic/core/qpack/qpack_encoder_stream_sender_test.cc
index 5f90e74..6fcf151 100644
--- a/quiche/quic/core/qpack/qpack_encoder_stream_sender_test.cc
+++ b/quiche/quic/core/qpack/qpack_encoder_stream_sender_test.cc
@@ -15,18 +15,27 @@
namespace test {
namespace {
-class QpackEncoderStreamSenderTest : public QuicTest {
+class QpackEncoderStreamSenderTest : public QuicTestWithParam<bool> {
protected:
- QpackEncoderStreamSenderTest() {
+ QpackEncoderStreamSenderTest() : stream_(HuffmanEncoding()) {
stream_.set_qpack_stream_sender_delegate(&delegate_);
}
~QpackEncoderStreamSenderTest() override = default;
+ bool DisableHuffmanEncoding() { return GetParam(); }
+ HuffmanEncoding HuffmanEncoding() {
+ return DisableHuffmanEncoding() ? HuffmanEncoding::kDisabled
+ : HuffmanEncoding::kEnabled;
+ }
+
StrictMock<MockQpackStreamSenderDelegate> delegate_;
QpackEncoderStreamSender stream_;
};
-TEST_F(QpackEncoderStreamSenderTest, InsertWithNameReference) {
+INSTANTIATE_TEST_SUITE_P(DisableHuffmanEncoding, QpackEncoderStreamSenderTest,
+ testing::Values(false, true));
+
+TEST_P(QpackEncoderStreamSenderTest, InsertWithNameReference) {
EXPECT_EQ(0u, stream_.BufferedByteCount());
// Static, index fits in prefix, empty value.
@@ -36,8 +45,13 @@
EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
stream_.Flush();
- // Static, index fits in prefix, Huffman encoded value.
- expected_encoded_data = absl::HexStringToBytes("c28294e7");
+ if (DisableHuffmanEncoding()) {
+ // Static, index fits in prefix, not Huffman encoded value.
+ expected_encoded_data = absl::HexStringToBytes("c203666f6f");
+ } else {
+ // Static, index fits in prefix, Huffman encoded value.
+ expected_encoded_data = absl::HexStringToBytes("c28294e7");
+ }
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendInsertWithNameReference(true, 2, "foo");
EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
@@ -63,7 +77,7 @@
stream_.Flush();
}
-TEST_F(QpackEncoderStreamSenderTest, InsertWithoutNameReference) {
+TEST_P(QpackEncoderStreamSenderTest, InsertWithoutNameReference) {
EXPECT_EQ(0u, stream_.BufferedByteCount());
// Empty name and value.
@@ -73,8 +87,14 @@
EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
stream_.Flush();
- // Huffman encoded short strings.
- expected_encoded_data = absl::HexStringToBytes("6294e78294e7");
+ if (DisableHuffmanEncoding()) {
+ // Not Huffman encoded short strings.
+ expected_encoded_data = absl::HexStringToBytes("43666f6f03666f6f");
+ } else {
+ // Huffman encoded short strings.
+ expected_encoded_data = absl::HexStringToBytes("6294e78294e7");
+ }
+
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendInsertWithoutNameReference("foo", "foo");
EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
@@ -102,7 +122,7 @@
stream_.Flush();
}
-TEST_F(QpackEncoderStreamSenderTest, Duplicate) {
+TEST_P(QpackEncoderStreamSenderTest, Duplicate) {
EXPECT_EQ(0u, stream_.BufferedByteCount());
// Small index fits in prefix.
@@ -120,7 +140,7 @@
stream_.Flush();
}
-TEST_F(QpackEncoderStreamSenderTest, SetDynamicTableCapacity) {
+TEST_P(QpackEncoderStreamSenderTest, SetDynamicTableCapacity) {
EXPECT_EQ(0u, stream_.BufferedByteCount());
// Small capacity fits in prefix.
@@ -141,7 +161,7 @@
}
// No writes should happen until Flush is called.
-TEST_F(QpackEncoderStreamSenderTest, Coalesce) {
+TEST_P(QpackEncoderStreamSenderTest, Coalesce) {
// Insert entry with static name reference, empty value.
stream_.SendInsertWithNameReference(true, 5, "");
@@ -154,12 +174,20 @@
// Duplicate entry.
stream_.SendDuplicate(17);
- std::string expected_encoded_data = absl::HexStringToBytes(
- "c500" // Insert entry with static name reference.
- "c28294e7" // Insert entry with static name reference.
- "6294e78294e7" // Insert literal entry.
- "11"); // Duplicate entry.
-
+ std::string expected_encoded_data;
+ if (DisableHuffmanEncoding()) {
+ expected_encoded_data = absl::HexStringToBytes(
+ "c500" // Insert entry with static name reference.
+ "c203666f6f" // Insert entry with static name reference.
+ "43666f6f03666f6f" // Insert literal entry.
+ "11"); // Duplicate entry.
+ } else {
+ expected_encoded_data = absl::HexStringToBytes(
+ "c500" // Insert entry with static name reference.
+ "c28294e7" // Insert entry with static name reference.
+ "6294e78294e7" // Insert literal entry.
+ "11"); // Duplicate entry.
+ }
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
stream_.Flush();
@@ -168,7 +196,7 @@
// No writes should happen if QpackEncoderStreamSender::Flush() is called
// when the buffer is empty.
-TEST_F(QpackEncoderStreamSenderTest, FlushEmpty) {
+TEST_P(QpackEncoderStreamSenderTest, FlushEmpty) {
EXPECT_EQ(0u, stream_.BufferedByteCount());
stream_.Flush();
EXPECT_EQ(0u, stream_.BufferedByteCount());
diff --git a/quiche/quic/core/qpack/qpack_encoder_test.cc b/quiche/quic/core/qpack/qpack_encoder_test.cc
index 03d7a3f..d484cbf 100644
--- a/quiche/quic/core/qpack/qpack_encoder_test.cc
+++ b/quiche/quic/core/qpack/qpack_encoder_test.cc
@@ -41,10 +41,10 @@
(override));
};
-class QpackEncoderTest : public QuicTest {
+class QpackEncoderTest : public QuicTestWithParam<bool> {
protected:
QpackEncoderTest()
- : encoder_(&decoder_stream_error_delegate_),
+ : encoder_(&decoder_stream_error_delegate_, HuffmanEncoding()),
encoder_stream_sent_byte_count_(0) {
encoder_.set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate_);
encoder_.SetMaximumBlockedStreams(1);
@@ -52,6 +52,12 @@
~QpackEncoderTest() override = default;
+ bool DisableHuffmanEncoding() { return GetParam(); }
+ HuffmanEncoding HuffmanEncoding() {
+ return DisableHuffmanEncoding() ? HuffmanEncoding::kDisabled
+ : HuffmanEncoding::kEnabled;
+ }
+
std::string Encode(const spdy::Http2HeaderBlock& header_list) {
return encoder_.EncodeHeaderList(/* stream_id = */ 1, header_list,
&encoder_stream_sent_byte_count_);
@@ -63,7 +69,10 @@
QuicByteCount encoder_stream_sent_byte_count_;
};
-TEST_F(QpackEncoderTest, Empty) {
+INSTANTIATE_TEST_SUITE_P(DisableHuffmanEncoding, QpackEncoderTest,
+ testing::Values(false, true));
+
+TEST_P(QpackEncoderTest, Empty) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
spdy::Http2HeaderBlock header_list;
@@ -72,27 +81,35 @@
EXPECT_EQ(absl::HexStringToBytes("0000"), output);
}
-TEST_F(QpackEncoderTest, EmptyName) {
+TEST_P(QpackEncoderTest, EmptyName) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
spdy::Http2HeaderBlock header_list;
header_list[""] = "foo";
std::string output = Encode(header_list);
- EXPECT_EQ(absl::HexStringToBytes("0000208294e7"), output);
+ if (DisableHuffmanEncoding()) {
+ EXPECT_EQ(absl::HexStringToBytes("00002003666f6f"), output);
+ } else {
+ EXPECT_EQ(absl::HexStringToBytes("0000208294e7"), output);
+ }
}
-TEST_F(QpackEncoderTest, EmptyValue) {
+TEST_P(QpackEncoderTest, EmptyValue) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
spdy::Http2HeaderBlock header_list;
header_list["foo"] = "";
std::string output = Encode(header_list);
- EXPECT_EQ(absl::HexStringToBytes("00002a94e700"), output);
+ if (DisableHuffmanEncoding()) {
+ EXPECT_EQ(absl::HexStringToBytes("000023666f6f00"), output);
+ } else {
+ EXPECT_EQ(absl::HexStringToBytes("00002a94e700"), output);
+ }
}
-TEST_F(QpackEncoderTest, EmptyNameAndValue) {
+TEST_P(QpackEncoderTest, EmptyNameAndValue) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
spdy::Http2HeaderBlock header_list;
@@ -102,17 +119,21 @@
EXPECT_EQ(absl::HexStringToBytes("00002000"), output);
}
-TEST_F(QpackEncoderTest, Simple) {
+TEST_P(QpackEncoderTest, Simple) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
spdy::Http2HeaderBlock header_list;
header_list["foo"] = "bar";
std::string output = Encode(header_list);
- EXPECT_EQ(absl::HexStringToBytes("00002a94e703626172"), output);
+ if (DisableHuffmanEncoding()) {
+ EXPECT_EQ(absl::HexStringToBytes("000023666f6f03626172"), output);
+ } else {
+ EXPECT_EQ(absl::HexStringToBytes("00002a94e703626172"), output);
+ }
}
-TEST_F(QpackEncoderTest, Multiple) {
+TEST_P(QpackEncoderTest, Multiple) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
spdy::Http2HeaderBlock header_list;
@@ -121,22 +142,29 @@
header_list["ZZZZZZZ"] = std::string(127, 'Z');
std::string output = Encode(header_list);
- EXPECT_EQ(
- absl::HexStringToBytes(
- "0000" // prefix
- "2a94e703626172" // foo: bar
- "27005a5a5a5a5a5a5a" // 7 octet long header name, the smallest number
- // that does not fit on a 3-bit prefix.
- "7f005a5a5a5a5a5a5a" // 127 octet long header value, the smallest
- "5a5a5a5a5a5a5a5a5a" // number that does not fit on a 7-bit prefix.
- "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
- "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
- "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
- "5a5a5a5a5a5a5a5a5a"),
- output);
+ std::string expected;
+ if (DisableHuffmanEncoding()) {
+ expected = absl::HexStringToBytes(
+ "0000" // prefix
+ "23666f6f03626172"); // foo: bar
+ } else {
+ expected = absl::HexStringToBytes(
+ "0000" // prefix
+ "2a94e703626172"); // foo: bar
+ }
+ expected += absl::HexStringToBytes(
+ "27005a5a5a5a5a5a5a" // 7 octet long header name, the smallest number
+ // that does not fit on a 3-bit prefix.
+ "7f005a5a5a5a5a5a5a" // 127 octet long header value, the smallest
+ "5a5a5a5a5a5a5a5a5a" // number that does not fit on a 7-bit prefix.
+ "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
+ "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
+ "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
+ "5a5a5a5a5a5a5a5a5a");
+ EXPECT_EQ(expected, output);
}
-TEST_F(QpackEncoderTest, StaticTable) {
+TEST_P(QpackEncoderTest, StaticTable) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
{
@@ -155,8 +183,14 @@
header_list["location"] = "foo";
std::string output = Encode(header_list);
- EXPECT_EQ(absl::HexStringToBytes("0000d45f108621e9aec2a11f5c8294e7"),
- output);
+ if (DisableHuffmanEncoding()) {
+ EXPECT_EQ(
+ absl::HexStringToBytes("0000d45f1008636f6d70726573735c03666f6f"),
+ output);
+ } else {
+ EXPECT_EQ(absl::HexStringToBytes("0000d45f108621e9aec2a11f5c8294e7"),
+ output);
+ }
}
{
spdy::Http2HeaderBlock header_list;
@@ -168,33 +202,42 @@
}
}
-TEST_F(QpackEncoderTest, DecoderStreamError) {
+TEST_P(QpackEncoderTest, DecoderStreamError) {
EXPECT_CALL(decoder_stream_error_delegate_,
OnDecoderStreamError(QUIC_QPACK_DECODER_STREAM_INTEGER_TOO_LARGE,
Eq("Encoded integer too large.")));
- QpackEncoder encoder(&decoder_stream_error_delegate_);
+ QpackEncoder encoder(&decoder_stream_error_delegate_, HuffmanEncoding());
encoder.set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate_);
encoder.decoder_stream_receiver()->Decode(
absl::HexStringToBytes("ffffffffffffffffffffff"));
}
-TEST_F(QpackEncoderTest, SplitAlongNullCharacter) {
+TEST_P(QpackEncoderTest, SplitAlongNullCharacter) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
spdy::Http2HeaderBlock header_list;
header_list["foo"] = absl::string_view("bar\0bar\0baz", 11);
std::string output = Encode(header_list);
- EXPECT_EQ(absl::HexStringToBytes("0000" // prefix
- "2a94e703626172" // foo: bar
- "2a94e703626172" // foo: bar
- "2a94e70362617a" // foo: baz
- ),
- output);
+ if (DisableHuffmanEncoding()) {
+ EXPECT_EQ(absl::HexStringToBytes("0000" // prefix
+ "23666f6f03626172" // foo: bar
+ "23666f6f03626172" // foo: bar
+ "23666f6f0362617a" // foo: bar
+ ),
+ output);
+ } else {
+ EXPECT_EQ(absl::HexStringToBytes("0000" // prefix
+ "2a94e703626172" // foo: bar
+ "2a94e703626172" // foo: bar
+ "2a94e70362617a" // foo: baz
+ ),
+ output);
+ }
}
-TEST_F(QpackEncoderTest, ZeroInsertCountIncrement) {
+TEST_P(QpackEncoderTest, ZeroInsertCountIncrement) {
// Encoder receives insert count increment with forbidden value 0.
EXPECT_CALL(
decoder_stream_error_delegate_,
@@ -203,7 +246,7 @@
encoder_.OnInsertCountIncrement(0);
}
-TEST_F(QpackEncoderTest, TooLargeInsertCountIncrement) {
+TEST_P(QpackEncoderTest, TooLargeInsertCountIncrement) {
// Encoder receives insert count increment with value that increases Known
// Received Count to a value (one) which is larger than the number of dynamic
// table insertions sent (zero).
@@ -216,7 +259,7 @@
}
// Regression test for https://crbug.com/1014372.
-TEST_F(QpackEncoderTest, InsertCountIncrementOverflow) {
+TEST_P(QpackEncoderTest, InsertCountIncrementOverflow) {
QpackEncoderHeaderTable* header_table =
QpackEncoderPeer::header_table(&encoder_);
@@ -238,7 +281,7 @@
encoder_.OnInsertCountIncrement(std::numeric_limits<uint64_t>::max());
}
-TEST_F(QpackEncoderTest, InvalidHeaderAcknowledgement) {
+TEST_P(QpackEncoderTest, InvalidHeaderAcknowledgement) {
// Encoder receives header acknowledgement for a stream on which no header
// block with dynamic table entries was ever sent.
EXPECT_CALL(
@@ -249,7 +292,7 @@
encoder_.OnHeaderAcknowledgement(/* stream_id = */ 0);
}
-TEST_F(QpackEncoderTest, DynamicTable) {
+TEST_P(QpackEncoderTest, DynamicTable) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
encoder_.SetMaximumBlockedStreams(1);
@@ -265,9 +308,17 @@
// Set Dynamic Table Capacity instruction.
std::string set_dyanamic_table_capacity = absl::HexStringToBytes("3fe11f");
// Insert three entries into the dynamic table.
- std::string insert_entries = absl::HexStringToBytes(
- "62" // insert without name reference
- "94e7" // Huffman-encoded name "foo"
+ std::string insert_entries;
+ if (DisableHuffmanEncoding()) {
+ insert_entries = absl::HexStringToBytes(
+ "43" // insert without name reference
+ "666f6f"); // Huffman-encoded name "foo"
+ } else {
+ insert_entries = absl::HexStringToBytes(
+ "62" // insert without name reference
+ "94e7"); // Huffman-encoded name "foo"
+ }
+ insert_entries += absl::HexStringToBytes(
"03626172" // value "bar"
"80" // insert with name reference, dynamic index 0
"0362617a" // value "baz"
@@ -286,7 +337,7 @@
}
// There is no room in the dynamic table after inserting the first entry.
-TEST_F(QpackEncoderTest, SmallDynamicTable) {
+TEST_P(QpackEncoderTest, SmallDynamicTable) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
encoder_.SetMaximumBlockedStreams(1);
@@ -303,10 +354,18 @@
// Set Dynamic Table Capacity instruction.
std::string set_dyanamic_table_capacity = absl::HexStringToBytes("3f07");
// Insert one entry into the dynamic table.
- std::string insert_entry = absl::HexStringToBytes(
- "62" // insert without name reference
- "94e7" // Huffman-encoded name "foo"
- "03626172"); // value "bar"
+ std::string insert_entry;
+ if (DisableHuffmanEncoding()) {
+ insert_entry = absl::HexStringToBytes(
+ "43" // insert without name reference
+ "666f6f" // Huffman-encoded name "foo"
+ "03626172"); // value "bar"
+ } else {
+ insert_entry = absl::HexStringToBytes(
+ "62" // insert without name reference
+ "94e7" // Huffman-encoded name "foo"
+ "03626172"); // value "bar"
+ }
EXPECT_CALL(encoder_stream_sender_delegate_,
WriteStreamData(
Eq(absl::StrCat(set_dyanamic_table_capacity, insert_entry))));
@@ -324,7 +383,7 @@
EXPECT_EQ(insert_entry.size(), encoder_stream_sent_byte_count_);
}
-TEST_F(QpackEncoderTest, BlockedStream) {
+TEST_P(QpackEncoderTest, BlockedStream) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
encoder_.SetMaximumBlockedStreams(1);
@@ -337,10 +396,18 @@
// Set Dynamic Table Capacity instruction.
std::string set_dyanamic_table_capacity = absl::HexStringToBytes("3fe11f");
// Insert one entry into the dynamic table.
- std::string insert_entry1 = absl::HexStringToBytes(
- "62" // insert without name reference
- "94e7" // Huffman-encoded name "foo"
- "03626172"); // value "bar"
+ std::string insert_entry1;
+ if (DisableHuffmanEncoding()) {
+ insert_entry1 = absl::HexStringToBytes(
+ "43" // insert without name reference
+ "666f6f" // Huffman-encoded name "foo"
+ "03626172"); // value "bar"
+ } else {
+ insert_entry1 = absl::HexStringToBytes(
+ "62" // insert without name reference
+ "94e7" // Huffman-encoded name "foo"
+ "03626172"); // value "bar"
+ }
EXPECT_CALL(encoder_stream_sender_delegate_,
WriteStreamData(Eq(
absl::StrCat(set_dyanamic_table_capacity, insert_entry1))));
@@ -359,15 +426,31 @@
header_list2["cookie"] = "baz"; // name matches static entry
header_list2["bar"] = "baz"; // no match
- EXPECT_EQ(absl::HexStringToBytes("0000" // prefix
- "2a94e7" // literal name "foo"
- "03626172" // with literal value "bar"
- "2a94e7" // literal name "foo"
- "0362617a" // with literal value "baz"
- "55" // name of static entry 5
- "0362617a" // with literal value "baz"
- "23626172" // literal name "bar"
- "0362617a"), // with literal value "baz"
+ std::string entries;
+ if (DisableHuffmanEncoding()) {
+ entries = absl::HexStringToBytes(
+ "0000" // prefix
+ "23666f6f" // literal name "foo"
+ "03626172" // with literal value "bar"
+ "23666f6f" // literal name "foo"
+ "0362617a" // with literal value "baz"
+ "55" // name of static entry 5
+ "0362617a" // with literal value "baz"
+ "23626172" // literal name "bar"
+ "0362617a"); // with literal value "baz"
+ } else {
+ entries = absl::HexStringToBytes(
+ "0000" // prefix
+ "2a94e7" // literal name "foo"
+ "03626172" // with literal value "bar"
+ "2a94e7" // literal name "foo"
+ "0362617a" // with literal value "baz"
+ "55" // name of static entry 5
+ "0362617a" // with literal value "baz"
+ "23626172" // literal name "bar"
+ "0362617a"); // with literal value "baz"
+ }
+ EXPECT_EQ(entries,
encoder_.EncodeHeaderList(/* stream_id = */ 2, header_list2,
&encoder_stream_sent_byte_count_));
EXPECT_EQ(0u, encoder_stream_sent_byte_count_);
@@ -396,14 +479,29 @@
// Stream 3 is blocked. Stream 4 is not allowed to block, but it can
// reference already acknowledged dynamic entry 0.
- EXPECT_EQ(absl::HexStringToBytes("0200" // prefix
- "80" // dynamic entry 0
- "2a94e7" // literal name "foo"
- "0362617a" // with literal value "baz"
- "2c21cfd4c5" // literal name "cookie"
- "0362617a" // with literal value "baz"
- "23626172" // literal name "bar"
- "0362617a"), // with literal value "baz"
+ std::string expected2;
+ if (DisableHuffmanEncoding()) {
+ expected2 = absl::HexStringToBytes(
+ "0200" // prefix
+ "80" // dynamic entry 0
+ "23666f6f" // literal name "foo"
+ "0362617a" // with literal value "baz"
+ "26636f6f6b6965" // literal name "cookie"
+ "0362617a" // with literal value "baz"
+ "23626172" // literal name "bar"
+ "0362617a"); // with literal value "baz"
+ } else {
+ expected2 = absl::HexStringToBytes(
+ "0200" // prefix
+ "80" // dynamic entry 0
+ "2a94e7" // literal name "foo"
+ "0362617a" // with literal value "baz"
+ "2c21cfd4c5" // literal name "cookie"
+ "0362617a" // with literal value "baz"
+ "23626172" // literal name "bar"
+ "0362617a"); // with literal value "baz"
+ }
+ EXPECT_EQ(expected2,
encoder_.EncodeHeaderList(/* stream_id = */ 4, header_list2,
&encoder_stream_sent_byte_count_));
EXPECT_EQ(0u, encoder_stream_sent_byte_count_);
@@ -433,7 +531,7 @@
EXPECT_EQ(0u, encoder_stream_sent_byte_count_);
}
-TEST_F(QpackEncoderTest, Draining) {
+TEST_P(QpackEncoderTest, Draining) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
spdy::Http2HeaderBlock header_list1;
@@ -489,15 +587,21 @@
// no room to insert new entry, it will be encoded with string literals.
header_list3.AppendValueOrAddHeader("two", "bar");
- EXPECT_EQ(absl::HexStringToBytes("0000" // prefix
- "2374776f" // literal name "two"
- "8294e7" // literal value "foo"
- "2374776f" // literal name "two"
- "03626172"), // literal value "bar"
- Encode(header_list3));
+ std::string entries =
+ "0000" // prefix
+ "2374776f"; // literal name "two"
+ if (DisableHuffmanEncoding()) {
+ entries += "03666f6f"; // literal name "foo"
+ } else {
+ entries += "8294e7"; // literal value "foo"
+ }
+ entries +=
+ "2374776f" // literal name "two"
+ "03626172"; // literal value "bar"
+ EXPECT_EQ(absl::HexStringToBytes(entries), Encode(header_list3));
}
-TEST_F(QpackEncoderTest, DynamicTableCapacityLessThanMaximum) {
+TEST_P(QpackEncoderTest, DynamicTableCapacityLessThanMaximum) {
encoder_.SetMaximumDynamicTableCapacity(1024);
encoder_.SetDynamicTableCapacity(30);
@@ -508,7 +612,7 @@
EXPECT_EQ(30u, header_table->dynamic_table_capacity());
}
-TEST_F(QpackEncoderTest, EncoderStreamWritesDisallowedThenAllowed) {
+TEST_P(QpackEncoderTest, EncoderStreamWritesDisallowedThenAllowed) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(kTooManyBytesBuffered));
encoder_.SetMaximumBlockedStreams(1);
@@ -523,14 +627,27 @@
// Encoder is not allowed to write on the encoder stream.
// No Set Dynamic Table Capacity or Insert instructions are sent.
// Headers are encoded as string literals.
- EXPECT_EQ(absl::HexStringToBytes("0000" // prefix
- "2a94e7" // literal name "foo"
- "03626172" // with literal value "bar"
- "2a94e7" // literal name "foo"
- "0362617a" // with literal value "baz"
- "55" // name of static entry 5
- "0362617a"), // with literal value "baz"
- Encode(header_list1));
+ std::string entries;
+ if (DisableHuffmanEncoding()) {
+ entries = absl::HexStringToBytes(
+ "0000" // prefix
+ "23666f6f" // literal name "foo"
+ "03626172" // with literal value "bar"
+ "23666f6f" // literal name "foo"
+ "0362617a" // with literal value "baz"
+ "55" // name of static entry 5
+ "0362617a"); // with literal value "baz"
+ } else {
+ entries = absl::HexStringToBytes(
+ "0000" // prefix
+ "2a94e7" // literal name "foo"
+ "03626172" // with literal value "bar"
+ "2a94e7" // literal name "foo"
+ "0362617a" // with literal value "baz"
+ "55" // name of static entry 5
+ "0362617a"); // with literal value "baz"
+ }
+ EXPECT_EQ(entries, Encode(header_list1));
EXPECT_EQ(0u, encoder_stream_sent_byte_count_);
@@ -549,9 +666,17 @@
// Set Dynamic Table Capacity instruction.
std::string set_dyanamic_table_capacity = absl::HexStringToBytes("3fe11f");
// Insert three entries into the dynamic table.
- std::string insert_entries = absl::HexStringToBytes(
- "62" // insert without name reference
- "94e7" // Huffman-encoded name "foo"
+ std::string insert_entries;
+ if (DisableHuffmanEncoding()) {
+ insert_entries = absl::HexStringToBytes(
+ "43" // insert without name reference
+ "666f6f"); // name "foo"
+ } else {
+ insert_entries = absl::HexStringToBytes(
+ "62" // insert without name reference
+ "94e7"); // Huffman-encoded name "foo"
+ }
+ insert_entries += absl::HexStringToBytes(
"03626172" // value "bar"
"80" // insert with name reference, dynamic index 0
"0362617a" // value "baz"
@@ -569,7 +694,7 @@
EXPECT_EQ(insert_entries.size(), encoder_stream_sent_byte_count_);
}
-TEST_F(QpackEncoderTest, EncoderStreamWritesAllowedThenDisallowed) {
+TEST_P(QpackEncoderTest, EncoderStreamWritesAllowedThenDisallowed) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
encoder_.SetMaximumBlockedStreams(1);
@@ -585,9 +710,17 @@
// Set Dynamic Table Capacity instruction.
std::string set_dyanamic_table_capacity = absl::HexStringToBytes("3fe11f");
// Insert three entries into the dynamic table.
- std::string insert_entries = absl::HexStringToBytes(
- "62" // insert without name reference
- "94e7" // Huffman-encoded name "foo"
+ std::string insert_entries;
+ if (DisableHuffmanEncoding()) {
+ insert_entries = absl::HexStringToBytes(
+ "43" // insert without name reference
+ "666f6f"); // name "foo"
+ } else {
+ insert_entries = absl::HexStringToBytes(
+ "62" // insert without name reference
+ "94e7"); // Huffman-encoded name "foo"
+ }
+ insert_entries += absl::HexStringToBytes(
"03626172" // value "bar"
"80" // insert with name reference, dynamic index 0
"0362617a" // value "baz"
@@ -630,7 +763,7 @@
}
// Regression test for https://crbug.com/1441880.
-TEST_F(QpackEncoderTest, UnackedEntryCannotBeEvicted) {
+TEST_P(QpackEncoderTest, UnackedEntryCannotBeEvicted) {
EXPECT_CALL(encoder_stream_sender_delegate_, NumBytesBuffered())
.WillRepeatedly(Return(0));
encoder_.SetMaximumBlockedStreams(2);
@@ -649,10 +782,18 @@
// Set Dynamic Table Capacity instruction.
std::string set_dyanamic_table_capacity = absl::HexStringToBytes("3f09");
// Insert one entry into the dynamic table.
- std::string insert_entries1 = absl::HexStringToBytes(
- "62" // insert without name reference
- "94e7" // Huffman-encoded name "foo"
- "03626172"); // value "bar"
+ std::string insert_entries1;
+ if (DisableHuffmanEncoding()) {
+ insert_entries1 = absl::HexStringToBytes(
+ "43" // insert without name reference
+ "666f6f" // Huffman-encoded name "foo"
+ "03626172"); // value "bar"
+ } else {
+ insert_entries1 = absl::HexStringToBytes(
+ "62" // insert without name reference
+ "94e7" // Huffman-encoded name "foo"
+ "03626172"); // value "bar"
+ }
EXPECT_CALL(encoder_stream_sender_delegate_,
WriteStreamData(Eq(
absl::StrCat(set_dyanamic_table_capacity, insert_entries1))));
diff --git a/quiche/quic/core/qpack/qpack_instruction_encoder.cc b/quiche/quic/core/qpack/qpack_instruction_encoder.cc
index 21f549c..60876d6 100644
--- a/quiche/quic/core/qpack/qpack_instruction_encoder.cc
+++ b/quiche/quic/core/qpack/qpack_instruction_encoder.cc
@@ -15,8 +15,10 @@
namespace quic {
-QpackInstructionEncoder::QpackInstructionEncoder()
- : use_huffman_(false),
+QpackInstructionEncoder::QpackInstructionEncoder(
+ HuffmanEncoding huffman_encoding)
+ : huffman_encoding_(huffman_encoding),
+ use_huffman_(false),
string_length_(0),
byte_(0),
state_(State::kOpcode),
@@ -142,16 +144,17 @@
(field_->type == QpackInstructionFieldType::kName) ? name : value;
string_length_ = string_to_write.size();
- size_t encoded_size = http2::HuffmanSize(string_to_write);
- use_huffman_ = encoded_size < string_length_;
+ if (huffman_encoding_ == HuffmanEncoding::kEnabled) {
+ size_t encoded_size = http2::HuffmanSize(string_to_write);
+ use_huffman_ = encoded_size < string_length_;
- if (use_huffman_) {
- QUICHE_DCHECK_EQ(0, byte_ & (1 << field_->param));
- byte_ |= (1 << field_->param);
+ if (use_huffman_) {
+ QUICHE_DCHECK_EQ(0, byte_ & (1 << field_->param));
+ byte_ |= (1 << field_->param);
- string_length_ = encoded_size;
+ string_length_ = encoded_size;
+ }
}
-
state_ = State::kVarintEncode;
}
diff --git a/quiche/quic/core/qpack/qpack_instruction_encoder.h b/quiche/quic/core/qpack/qpack_instruction_encoder.h
index 3d6003e..37cd3d1 100644
--- a/quiche/quic/core/qpack/qpack_instruction_encoder.h
+++ b/quiche/quic/core/qpack/qpack_instruction_encoder.h
@@ -14,12 +14,19 @@
namespace quic {
+// Enum which specifies if Huffman encoding should be used when sending
+// QPACK headers.
+enum class HuffmanEncoding {
+ kEnabled,
+ kDisabled,
+};
+
// Generic instruction encoder class. Takes a QpackLanguage that describes a
// language, that is, a set of instruction opcodes together with a list of
// fields that follow each instruction.
class QUICHE_EXPORT QpackInstructionEncoder {
public:
- QpackInstructionEncoder();
+ explicit QpackInstructionEncoder(HuffmanEncoding huffman_encoding);
QpackInstructionEncoder(const QpackInstructionEncoder&) = delete;
QpackInstructionEncoder& operator=(const QpackInstructionEncoder&) = delete;
@@ -57,6 +64,10 @@
void DoWriteString(absl::string_view name, absl::string_view value,
std::string* output);
+ // If true then Huffman encoding will not be used, regardless of the
+ // string size.
+ const HuffmanEncoding huffman_encoding_;
+
// True if name or value should be Huffman encoded.
bool use_huffman_;
diff --git a/quiche/quic/core/qpack/qpack_instruction_encoder_test.cc b/quiche/quic/core/qpack/qpack_instruction_encoder_test.cc
index dfdec9e..9880d3f 100644
--- a/quiche/quic/core/qpack/qpack_instruction_encoder_test.cc
+++ b/quiche/quic/core/qpack/qpack_instruction_encoder_test.cc
@@ -49,11 +49,18 @@
namespace {
-class QpackInstructionEncoderTest : public QuicTest {
+class QpackInstructionEncoderTest : public QuicTestWithParam<bool> {
protected:
- QpackInstructionEncoderTest() : verified_position_(0) {}
+ QpackInstructionEncoderTest()
+ : encoder_(HuffmanEncoding()), verified_position_(0) {}
~QpackInstructionEncoderTest() override = default;
+ bool DisableHuffmanEncoding() { return GetParam(); }
+ HuffmanEncoding HuffmanEncoding() {
+ return DisableHuffmanEncoding() ? HuffmanEncoding::kDisabled
+ : HuffmanEncoding::kEnabled;
+ }
+
// Append encoded |instruction| to |output_|.
void EncodeInstruction(
const QpackInstructionWithValues& instruction_with_values) {
@@ -76,7 +83,10 @@
std::string::size_type verified_position_;
};
-TEST_F(QpackInstructionEncoderTest, Varint) {
+INSTANTIATE_TEST_SUITE_P(DisableHuffmanEncoding, QpackInstructionEncoderTest,
+ testing::Values(false, true));
+
+TEST_P(QpackInstructionEncoderTest, Varint) {
const QpackInstruction instruction{QpackInstructionOpcode{0x00, 0x80},
{{QpackInstructionFieldType::kVarint, 7}}};
@@ -92,7 +102,7 @@
EXPECT_TRUE(EncodedSegmentMatches("7f00"));
}
-TEST_F(QpackInstructionEncoderTest, SBitAndTwoVarint2) {
+TEST_P(QpackInstructionEncoderTest, SBitAndTwoVarint2) {
const QpackInstruction instruction{
QpackInstructionOpcode{0x80, 0xc0},
{{QpackInstructionFieldType::kSbit, 0x20},
@@ -115,7 +125,7 @@
EXPECT_TRUE(EncodedSegmentMatches("9f00ff65"));
}
-TEST_F(QpackInstructionEncoderTest, SBitAndVarintAndValue) {
+TEST_P(QpackInstructionEncoderTest, SBitAndVarintAndValue) {
const QpackInstruction instruction{QpackInstructionOpcode{0xc0, 0xc0},
{{QpackInstructionFieldType::kSbit, 0x20},
{QpackInstructionFieldType::kVarint, 5},
@@ -128,7 +138,11 @@
QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 100);
QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "foo");
EncodeInstruction(instruction_with_values);
- EXPECT_TRUE(EncodedSegmentMatches("ff458294e7"));
+ if (DisableHuffmanEncoding()) {
+ EXPECT_TRUE(EncodedSegmentMatches("ff4503666f6f"));
+ } else {
+ EXPECT_TRUE(EncodedSegmentMatches("ff458294e7"));
+ }
QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false);
QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 3);
@@ -137,7 +151,7 @@
EXPECT_TRUE(EncodedSegmentMatches("c303626172"));
}
-TEST_F(QpackInstructionEncoderTest, Name) {
+TEST_P(QpackInstructionEncoderTest, Name) {
const QpackInstruction instruction{QpackInstructionOpcode{0xe0, 0xe0},
{{QpackInstructionFieldType::kName, 4}}};
@@ -150,14 +164,18 @@
QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "foo");
EncodeInstruction(instruction_with_values);
- EXPECT_TRUE(EncodedSegmentMatches("f294e7"));
+ if (DisableHuffmanEncoding()) {
+ EXPECT_TRUE(EncodedSegmentMatches("e3666f6f"));
+ } else {
+ EXPECT_TRUE(EncodedSegmentMatches("f294e7"));
+ }
QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "bar");
EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("e3626172"));
}
-TEST_F(QpackInstructionEncoderTest, Value) {
+TEST_P(QpackInstructionEncoderTest, Value) {
const QpackInstruction instruction{QpackInstructionOpcode{0xf0, 0xf0},
{{QpackInstructionFieldType::kValue, 3}}};
@@ -167,17 +185,20 @@
QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "");
EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("f0"));
-
QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "foo");
EncodeInstruction(instruction_with_values);
- EXPECT_TRUE(EncodedSegmentMatches("fa94e7"));
+ if (DisableHuffmanEncoding()) {
+ EXPECT_TRUE(EncodedSegmentMatches("f3666f6f"));
+ } else {
+ EXPECT_TRUE(EncodedSegmentMatches("fa94e7"));
+ }
QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar");
EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("f3626172"));
}
-TEST_F(QpackInstructionEncoderTest, SBitAndNameAndValue) {
+TEST_P(QpackInstructionEncoderTest, SBitAndNameAndValue) {
const QpackInstruction instruction{QpackInstructionOpcode{0xf0, 0xf0},
{{QpackInstructionFieldType::kSbit, 0x08},
{QpackInstructionFieldType::kName, 2},
@@ -196,7 +217,11 @@
QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "foo");
QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar");
EncodeInstruction(instruction_with_values);
- EXPECT_TRUE(EncodedSegmentMatches("fe94e703626172"));
+ if (DisableHuffmanEncoding()) {
+ EXPECT_TRUE(EncodedSegmentMatches("fb00666f6f03626172"));
+ } else {
+ EXPECT_TRUE(EncodedSegmentMatches("fe94e703626172"));
+ }
}
} // namespace
diff --git a/quiche/quic/core/qpack/qpack_round_trip_test.cc b/quiche/quic/core/qpack/qpack_round_trip_test.cc
index 147c627..ed3fb19 100644
--- a/quiche/quic/core/qpack/qpack_round_trip_test.cc
+++ b/quiche/quic/core/qpack/qpack_round_trip_test.cc
@@ -28,7 +28,8 @@
const spdy::Http2HeaderBlock& header_list) {
NoopDecoderStreamErrorDelegate decoder_stream_error_delegate;
NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
- QpackEncoder encoder(&decoder_stream_error_delegate);
+ QpackEncoder encoder(&decoder_stream_error_delegate,
+ HuffmanEncoding::kEnabled);
encoder.set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate);
std::string encoded_header_block =
encoder.EncodeHeaderList(/* stream_id = */ 1, header_list, nullptr);