Add HpackDecodingError enum, bubble up all third_party/http2/hpack/decoder errors to HpackDecoder.
Replace error_detected_ Boolean members with HpackDecodingError; false becomes
kOk, true is split to more gradual error codes.
gfe-relnote: n/a (no functional change)
PiperOrigin-RevId: 293809195
Change-Id: I8ec3264f1dd630045e438b4354b5453a3d9b3ef3
diff --git a/http2/hpack/decoder/hpack_block_decoder.h b/http2/hpack/decoder/hpack_block_decoder.h
index ed4b0b0..1e60af4 100644
--- a/http2/hpack/decoder/hpack_block_decoder.h
+++ b/http2/hpack/decoder/hpack_block_decoder.h
@@ -14,6 +14,7 @@
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
+#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoding_error.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder_listener.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
@@ -49,6 +50,9 @@
// first byte of a new HPACK entry)?
bool before_entry() const { return before_entry_; }
+ // Return error code after decoding error occurred in HpackEntryDecoder.
+ HpackDecodingError error() const { return entry_decoder_.error(); }
+
std::string DebugString() const;
private:
diff --git a/http2/hpack/decoder/hpack_decoder.cc b/http2/hpack/decoder/hpack_decoder.cc
index b0d5bf8..1013292 100644
--- a/http2/hpack/decoder/hpack_decoder.cc
+++ b/http2/hpack/decoder/hpack_decoder.cc
@@ -16,7 +16,7 @@
: decoder_state_(listener),
entry_buffer_(&decoder_state_, max_string_size),
block_decoder_(&entry_buffer_),
- error_detected_(false),
+ error_(HpackDecodingError::kOk),
http2_skip_querying_entry_buffer_error_(
GetHttp2ReloadableFlag(http2_skip_querying_entry_buffer_error)) {}
@@ -62,8 +62,7 @@
// which finally forwards them to the HpackDecoderListener.
DecodeStatus status = block_decoder_.Decode(db);
if (status == DecodeStatus::kDecodeError) {
- // This has probably already been reported, but just in case...
- ReportError("HPACK block malformed.");
+ ReportError(block_decoder_.error());
HTTP2_CODE_COUNT_N(decompress_failure_3, 4, 23);
return false;
} else if (DetectError()) {
@@ -88,7 +87,7 @@
}
if (!block_decoder_.before_entry()) {
// The HPACK block ended in the middle of an entry.
- ReportError("HPACK block truncated.");
+ ReportError(HpackDecodingError::kTruncatedBlock);
HTTP2_CODE_COUNT_N(decompress_failure_3, 7, 23);
return false;
}
@@ -102,42 +101,45 @@
}
bool HpackDecoder::DetectError() {
- if (error_detected_) {
+ if (error_ != HpackDecodingError::kOk) {
return true;
}
- if (decoder_state_.error_detected()) {
- HTTP2_DVLOG(2) << "HpackDecoder::error_detected in decoder_state_";
+ if (decoder_state_.error() != HpackDecodingError::kOk) {
+ HTTP2_DVLOG(2) << "Error detected in decoder_state_";
HTTP2_CODE_COUNT_N(decompress_failure_3, 10, 23);
HTTP2_CODE_COUNT_N(http2_skip_querying_entry_buffer_error, 1, 3);
- error_detected_ = true;
+ error_ = decoder_state_.error();
} else if (entry_buffer_.error_detected()) {
// This should never happen, because if an error had occured in
// |entry_buffer_|, it would have notified its listener, |decoder_state_|.
if (http2_skip_querying_entry_buffer_error_) {
HTTP2_CODE_COUNT_N(http2_skip_querying_entry_buffer_error, 2, 3);
} else {
- HTTP2_DVLOG(2) << "HpackDecoder::error_detected in entry_buffer_";
+ HTTP2_DVLOG(2) << "Error detected in entry_buffer_";
HTTP2_CODE_COUNT_N(decompress_failure_3, 9, 23);
HTTP2_CODE_COUNT_N(http2_skip_querying_entry_buffer_error, 3, 3);
- error_detected_ = true;
+ // Since this code path should never be executed, error code does not
+ // matter as long as it is not HpackDecodingError::kOk.
+ error_ = HpackDecodingError::kIndexVarintError;
}
}
- return error_detected_;
+ return error_ != HpackDecodingError::kOk;
}
size_t HpackDecoder::EstimateMemoryUsage() const {
return Http2EstimateMemoryUsage(entry_buffer_);
}
-void HpackDecoder::ReportError(quiche::QuicheStringPiece error_message) {
+void HpackDecoder::ReportError(HpackDecodingError error) {
HTTP2_DVLOG(3) << "HpackDecoder::ReportError is new="
- << (!error_detected_ ? "true" : "false")
- << ", error_message: " << error_message;
- if (!error_detected_) {
- error_detected_ = true;
- decoder_state_.listener()->OnHeaderErrorDetected(error_message);
+ << (error_ == HpackDecodingError::kOk ? "true" : "false")
+ << ", error: " << HpackDecodingErrorToString(error);
+ if (error_ == HpackDecodingError::kOk) {
+ error_ = error;
+ decoder_state_.listener()->OnHeaderErrorDetected(
+ HpackDecodingErrorToString(error));
}
}
diff --git a/http2/hpack/decoder/hpack_decoder.h b/http2/hpack/decoder/hpack_decoder.h
index 1b332d9..6e63604 100644
--- a/http2/hpack/decoder/hpack_decoder.h
+++ b/http2/hpack/decoder/hpack_decoder.h
@@ -28,9 +28,9 @@
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_listener.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables.h"
+#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoding_error.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_whole_entry_buffer.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_export.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
namespace http2 {
namespace test {
@@ -93,9 +93,13 @@
bool EndDecodingBlock();
// If no error has been detected so far, query |decoder_state_| for errors and
- // set |error_detected_| if necessary.
+ // set |error_| if necessary. Returns true if an error has ever been
+ // detected.
bool DetectError();
+ // Error code if an error has occurred, HpackDecodingError::kOk otherwise.
+ HpackDecodingError error() const { return error_; }
+
// Returns the estimate of dynamically allocated memory in bytes.
size_t EstimateMemoryUsage() const;
@@ -103,7 +107,7 @@
friend class test::HpackDecoderPeer;
// Reports an error to the listener IF this is the first error detected.
- void ReportError(quiche::QuicheStringPiece error_message);
+ void ReportError(HpackDecodingError error);
// The decompressor state, as defined by HPACK (i.e. the static and dynamic
// tables).
@@ -115,8 +119,8 @@
// The decoder of HPACK blocks into entry parts, passed to entry_buffer_.
HpackBlockDecoder block_decoder_;
- // Has an error been detected?
- bool error_detected_;
+ // Error code if an error has occurred, HpackDecodingError::kOk otherwise.
+ HpackDecodingError error_;
// Latched value of reloadable_flag_http2_skip_querying_entry_buffer_error.
const bool http2_skip_querying_entry_buffer_error_;
diff --git a/http2/hpack/decoder/hpack_decoder_state.cc b/http2/hpack/decoder/hpack_decoder_state.cc
index 7c10b52..09b64c0 100644
--- a/http2/hpack/decoder/hpack_decoder_state.cc
+++ b/http2/hpack/decoder/hpack_decoder_state.cc
@@ -31,7 +31,7 @@
require_dynamic_table_size_update_(false),
allow_dynamic_table_size_update_(true),
saw_dynamic_table_size_update_(false),
- error_detected_(false) {}
+ error_(HpackDecodingError::kOk) {}
HpackDecoderState::~HpackDecoderState() = default;
void HpackDecoderState::set_tables_debug_listener(
@@ -59,7 +59,8 @@
// This instance can't be reused after an error has been detected, as we must
// assume that the encoder and decoder compression states are no longer
// synchronized.
- DCHECK(!error_detected_);
+ DCHECK(error_ == HpackDecodingError::kOk)
+ << HpackDecodingErrorToString(error_);
DCHECK_LE(lowest_header_table_size_, final_header_table_size_);
allow_dynamic_table_size_update_ = true;
saw_dynamic_table_size_update_ = false;
@@ -80,11 +81,11 @@
void HpackDecoderState::OnIndexedHeader(size_t index) {
HTTP2_DVLOG(2) << "HpackDecoderState::OnIndexedHeader: " << index;
- if (error_detected_) {
+ if (error_ != HpackDecodingError::kOk) {
return;
}
if (require_dynamic_table_size_update_) {
- ReportError("Missing dynamic table size update.");
+ ReportError(HpackDecodingError::kMissingDynamicTableSizeUpdate);
return;
}
allow_dynamic_table_size_update_ = false;
@@ -92,7 +93,7 @@
if (entry != nullptr) {
listener_->OnHeader(entry->name, entry->value);
} else {
- ReportError("Invalid index.");
+ ReportError(HpackDecodingError::kInvalidIndex);
}
}
@@ -103,11 +104,11 @@
HTTP2_DVLOG(2) << "HpackDecoderState::OnNameIndexAndLiteralValue "
<< entry_type << ", " << name_index << ", "
<< value_buffer->str();
- if (error_detected_) {
+ if (error_ != HpackDecodingError::kOk) {
return;
}
if (require_dynamic_table_size_update_) {
- ReportError("Missing dynamic table size update.");
+ ReportError(HpackDecodingError::kMissingDynamicTableSizeUpdate);
return;
}
allow_dynamic_table_size_update_ = false;
@@ -119,7 +120,7 @@
decoder_tables_.Insert(entry->name, value);
}
} else {
- ReportError("Invalid name index.");
+ ReportError(HpackDecodingError::kInvalidNameIndex);
}
}
@@ -129,11 +130,11 @@
HpackDecoderStringBuffer* value_buffer) {
HTTP2_DVLOG(2) << "HpackDecoderState::OnLiteralNameAndValue " << entry_type
<< ", " << name_buffer->str() << ", " << value_buffer->str();
- if (error_detected_) {
+ if (error_ != HpackDecodingError::kOk) {
return;
}
if (require_dynamic_table_size_update_) {
- ReportError("Missing dynamic table size update.");
+ ReportError(HpackDecodingError::kMissingDynamicTableSizeUpdate);
return;
}
allow_dynamic_table_size_update_ = false;
@@ -151,27 +152,29 @@
<< (require_dynamic_table_size_update_ ? "true" : "false")
<< ", allowed="
<< (allow_dynamic_table_size_update_ ? "true" : "false");
- if (error_detected_) {
+ if (error_ != HpackDecodingError::kOk) {
return;
}
DCHECK_LE(lowest_header_table_size_, final_header_table_size_);
if (!allow_dynamic_table_size_update_) {
// At most two dynamic table size updates allowed at the start, and not
// after a header.
- ReportError("Dynamic table size update not allowed.");
+ ReportError(HpackDecodingError::kDynamicTableSizeUpdateNotAllowed);
return;
}
if (require_dynamic_table_size_update_) {
// The new size must not be greater than the low water mark.
if (size_limit > lowest_header_table_size_) {
- ReportError("Initial dynamic table size update is above low water mark.");
+ ReportError(HpackDecodingError::
+ kInitialDynamicTableSizeUpdateIsAboveLowWaterMark);
return;
}
require_dynamic_table_size_update_ = false;
} else if (size_limit > final_header_table_size_) {
// The new size must not be greater than the final max header table size
// that the peer acknowledged.
- ReportError("Dynamic table size update is above acknowledged setting.");
+ ReportError(
+ HpackDecodingError::kDynamicTableSizeUpdateIsAboveAcknowledgedSetting);
return;
}
decoder_tables_.DynamicTableSizeUpdate(size_limit);
@@ -184,35 +187,35 @@
lowest_header_table_size_ = final_header_table_size_;
}
-void HpackDecoderState::OnHpackDecodeError(
- quiche::QuicheStringPiece error_message) {
- HTTP2_DVLOG(2) << "HpackDecoderState::OnHpackDecodeError " << error_message;
- if (!error_detected_) {
- ReportError(error_message);
+void HpackDecoderState::OnHpackDecodeError(HpackDecodingError error) {
+ HTTP2_DVLOG(2) << "HpackDecoderState::OnHpackDecodeError "
+ << HpackDecodingErrorToString(error);
+ if (error_ == HpackDecodingError::kOk) {
+ ReportError(error);
}
}
void HpackDecoderState::OnHeaderBlockEnd() {
HTTP2_DVLOG(2) << "HpackDecoderState::OnHeaderBlockEnd";
- if (error_detected_) {
+ if (error_ != HpackDecodingError::kOk) {
return;
}
if (require_dynamic_table_size_update_) {
// Apparently the HPACK block was empty, but we needed it to contain at
// least 1 dynamic table size update.
- ReportError("Missing dynamic table size update.");
+ ReportError(HpackDecodingError::kMissingDynamicTableSizeUpdate);
} else {
listener_->OnHeaderListEnd();
}
}
-void HpackDecoderState::ReportError(quiche::QuicheStringPiece error_message) {
+void HpackDecoderState::ReportError(HpackDecodingError error) {
HTTP2_DVLOG(2) << "HpackDecoderState::ReportError is new="
- << (!error_detected_ ? "true" : "false")
- << ", error_message: " << error_message;
- if (!error_detected_) {
- listener_->OnHeaderErrorDetected(error_message);
- error_detected_ = true;
+ << (error_ == HpackDecodingError::kOk ? "true" : "false")
+ << ", error: " << HpackDecodingErrorToString(error);
+ if (error_ == HpackDecodingError::kOk) {
+ listener_->OnHeaderErrorDetected(HpackDecodingErrorToString(error));
+ error_ = error;
}
}
diff --git a/http2/hpack/decoder/hpack_decoder_state.h b/http2/hpack/decoder/hpack_decoder_state.h
index 4436ef3..0735f6a 100644
--- a/http2/hpack/decoder/hpack_decoder_state.h
+++ b/http2/hpack/decoder/hpack_decoder_state.h
@@ -19,6 +19,7 @@
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_listener.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables.h"
+#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoding_error.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_whole_entry_listener.h"
#include "net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_export.h"
@@ -76,15 +77,15 @@
HpackDecoderStringBuffer* name_buffer,
HpackDecoderStringBuffer* value_buffer) override;
void OnDynamicTableSizeUpdate(size_t size) override;
- void OnHpackDecodeError(quiche::QuicheStringPiece error_message) override;
+ void OnHpackDecodeError(HpackDecodingError error) override;
// OnHeaderBlockEnd notifies this object that an entire HPACK block has been
// decoded, which might have extended into CONTINUATION blocks.
void OnHeaderBlockEnd();
- // Was an error detected? After an error has been detected and reported,
- // no further callbacks will be made to the listener.
- bool error_detected() const { return error_detected_; }
+ // Returns error code after an error has been detected and reported.
+ // No further callbacks will be made to the listener.
+ HpackDecodingError error() const { return error_; }
const HpackDecoderTables& decoder_tables_for_test() const {
return decoder_tables_;
@@ -94,7 +95,7 @@
friend class test::HpackDecoderStatePeer;
// Reports an error to the listener IF this is the first error detected.
- void ReportError(quiche::QuicheStringPiece error_message);
+ void ReportError(HpackDecodingError error);
// The static and dynamic HPACK tables.
HpackDecoderTables decoder_tables_;
@@ -121,7 +122,7 @@
bool saw_dynamic_table_size_update_;
// Has an error already been detected and reported to the listener?
- bool error_detected_;
+ HpackDecodingError error_;
};
} // namespace http2
diff --git a/http2/hpack/decoder/hpack_decoder_state_test.cc b/http2/hpack/decoder/hpack_decoder_state_test.cc
index 6f54cdb..02abb55 100644
--- a/http2/hpack/decoder/hpack_decoder_state_test.cc
+++ b/http2/hpack/decoder/hpack_decoder_state_test.cc
@@ -21,7 +21,6 @@
using ::testing::AssertionResult;
using ::testing::AssertionSuccess;
using ::testing::Eq;
-using ::testing::HasSubstr;
using ::testing::Mock;
using ::testing::StrictMock;
@@ -419,8 +418,8 @@
EXPECT_EQ(0u, header_table_size_limit());
// Three updates aren't allowed.
- EXPECT_CALL(listener_,
- OnHeaderErrorDetected(HasSubstr("size update not allowed")));
+ EXPECT_CALL(listener_, OnHeaderErrorDetected(
+ Eq("Dynamic table size update not allowed")));
SendSizeUpdate(0);
}
@@ -442,8 +441,8 @@
// Another HPACK block, but this time missing the required size update.
decoder_state_.ApplyHeaderTableSizeSetting(1024);
SendStartAndVerifyCallback();
- EXPECT_CALL(listener_, OnHeaderErrorDetected(
- HasSubstr("Missing dynamic table size update")));
+ EXPECT_CALL(listener_,
+ OnHeaderErrorDetected(Eq("Missing dynamic table size update")));
decoder_state_.OnIndexedHeader(1);
// Further decoded entries are ignored.
@@ -456,7 +455,7 @@
decoder_state_.OnLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader,
&name_buffer_, &value_buffer_);
decoder_state_.OnHeaderBlockEnd();
- decoder_state_.OnHpackDecodeError("NOT FORWARDED");
+ decoder_state_.OnHpackDecodeError(HpackDecodingError::kIndexVarintError);
}
// Confirm that required size updates are validated.
@@ -466,8 +465,10 @@
SendStartAndVerifyCallback();
EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
header_table_size_limit());
- EXPECT_CALL(listener_,
- OnHeaderErrorDetected(HasSubstr("above low water mark")));
+ EXPECT_CALL(
+ listener_,
+ OnHeaderErrorDetected(
+ Eq("Initial dynamic table size update is above low water mark")));
SendSizeUpdate(2048);
}
@@ -475,8 +476,8 @@
TEST_F(HpackDecoderStateTest, RequiredTableSizeChangeBeforeEnd) {
decoder_state_.ApplyHeaderTableSizeSetting(1024);
SendStartAndVerifyCallback();
- EXPECT_CALL(listener_, OnHeaderErrorDetected(
- HasSubstr("Missing dynamic table size update")));
+ EXPECT_CALL(listener_,
+ OnHeaderErrorDetected(Eq("Missing dynamic table size update")));
decoder_state_.OnHeaderBlockEnd();
}
@@ -487,26 +488,32 @@
EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
header_table_size_limit());
EXPECT_CALL(listener_,
- OnHeaderErrorDetected(HasSubstr("size update is above")));
+ OnHeaderErrorDetected(Eq(
+ "Dynamic table size update is above acknowledged setting")));
SendSizeUpdate(Http2SettingsInfo::DefaultHeaderTableSize() + 1);
}
TEST_F(HpackDecoderStateTest, InvalidStaticIndex) {
SendStartAndVerifyCallback();
- EXPECT_CALL(listener_, OnHeaderErrorDetected(HasSubstr("Invalid index")));
+ EXPECT_CALL(listener_,
+ OnHeaderErrorDetected(
+ Eq("Invalid index in indexed header field representation")));
decoder_state_.OnIndexedHeader(0);
}
TEST_F(HpackDecoderStateTest, InvalidDynamicIndex) {
SendStartAndVerifyCallback();
- EXPECT_CALL(listener_, OnHeaderErrorDetected(HasSubstr("Invalid index")));
+ EXPECT_CALL(listener_,
+ OnHeaderErrorDetected(
+ Eq("Invalid index in indexed header field representation")));
decoder_state_.OnIndexedHeader(kFirstDynamicTableIndex);
}
TEST_F(HpackDecoderStateTest, InvalidNameIndex) {
SendStartAndVerifyCallback();
EXPECT_CALL(listener_,
- OnHeaderErrorDetected(HasSubstr("Invalid name index")));
+ OnHeaderErrorDetected(Eq("Invalid index in literal header field "
+ "with indexed name representation")));
SetValue("value", UNBUFFERED);
decoder_state_.OnNameIndexAndLiteralValue(
HpackEntryType::kIndexedLiteralHeader, kFirstDynamicTableIndex,
@@ -515,9 +522,9 @@
TEST_F(HpackDecoderStateTest, ErrorsSuppressCallbacks) {
SendStartAndVerifyCallback();
- EXPECT_CALL(listener_, OnHeaderErrorDetected(quiche::QuicheStringPiece(
- "Huffman decode error.")));
- decoder_state_.OnHpackDecodeError("Huffman decode error.");
+ EXPECT_CALL(listener_,
+ OnHeaderErrorDetected(Eq("Name Huffman encoding error")));
+ decoder_state_.OnHpackDecodeError(HpackDecodingError::kNameHuffmanError);
// Further decoded entries are ignored.
decoder_state_.OnIndexedHeader(1);
@@ -529,7 +536,7 @@
decoder_state_.OnLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader,
&name_buffer_, &value_buffer_);
decoder_state_.OnHeaderBlockEnd();
- decoder_state_.OnHpackDecodeError("NOT FORWARDED");
+ decoder_state_.OnHpackDecodeError(HpackDecodingError::kIndexVarintError);
}
} // namespace
diff --git a/http2/hpack/decoder/hpack_decoder_test.cc b/http2/hpack/decoder/hpack_decoder_test.cc
index 1b8cdd9..7d6242d 100644
--- a/http2/hpack/decoder/hpack_decoder_test.cc
+++ b/http2/hpack/decoder/hpack_decoder_test.cc
@@ -31,7 +31,7 @@
using ::testing::AssertionResult;
using ::testing::AssertionSuccess;
using ::testing::ElementsAreArray;
-using ::testing::HasSubstr;
+using ::testing::Eq;
namespace http2 {
namespace test {
@@ -940,8 +940,11 @@
hbb.AppendDynamicTableSizeUpdate(1000);
hbb.AppendDynamicTableSizeUpdate(500);
EXPECT_FALSE(DecodeBlock(hbb.buffer()));
+ EXPECT_EQ(HpackDecodingError::kDynamicTableSizeUpdateNotAllowed,
+ decoder_.error());
EXPECT_EQ(1u, error_messages_.size());
- EXPECT_THAT(error_messages_[0], HasSubstr("size update not allowed"));
+ EXPECT_THAT(error_messages_[0],
+ Eq("Dynamic table size update not allowed"));
EXPECT_EQ(1000u, header_table_size_limit());
EXPECT_EQ(0u, current_header_table_size());
EXPECT_TRUE(header_entries_.empty());
@@ -997,8 +1000,11 @@
hbb.AppendIndexedHeader(5); // Not decoded.
EXPECT_FALSE(DecodeBlock(hbb.buffer()));
EXPECT_FALSE(saw_end_);
+ EXPECT_EQ(HpackDecodingError::kDynamicTableSizeUpdateNotAllowed,
+ decoder_.error());
EXPECT_EQ(1u, error_messages_.size());
- EXPECT_THAT(error_messages_[0], HasSubstr("size update not allowed"));
+ EXPECT_THAT(error_messages_[0],
+ Eq("Dynamic table size update not allowed"));
EXPECT_EQ(700u, header_table_size_limit());
EXPECT_EQ(0u, current_header_table_size());
EXPECT_TRUE(header_entries_.empty());
@@ -1020,8 +1026,12 @@
DecodeBuffer db(hbb.buffer());
EXPECT_FALSE(decoder_.DecodeFragment(&db));
EXPECT_FALSE(saw_end_);
+ EXPECT_EQ(
+ HpackDecodingError::kInitialDynamicTableSizeUpdateIsAboveLowWaterMark,
+ decoder_.error());
EXPECT_EQ(1u, error_messages_.size());
- EXPECT_THAT(error_messages_[0], HasSubstr("above low water mark"));
+ EXPECT_THAT(error_messages_[0],
+ Eq("Initial dynamic table size update is above low water mark"));
EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
header_table_size_limit());
}
@@ -1030,9 +1040,10 @@
TEST_P(HpackDecoderTest, RequiredTableSizeChangeBeforeEnd) {
decoder_.ApplyHeaderTableSizeSetting(1024);
EXPECT_FALSE(DecodeBlock(""));
+ EXPECT_EQ(HpackDecodingError::kMissingDynamicTableSizeUpdate,
+ decoder_.error());
EXPECT_EQ(1u, error_messages_.size());
- EXPECT_THAT(error_messages_[0],
- HasSubstr("Missing dynamic table size update"));
+ EXPECT_THAT(error_messages_[0], Eq("Missing dynamic table size update"));
EXPECT_FALSE(saw_end_);
}
@@ -1043,9 +1054,10 @@
HpackBlockBuilder hbb;
hbb.AppendIndexedHeader(1);
EXPECT_FALSE(DecodeBlock(hbb.buffer()));
+ EXPECT_EQ(HpackDecodingError::kMissingDynamicTableSizeUpdate,
+ decoder_.error());
EXPECT_EQ(1u, error_messages_.size());
- EXPECT_THAT(error_messages_[0],
- HasSubstr("Missing dynamic table size update"));
+ EXPECT_THAT(error_messages_[0], Eq("Missing dynamic table size update"));
EXPECT_FALSE(saw_end_);
EXPECT_TRUE(header_entries_.empty());
}
@@ -1059,9 +1071,10 @@
hbb.AppendNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader, 2,
false, "PUT");
EXPECT_FALSE(DecodeBlock(hbb.buffer()));
+ EXPECT_EQ(HpackDecodingError::kMissingDynamicTableSizeUpdate,
+ decoder_.error());
EXPECT_EQ(1u, error_messages_.size());
- EXPECT_THAT(error_messages_[0],
- HasSubstr("Missing dynamic table size update"));
+ EXPECT_THAT(error_messages_[0], Eq("Missing dynamic table size update"));
EXPECT_FALSE(saw_end_);
EXPECT_TRUE(header_entries_.empty());
}
@@ -1074,9 +1087,10 @@
hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader,
false, "name", false, "some data.");
EXPECT_FALSE(DecodeBlock(hbb.buffer()));
+ EXPECT_EQ(HpackDecodingError::kMissingDynamicTableSizeUpdate,
+ decoder_.error());
EXPECT_EQ(1u, error_messages_.size());
- EXPECT_THAT(error_messages_[0],
- HasSubstr("Missing dynamic table size update"));
+ EXPECT_THAT(error_messages_[0], Eq("Missing dynamic table size update"));
EXPECT_FALSE(saw_end_);
EXPECT_TRUE(header_entries_.empty());
}
@@ -1090,8 +1104,10 @@
EXPECT_FALSE(decoder_.DecodeFragment(&db));
EXPECT_TRUE(decoder_.DetectError());
EXPECT_FALSE(saw_end_);
+ EXPECT_EQ(HpackDecodingError::kIndexVarintError, decoder_.error());
EXPECT_EQ(1u, error_messages_.size());
- EXPECT_THAT(error_messages_[0], HasSubstr("malformed"));
+ EXPECT_THAT(error_messages_[0],
+ Eq("Index varint beyond implementation limit"));
EXPECT_TRUE(header_entries_.empty());
// Now that an error has been detected, EndDecodingBlock should not succeed.
EXPECT_FALSE(decoder_.EndDecodingBlock());
@@ -1105,8 +1121,10 @@
EXPECT_FALSE(decoder_.DecodeFragment(&db));
EXPECT_TRUE(decoder_.DetectError());
EXPECT_FALSE(saw_end_);
+ EXPECT_EQ(HpackDecodingError::kInvalidIndex, decoder_.error());
EXPECT_EQ(1u, error_messages_.size());
- EXPECT_THAT(error_messages_[0], HasSubstr("Invalid index"));
+ EXPECT_THAT(error_messages_[0],
+ Eq("Invalid index in indexed header field representation"));
EXPECT_TRUE(header_entries_.empty());
// Now that an error has been detected, EndDecodingBlock should not succeed.
EXPECT_FALSE(decoder_.EndDecodingBlock());
@@ -1128,8 +1146,10 @@
// But not if the block is truncated.
EXPECT_FALSE(DecodeBlock(hbb.buffer().substr(0, hbb.size() - 1)));
EXPECT_FALSE(saw_end_);
+ EXPECT_EQ(HpackDecodingError::kTruncatedBlock, decoder_.error());
EXPECT_EQ(1u, error_messages_.size());
- EXPECT_THAT(error_messages_[0], HasSubstr("truncated"));
+ EXPECT_THAT(error_messages_[0],
+ Eq("Block ends in the middle of an instruction"));
// The first update was decoded.
EXPECT_EQ(3000u, header_table_size_limit());
EXPECT_EQ(0u, current_header_table_size());
@@ -1156,8 +1176,9 @@
EXPECT_THAT(header_entries_,
ElementsAreArray({HpackHeaderEntry{"name", "some data."}}));
EXPECT_FALSE(saw_end_);
+ EXPECT_EQ(HpackDecodingError::kValueTooLong, decoder_.error());
EXPECT_EQ(1u, error_messages_.size());
- EXPECT_THAT(error_messages_[0], HasSubstr("too long"));
+ EXPECT_THAT(error_messages_[0], Eq("Value length exceeds buffer limit"));
}
} // namespace
diff --git a/http2/hpack/decoder/hpack_decoding_error.cc b/http2/hpack/decoder/hpack_decoding_error.cc
new file mode 100644
index 0000000..56eec6c
--- /dev/null
+++ b/http2/hpack/decoder/hpack_decoding_error.cc
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoding_error.h"
+
+namespace http2 {
+
+// static
+quiche::QuicheStringPiece HpackDecodingErrorToString(HpackDecodingError error) {
+ switch (error) {
+ case HpackDecodingError::kOk:
+ return "No error detected";
+ case HpackDecodingError::kIndexVarintError:
+ return "Index varint beyond implementation limit";
+ case HpackDecodingError::kNameLengthVarintError:
+ return "Name length varint beyond implementation limit";
+ case HpackDecodingError::kValueLengthVarintError:
+ return "Value length varint beyond implementation limit";
+ case HpackDecodingError::kNameTooLong:
+ return "Name length exceeds buffer limit";
+ case HpackDecodingError::kValueTooLong:
+ return "Value length exceeds buffer limit";
+ case HpackDecodingError::kNameHuffmanError:
+ return "Name Huffman encoding error";
+ case HpackDecodingError::kValueHuffmanError:
+ return "Value Huffman encoding error";
+ case HpackDecodingError::kMissingDynamicTableSizeUpdate:
+ return "Missing dynamic table size update";
+ case HpackDecodingError::kInvalidIndex:
+ return "Invalid index in indexed header field representation";
+ case HpackDecodingError::kInvalidNameIndex:
+ return "Invalid index in literal header field with indexed name "
+ "representation";
+ case HpackDecodingError::kDynamicTableSizeUpdateNotAllowed:
+ return "Dynamic table size update not allowed";
+ case HpackDecodingError::kInitialDynamicTableSizeUpdateIsAboveLowWaterMark:
+ return "Initial dynamic table size update is above low water mark";
+ case HpackDecodingError::kDynamicTableSizeUpdateIsAboveAcknowledgedSetting:
+ return "Dynamic table size update is above acknowledged setting";
+ case HpackDecodingError::kTruncatedBlock:
+ return "Block ends in the middle of an instruction";
+ }
+ return "invalid HpackDecodingError value";
+}
+
+} // namespace http2
diff --git a/http2/hpack/decoder/hpack_decoding_error.h b/http2/hpack/decoder/hpack_decoding_error.h
new file mode 100644
index 0000000..98df064
--- /dev/null
+++ b/http2/hpack/decoder/hpack_decoding_error.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODING_ERROR_H_
+#define QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODING_ERROR_H_
+
+#include "net/third_party/quiche/src/common/platform/api/quiche_export.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+
+namespace http2 {
+
+enum class HpackDecodingError {
+ // No error detected so far.
+ kOk,
+ // Varint beyond implementation limit.
+ kIndexVarintError,
+ kNameLengthVarintError,
+ kValueLengthVarintError,
+ // String literal length exceeds buffer limit.
+ kNameTooLong,
+ kValueTooLong,
+ // Error in Huffman encoding.
+ kNameHuffmanError,
+ kValueHuffmanError,
+ // Next instruction should have been a dynamic table size update.
+ kMissingDynamicTableSizeUpdate,
+ // Invalid index in indexed header field representation.
+ kInvalidIndex,
+ // Invalid index in literal header field with indexed name representation.
+ kInvalidNameIndex,
+ // Dynamic table size update not allowed.
+ kDynamicTableSizeUpdateNotAllowed,
+ // Initial dynamic table size update is above low water mark.
+ kInitialDynamicTableSizeUpdateIsAboveLowWaterMark,
+ // Dynamic table size update is above acknowledged setting.
+ kDynamicTableSizeUpdateIsAboveAcknowledgedSetting,
+ // HPACK block ends in the middle of an instruction.
+ kTruncatedBlock,
+};
+
+QUICHE_EXPORT_PRIVATE quiche::QuicheStringPiece HpackDecodingErrorToString(
+ HpackDecodingError error);
+
+} // namespace http2
+
+#endif // QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODING_ERROR_H_
diff --git a/http2/hpack/decoder/hpack_entry_decoder.cc b/http2/hpack/decoder/hpack_entry_decoder.cc
index e177728..4e8b4d0 100644
--- a/http2/hpack/decoder/hpack_entry_decoder.cc
+++ b/http2/hpack/decoder/hpack_entry_decoder.cc
@@ -80,6 +80,7 @@
return status;
case DecodeStatus::kDecodeError:
HTTP2_CODE_COUNT_N(decompress_failure_3, 11, 23);
+ error_ = HpackDecodingError::kIndexVarintError;
// The varint must have been invalid (too long).
return status;
}
@@ -104,6 +105,7 @@
status = entry_type_decoder_.Resume(db);
if (status == DecodeStatus::kDecodeError) {
HTTP2_CODE_COUNT_N(decompress_failure_3, 12, 23);
+ error_ = HpackDecodingError::kIndexVarintError;
}
if (status != DecodeStatus::kDecodeDone) {
return status;
@@ -136,6 +138,7 @@
state_ = EntryDecoderState::kResumeDecodingName;
if (status == DecodeStatus::kDecodeError) {
HTTP2_CODE_COUNT_N(decompress_failure_3, 13, 23);
+ error_ = HpackDecodingError::kNameLengthVarintError;
}
return status;
}
@@ -151,6 +154,7 @@
}
if (status == DecodeStatus::kDecodeError) {
HTTP2_CODE_COUNT_N(decompress_failure_3, 14, 23);
+ error_ = HpackDecodingError::kValueLengthVarintError;
}
if (status == DecodeStatus::kDecodeDone) {
// Done with decoding the literal value, so we've reached the
@@ -180,6 +184,7 @@
state_ = EntryDecoderState::kResumeDecodingName;
if (status == DecodeStatus::kDecodeError) {
HTTP2_CODE_COUNT_N(decompress_failure_3, 15, 23);
+ error_ = HpackDecodingError::kNameLengthVarintError;
}
return status;
}
@@ -196,6 +201,7 @@
}
if (status == DecodeStatus::kDecodeError) {
HTTP2_CODE_COUNT_N(decompress_failure_3, 16, 23);
+ error_ = HpackDecodingError::kValueLengthVarintError;
}
if (status == DecodeStatus::kDecodeDone) {
// Done with decoding the value, therefore the entry as a whole.
diff --git a/http2/hpack/decoder/hpack_entry_decoder.h b/http2/hpack/decoder/hpack_entry_decoder.h
index 1da3644..3e77254 100644
--- a/http2/hpack/decoder/hpack_entry_decoder.h
+++ b/http2/hpack/decoder/hpack_entry_decoder.h
@@ -14,6 +14,7 @@
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
+#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoding_error.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder_listener.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_type_decoder.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder.h"
@@ -63,6 +64,9 @@
// in decoding the entry type and its varint.
DecodeStatus Resume(DecodeBuffer* db, HpackEntryDecoderListener* listener);
+ // Return error code after decoding error occurred.
+ HpackDecodingError error() const { return error_; }
+
std::string DebugString() const;
void OutputDebugString(std::ostream& out) const;
@@ -73,6 +77,7 @@
HpackEntryTypeDecoder entry_type_decoder_;
HpackStringDecoder string_decoder_;
EntryDecoderState state_ = EntryDecoderState();
+ HpackDecodingError error_ = HpackDecodingError::kOk;
};
QUICHE_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out,
diff --git a/http2/hpack/decoder/hpack_whole_entry_buffer.cc b/http2/hpack/decoder/hpack_whole_entry_buffer.cc
index 2173756..da5613e 100644
--- a/http2/hpack/decoder/hpack_whole_entry_buffer.cc
+++ b/http2/hpack/decoder/hpack_whole_entry_buffer.cc
@@ -58,7 +58,7 @@
if (len > max_string_size_bytes_) {
HTTP2_DVLOG(1) << "Name length (" << len << ") is longer than permitted ("
<< max_string_size_bytes_ << ")";
- ReportError("HPACK entry name size is too long.");
+ ReportError(HpackDecodingError::kNameTooLong);
HTTP2_CODE_COUNT_N(decompress_failure_3, 18, 23);
return;
}
@@ -72,7 +72,7 @@
<< Http2HexDump(quiche::QuicheStringPiece(data, len));
DCHECK_EQ(maybe_name_index_, 0u);
if (!error_detected_ && !name_.OnData(data, len)) {
- ReportError("Error decoding HPACK entry name.");
+ ReportError(HpackDecodingError::kNameHuffmanError);
HTTP2_CODE_COUNT_N(decompress_failure_3, 19, 23);
}
}
@@ -81,7 +81,7 @@
HTTP2_DVLOG(2) << "HpackWholeEntryBuffer::OnNameEnd";
DCHECK_EQ(maybe_name_index_, 0u);
if (!error_detected_ && !name_.OnEnd()) {
- ReportError("Error decoding HPACK entry name.");
+ ReportError(HpackDecodingError::kNameHuffmanError);
HTTP2_CODE_COUNT_N(decompress_failure_3, 20, 23);
}
}
@@ -94,7 +94,7 @@
HTTP2_DVLOG(1) << "Value length (" << len
<< ") is longer than permitted (" << max_string_size_bytes_
<< ")";
- ReportError("HPACK entry value size is too long.");
+ ReportError(HpackDecodingError::kValueTooLong);
HTTP2_CODE_COUNT_N(decompress_failure_3, 21, 23);
return;
}
@@ -107,7 +107,7 @@
<< " data:\n"
<< Http2HexDump(quiche::QuicheStringPiece(data, len));
if (!error_detected_ && !value_.OnData(data, len)) {
- ReportError("Error decoding HPACK entry value.");
+ ReportError(HpackDecodingError::kValueHuffmanError);
HTTP2_CODE_COUNT_N(decompress_failure_3, 22, 23);
}
}
@@ -118,7 +118,7 @@
return;
}
if (!value_.OnEnd()) {
- ReportError("Error decoding HPACK entry value.");
+ ReportError(HpackDecodingError::kValueHuffmanError);
HTTP2_CODE_COUNT_N(decompress_failure_3, 23, 23);
return;
}
@@ -138,12 +138,12 @@
listener_->OnDynamicTableSizeUpdate(size);
}
-void HpackWholeEntryBuffer::ReportError(
- quiche::QuicheStringPiece error_message) {
+void HpackWholeEntryBuffer::ReportError(HpackDecodingError error) {
if (!error_detected_) {
- HTTP2_DVLOG(1) << "HpackWholeEntryBuffer::ReportError: " << error_message;
+ HTTP2_DVLOG(1) << "HpackWholeEntryBuffer::ReportError: "
+ << HpackDecodingErrorToString(error);
error_detected_ = true;
- listener_->OnHpackDecodeError(error_message);
+ listener_->OnHpackDecodeError(error);
listener_ = HpackWholeEntryNoOpListener::NoOpListener();
}
}
diff --git a/http2/hpack/decoder/hpack_whole_entry_buffer.h b/http2/hpack/decoder/hpack_whole_entry_buffer.h
index fd445c0..5c0bfe2 100644
--- a/http2/hpack/decoder/hpack_whole_entry_buffer.h
+++ b/http2/hpack/decoder/hpack_whole_entry_buffer.h
@@ -13,6 +13,7 @@
#include <stddef.h>
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.h"
+#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoding_error.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder_listener.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_whole_entry_listener.h"
#include "net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h"
@@ -79,7 +80,7 @@
void OnDynamicTableSizeUpdate(size_t size) override;
private:
- void ReportError(quiche::QuicheStringPiece error_message);
+ void ReportError(HpackDecodingError error);
HpackWholeEntryListener* listener_;
HpackDecoderStringBuffer name_, value_;
diff --git a/http2/hpack/decoder/hpack_whole_entry_buffer_test.cc b/http2/hpack/decoder/hpack_whole_entry_buffer_test.cc
index 4ac82ea..a48afd7 100644
--- a/http2/hpack/decoder/hpack_whole_entry_buffer_test.cc
+++ b/http2/hpack/decoder/hpack_whole_entry_buffer_test.cc
@@ -12,7 +12,6 @@
#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
using ::testing::AllOf;
-using ::testing::HasSubstr;
using ::testing::InSequence;
using ::testing::Property;
using ::testing::StrictMock;
@@ -37,8 +36,7 @@
HpackDecoderStringBuffer* name_buffer,
HpackDecoderStringBuffer* value_buffer));
MOCK_METHOD1(OnDynamicTableSizeUpdate, void(size_t size));
- MOCK_METHOD1(OnHpackDecodeError,
- void(quiche::QuicheStringPiece error_message));
+ MOCK_METHOD1(OnHpackDecodeError, void(HpackDecodingError error));
};
class HpackWholeEntryBufferTest : public ::testing::Test {
@@ -156,14 +154,14 @@
// Verify that a name longer than the allowed size generates an error.
TEST_F(HpackWholeEntryBufferTest, NameTooLong) {
entry_buffer_.OnStartLiteralHeader(HpackEntryType::kIndexedLiteralHeader, 0);
- EXPECT_CALL(listener_, OnHpackDecodeError(HasSubstr("HPACK entry name")));
+ EXPECT_CALL(listener_, OnHpackDecodeError(HpackDecodingError::kNameTooLong));
entry_buffer_.OnNameStart(false, kMaxStringSize + 1);
}
// Verify that a name longer than the allowed size generates an error.
TEST_F(HpackWholeEntryBufferTest, ValueTooLong) {
entry_buffer_.OnStartLiteralHeader(HpackEntryType::kIndexedLiteralHeader, 1);
- EXPECT_CALL(listener_, OnHpackDecodeError(HasSubstr("HPACK entry value")));
+ EXPECT_CALL(listener_, OnHpackDecodeError(HpackDecodingError::kValueTooLong));
entry_buffer_.OnValueStart(false, kMaxStringSize + 1);
}
@@ -176,7 +174,8 @@
entry_buffer_.OnNameStart(true, 4);
entry_buffer_.OnNameData(data, 3);
- EXPECT_CALL(listener_, OnHpackDecodeError(HasSubstr("HPACK entry name")));
+ EXPECT_CALL(listener_,
+ OnHpackDecodeError(HpackDecodingError::kNameHuffmanError));
entry_buffer_.OnNameData(data, 1);
@@ -187,14 +186,15 @@
// Verify that a Huffman encoded value that isn't properly terminated with
// a partial EOS symbol generates an error.
-TEST_F(HpackWholeEntryBufferTest, ValueeHuffmanError) {
+TEST_F(HpackWholeEntryBufferTest, ValueHuffmanError) {
const char data[] = "\x00\x00\x00";
entry_buffer_.OnStartLiteralHeader(HpackEntryType::kNeverIndexedLiteralHeader,
61);
entry_buffer_.OnValueStart(true, 3);
entry_buffer_.OnValueData(data, 3);
- EXPECT_CALL(listener_, OnHpackDecodeError(HasSubstr("HPACK entry value")));
+ EXPECT_CALL(listener_,
+ OnHpackDecodeError(HpackDecodingError::kValueHuffmanError));
entry_buffer_.OnValueEnd();
diff --git a/http2/hpack/decoder/hpack_whole_entry_listener.cc b/http2/hpack/decoder/hpack_whole_entry_listener.cc
index 69cf122..5003f11 100644
--- a/http2/hpack/decoder/hpack_whole_entry_listener.cc
+++ b/http2/hpack/decoder/hpack_whole_entry_listener.cc
@@ -20,8 +20,8 @@
HpackDecoderStringBuffer* name_buffer,
HpackDecoderStringBuffer* value_buffer) {}
void HpackWholeEntryNoOpListener::OnDynamicTableSizeUpdate(size_t size) {}
-void HpackWholeEntryNoOpListener::OnHpackDecodeError(
- quiche::QuicheStringPiece error_message) {}
+void HpackWholeEntryNoOpListener::OnHpackDecodeError(HpackDecodingError error) {
+}
// static
HpackWholeEntryNoOpListener* HpackWholeEntryNoOpListener::NoOpListener() {
diff --git a/http2/hpack/decoder/hpack_whole_entry_listener.h b/http2/hpack/decoder/hpack_whole_entry_listener.h
index 86e8e7f..ef2f77e 100644
--- a/http2/hpack/decoder/hpack_whole_entry_listener.h
+++ b/http2/hpack/decoder/hpack_whole_entry_listener.h
@@ -12,6 +12,7 @@
#include <stddef.h>
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.h"
+#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoding_error.h"
#include "net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_export.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
@@ -50,8 +51,7 @@
virtual void OnDynamicTableSizeUpdate(size_t size) = 0;
// OnHpackDecodeError is called if an error is detected while decoding.
- // error_message may be used in a GOAWAY frame as the Opaque Data.
- virtual void OnHpackDecodeError(quiche::QuicheStringPiece error_message) = 0;
+ virtual void OnHpackDecodeError(HpackDecodingError error) = 0;
};
// A no-op implementation of HpackWholeEntryDecoderListener, useful for ignoring
@@ -69,7 +69,7 @@
HpackDecoderStringBuffer* name_buffer,
HpackDecoderStringBuffer* value_buffer) override;
void OnDynamicTableSizeUpdate(size_t size) override;
- void OnHpackDecodeError(quiche::QuicheStringPiece error_message) override;
+ void OnHpackDecodeError(HpackDecodingError error) override;
// Returns a listener that ignores all the calls.
static HpackWholeEntryNoOpListener* NoOpListener();