Add and use unique SpdyFramerErrors and QuicErrorCodes for each HpackDecodingError entry.
gfe-relnote: protected by gfe2_reloadable_flag_spdy_enable_granular_decompress_errors.
PiperOrigin-RevId: 296436981
Change-Id: I5dc3107b303893e82ed84d79a65a74d9f83fe276
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index 0c818a3..bf76e2e 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -3527,8 +3527,12 @@
client_->SendMessage(headers, "");
client_->WaitForResponse();
- EXPECT_THAT(client_->connection_error(),
- IsError(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE));
+
+ QuicErrorCode expected_error =
+ GetQuicReloadableFlag(spdy_enable_granular_decompress_errors)
+ ? QUIC_HPACK_INDEX_VARINT_ERROR
+ : QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE;
+ EXPECT_THAT(client_->connection_error(), IsError(expected_error));
}
class WindowUpdateObserver : public QuicConnectionDebugVisitor {
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index 7d376fc..e46ea5d 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -139,13 +139,68 @@
}
void OnError(Http2DecoderAdapter::SpdyFramerError error) override {
- QuicErrorCode code = QUIC_INVALID_HEADERS_STREAM_DATA;
+ QuicErrorCode code;
switch (error) {
+ case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_INDEX_VARINT_ERROR:
+ code = QUIC_HPACK_NAME_LENGTH_VARINT_ERROR;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_NAME_LENGTH_VARINT_ERROR:
+ code = QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_VALUE_LENGTH_VARINT_ERROR:
+ code = QUIC_HPACK_NAME_TOO_LONG;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_NAME_TOO_LONG:
+ code = QUIC_HPACK_VALUE_TOO_LONG;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_VALUE_TOO_LONG:
+ code = QUIC_HPACK_INDEX_VARINT_ERROR;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_NAME_HUFFMAN_ERROR:
+ code = QUIC_HPACK_NAME_HUFFMAN_ERROR;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_VALUE_HUFFMAN_ERROR:
+ code = QUIC_HPACK_VALUE_HUFFMAN_ERROR;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE:
+ code = QUIC_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_INVALID_INDEX:
+ code = QUIC_HPACK_INVALID_INDEX;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_INVALID_NAME_INDEX:
+ code = QUIC_HPACK_INVALID_NAME_INDEX;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED:
+ code = QUIC_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_INITIAL_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK:
+ code = QUIC_HPACK_INITIAL_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING:
+ code = QUIC_HPACK_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_TRUNCATED_BLOCK:
+ code = QUIC_HPACK_TRUNCATED_BLOCK;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_FRAGMENT_TOO_LONG:
+ code = QUIC_HPACK_FRAGMENT_TOO_LONG;
+ break;
+ case Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT:
+ code = QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT;
+ break;
case Http2DecoderAdapter::SpdyFramerError::SPDY_DECOMPRESS_FAILURE:
code = QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE;
break;
default:
- break;
+ code = QUIC_INVALID_HEADERS_STREAM_DATA;
}
CloseConnection(quiche::QuicheStrCat(
"SPDY framing error: ",
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 82ac0d1..fc2f653 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -2745,6 +2745,40 @@
EXPECT_EQ(59u, hpack_encoder->CurrentHeaderTableSizeSetting());
}
+TEST_P(QuicSpdySessionTestServer, FineGrainedHpackErrorCodes) {
+ if (VersionUsesHttp3(transport_version())) {
+ // HPACK is not used in HTTP/3.
+ return;
+ }
+
+ QuicFlagSaver flag_saver;
+ SetQuicReloadableFlag(spdy_enable_granular_decompress_errors, true);
+
+ QuicStreamId request_stream_id = 5;
+ session_.CreateIncomingStream(request_stream_id);
+
+ // Index 126 does not exist (static table has 61 entries and dynamic table is
+ // empty).
+ std::string headers_frame = quiche::QuicheTextUtils::HexDecode(
+ "000006" // length
+ "01" // type
+ "24" // flags: PRIORITY | END_HEADERS
+ "00000005" // stream_id
+ "00000000" // stream dependency
+ "10" // weight
+ "fe"); // payload: reference to index 126.
+ QuicStreamId headers_stream_id =
+ QuicUtils::GetHeadersStreamId(transport_version());
+ QuicStreamFrame data(headers_stream_id, false, 0, headers_frame);
+
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_HPACK_INVALID_INDEX,
+ "SPDY framing error: HPACK_INVALID_INDEX",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET));
+ session_.OnStreamFrame(data);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/quic_error_codes.cc b/quic/core/quic_error_codes.cc
index 7aa0dff..ce9866c 100644
--- a/quic/core/quic_error_codes.cc
+++ b/quic/core/quic_error_codes.cc
@@ -169,6 +169,24 @@
RETURN_STRING_LITERAL(QUIC_HTTP_FRAME_ERROR);
RETURN_STRING_LITERAL(QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM);
RETURN_STRING_LITERAL(QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM);
+ RETURN_STRING_LITERAL(QUIC_HPACK_INDEX_VARINT_ERROR);
+ RETURN_STRING_LITERAL(QUIC_HPACK_NAME_LENGTH_VARINT_ERROR);
+ RETURN_STRING_LITERAL(QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR);
+ RETURN_STRING_LITERAL(QUIC_HPACK_NAME_TOO_LONG);
+ RETURN_STRING_LITERAL(QUIC_HPACK_VALUE_TOO_LONG);
+ RETURN_STRING_LITERAL(QUIC_HPACK_NAME_HUFFMAN_ERROR);
+ RETURN_STRING_LITERAL(QUIC_HPACK_VALUE_HUFFMAN_ERROR);
+ RETURN_STRING_LITERAL(QUIC_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE);
+ RETURN_STRING_LITERAL(QUIC_HPACK_INVALID_INDEX);
+ RETURN_STRING_LITERAL(QUIC_HPACK_INVALID_NAME_INDEX);
+ RETURN_STRING_LITERAL(QUIC_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED);
+ RETURN_STRING_LITERAL(
+ QUIC_HPACK_INITIAL_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK);
+ RETURN_STRING_LITERAL(
+ QUIC_HPACK_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING);
+ RETURN_STRING_LITERAL(QUIC_HPACK_TRUNCATED_BLOCK);
+ RETURN_STRING_LITERAL(QUIC_HPACK_FRAGMENT_TOO_LONG);
+ RETURN_STRING_LITERAL(QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT);
RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
// Intentionally have no default case, so we'll break the build
diff --git a/quic/core/quic_error_codes.h b/quic/core/quic_error_codes.h
index 9a08844..7f250c3 100644
--- a/quic/core/quic_error_codes.h
+++ b/quic/core/quic_error_codes.h
@@ -359,8 +359,42 @@
QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM = 133,
QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM = 134,
+ // HPACK header block decoding errors.
+ // Index varint beyond implementation limit.
+ QUIC_HPACK_INDEX_VARINT_ERROR = 135,
+ // Name length varint beyond implementation limit.
+ QUIC_HPACK_NAME_LENGTH_VARINT_ERROR = 136,
+ // Value length varint beyond implementation limit.
+ QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR = 137,
+ // Name length exceeds buffer limit.
+ QUIC_HPACK_NAME_TOO_LONG = 138,
+ // Value length exceeds buffer limit.
+ QUIC_HPACK_VALUE_TOO_LONG = 139,
+ // Name Huffman encoding error.
+ QUIC_HPACK_NAME_HUFFMAN_ERROR = 140,
+ // Value Huffman encoding error.
+ QUIC_HPACK_VALUE_HUFFMAN_ERROR = 141,
+ // Next instruction should have been a dynamic table size update.
+ QUIC_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE = 142,
+ // Invalid index in indexed header field representation.
+ QUIC_HPACK_INVALID_INDEX = 143,
+ // Invalid index in literal header field with indexed name representation.
+ QUIC_HPACK_INVALID_NAME_INDEX = 144,
+ // Dynamic table size update not allowed.
+ QUIC_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED = 145,
+ // Initial dynamic table size update is above low water mark.
+ QUIC_HPACK_INITIAL_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK = 146,
+ // Dynamic table size update is above acknowledged setting.
+ QUIC_HPACK_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING = 147,
+ // HPACK block ends in the middle of an instruction.
+ QUIC_HPACK_TRUNCATED_BLOCK = 148,
+ // Incoming data fragment exceeds buffer limit.
+ QUIC_HPACK_FRAGMENT_TOO_LONG = 149,
+ // Total compressed HPACK data size exceeds limit.
+ QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT = 150,
+
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 135,
+ QUIC_LAST_ERROR = 151,
};
// QuicErrorCodes is encoded as four octets on-the-wire when doing Google QUIC,
// or a varint62 when doing IETF QUIC. Ensure that its value does not exceed
diff --git a/quic/core/quic_types.cc b/quic/core/quic_types.cc
index 0fa7cfb..d39fffe 100644
--- a/quic/core/quic_types.cc
+++ b/quic/core/quic_types.cc
@@ -465,6 +465,51 @@
return {false,
{static_cast<uint64_t>(
QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_UNEXPECTED)}};
+ case QUIC_HPACK_INDEX_VARINT_ERROR:
+ return {false, {static_cast<uint64_t>(QUIC_HPACK_INDEX_VARINT_ERROR)}};
+ case QUIC_HPACK_NAME_LENGTH_VARINT_ERROR:
+ return {false,
+ {static_cast<uint64_t>(QUIC_HPACK_NAME_LENGTH_VARINT_ERROR)}};
+ case QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR:
+ return {false,
+ {static_cast<uint64_t>(QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR)}};
+ case QUIC_HPACK_NAME_TOO_LONG:
+ return {false, {static_cast<uint64_t>(QUIC_HPACK_NAME_TOO_LONG)}};
+ case QUIC_HPACK_VALUE_TOO_LONG:
+ return {false, {static_cast<uint64_t>(QUIC_HPACK_VALUE_TOO_LONG)}};
+ case QUIC_HPACK_NAME_HUFFMAN_ERROR:
+ return {false, {static_cast<uint64_t>(QUIC_HPACK_NAME_HUFFMAN_ERROR)}};
+ case QUIC_HPACK_VALUE_HUFFMAN_ERROR:
+ return {false, {static_cast<uint64_t>(QUIC_HPACK_VALUE_HUFFMAN_ERROR)}};
+ case QUIC_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE:
+ return {false,
+ {static_cast<uint64_t>(
+ QUIC_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE)}};
+ case QUIC_HPACK_INVALID_INDEX:
+ return {false, {static_cast<uint64_t>(QUIC_HPACK_INVALID_INDEX)}};
+ case QUIC_HPACK_INVALID_NAME_INDEX:
+ return {false, {static_cast<uint64_t>(QUIC_HPACK_INVALID_NAME_INDEX)}};
+ case QUIC_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED:
+ return {false,
+ {static_cast<uint64_t>(
+ QUIC_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED)}};
+ case QUIC_HPACK_INITIAL_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK:
+ return {
+ false,
+ {static_cast<uint64_t>(
+ QUIC_HPACK_INITIAL_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK)}};
+ case QUIC_HPACK_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING:
+ return {false,
+ {static_cast<uint64_t>(
+ QUIC_HPACK_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING)}};
+ case QUIC_HPACK_TRUNCATED_BLOCK:
+ return {false, {static_cast<uint64_t>(QUIC_HPACK_TRUNCATED_BLOCK)}};
+ case QUIC_HPACK_FRAGMENT_TOO_LONG:
+ return {false, {static_cast<uint64_t>(QUIC_HPACK_FRAGMENT_TOO_LONG)}};
+ case QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT:
+ return {false,
+ {static_cast<uint64_t>(
+ QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT)}};
case QUIC_LAST_ERROR:
return {false, {static_cast<uint64_t>(QUIC_LAST_ERROR)}};
}
diff --git a/spdy/core/http2_frame_decoder_adapter.cc b/spdy/core/http2_frame_decoder_adapter.cc
index bc2263e..df60047 100644
--- a/spdy/core/http2_frame_decoder_adapter.cc
+++ b/spdy/core/http2_frame_decoder_adapter.cc
@@ -73,9 +73,8 @@
// Overwrites the fields of the header with invalid values, for the purpose
// of identifying reading of unset fields. Only takes effect for debug builds.
// In Address Sanatizer builds, it also marks the fields as un-readable.
-void CorruptFrameHeader(Http2FrameHeader*
#ifndef NDEBUG
- header) {
+void CorruptFrameHeader(Http2FrameHeader* header) {
// Beyond a valid payload length, which is 2^24 - 1.
header->payload_length = 0x1010dead;
// An unsupported frame type.
@@ -86,9 +85,68 @@
// A stream id with the reserved high-bit (R in the RFC) set.
// 2129510127 when the high-bit is cleared.
header->stream_id = 0xfeedbeef;
+}
#else
- /*header*/) {
+void CorruptFrameHeader(Http2FrameHeader* /*header*/) {}
#endif
+
+Http2DecoderAdapter::SpdyFramerError HpackDecodingErrorToSpdyFramerError(
+ HpackDecodingError error) {
+ if (!GetSpdyReloadableFlag(spdy_enable_granular_decompress_errors)) {
+ return Http2DecoderAdapter::SpdyFramerError::SPDY_DECOMPRESS_FAILURE;
+ }
+
+ SPDY_CODE_COUNT(spdy_enable_granular_decompress_errors);
+
+ switch (error) {
+ case HpackDecodingError::kOk:
+ return Http2DecoderAdapter::SpdyFramerError::SPDY_NO_ERROR;
+ case HpackDecodingError::kIndexVarintError:
+ return Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_INDEX_VARINT_ERROR;
+ case HpackDecodingError::kNameLengthVarintError:
+ return Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_NAME_LENGTH_VARINT_ERROR;
+ case HpackDecodingError::kValueLengthVarintError:
+ return Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_VALUE_LENGTH_VARINT_ERROR;
+ case HpackDecodingError::kNameTooLong:
+ return Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_NAME_TOO_LONG;
+ case HpackDecodingError::kValueTooLong:
+ return Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_VALUE_TOO_LONG;
+ case HpackDecodingError::kNameHuffmanError:
+ return Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_NAME_HUFFMAN_ERROR;
+ case HpackDecodingError::kValueHuffmanError:
+ return Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_VALUE_HUFFMAN_ERROR;
+ case HpackDecodingError::kMissingDynamicTableSizeUpdate:
+ return Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE;
+ case HpackDecodingError::kInvalidIndex:
+ return Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_INVALID_INDEX;
+ case HpackDecodingError::kInvalidNameIndex:
+ return Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_INVALID_NAME_INDEX;
+ case HpackDecodingError::kDynamicTableSizeUpdateNotAllowed:
+ return Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED;
+ case HpackDecodingError::kInitialDynamicTableSizeUpdateIsAboveLowWaterMark:
+ return Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_INITIAL_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK;
+ case HpackDecodingError::kDynamicTableSizeUpdateIsAboveAcknowledgedSetting:
+ return Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING;
+ case HpackDecodingError::kTruncatedBlock:
+ return Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_TRUNCATED_BLOCK;
+ case HpackDecodingError::kFragmentTooLong:
+ return Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_FRAGMENT_TOO_LONG;
+ case HpackDecodingError::kCompressedHeaderSizeExceedsLimit:
+ return Http2DecoderAdapter::SpdyFramerError::
+ SPDY_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT;
+ }
+
+ return Http2DecoderAdapter::SpdyFramerError::SPDY_DECOMPRESS_FAILURE;
}
} // namespace
@@ -166,6 +224,38 @@
return "INVALID_CONTROL_FRAME_SIZE";
case SPDY_OVERSIZED_PAYLOAD:
return "OVERSIZED_PAYLOAD";
+ case SPDY_HPACK_INDEX_VARINT_ERROR:
+ return "HPACK_INDEX_VARINT_ERROR";
+ case SPDY_HPACK_NAME_LENGTH_VARINT_ERROR:
+ return "HPACK_NAME_LENGTH_VARINT_ERROR";
+ case SPDY_HPACK_VALUE_LENGTH_VARINT_ERROR:
+ return "HPACK_VALUE_LENGTH_VARINT_ERROR";
+ case SPDY_HPACK_NAME_TOO_LONG:
+ return "HPACK_NAME_TOO_LONG";
+ case SPDY_HPACK_VALUE_TOO_LONG:
+ return "HPACK_VALUE_TOO_LONG";
+ case SPDY_HPACK_NAME_HUFFMAN_ERROR:
+ return "HPACK_NAME_HUFFMAN_ERROR";
+ case SPDY_HPACK_VALUE_HUFFMAN_ERROR:
+ return "HPACK_VALUE_HUFFMAN_ERROR";
+ case SPDY_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE:
+ return "HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE";
+ case SPDY_HPACK_INVALID_INDEX:
+ return "HPACK_INVALID_INDEX";
+ case SPDY_HPACK_INVALID_NAME_INDEX:
+ return "HPACK_INVALID_NAME_INDEX";
+ case SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED:
+ return "HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED";
+ case SPDY_HPACK_INITIAL_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK:
+ return "HPACK_INITIAL_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK";
+ case SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING:
+ return "HPACK_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING";
+ case SPDY_HPACK_TRUNCATED_BLOCK:
+ return "HPACK_TRUNCATED_BLOCK";
+ case SPDY_HPACK_FRAGMENT_TOO_LONG:
+ return "HPACK_FRAGMENT_TOO_LONG";
+ case SPDY_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT:
+ return "HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT";
case LAST_ERROR:
return "UNKNOWN_ERROR";
}
@@ -410,8 +500,10 @@
void Http2DecoderAdapter::OnHpackFragment(const char* data, size_t len) {
SPDY_DVLOG(1) << "OnHpackFragment: len=" << len;
on_hpack_fragment_called_ = true;
- if (!GetHpackDecoder()->HandleControlFrameHeadersData(data, len)) {
- SetSpdyErrorAndNotify(SpdyFramerError::SPDY_DECOMPRESS_FAILURE);
+ auto* decoder = GetHpackDecoder();
+ if (!decoder->HandleControlFrameHeadersData(data, len)) {
+ SetSpdyErrorAndNotify(
+ HpackDecodingErrorToSpdyFramerError(decoder->error()));
return;
}
}
@@ -995,10 +1087,12 @@
frame_type() == Http2FrameType::CONTINUATION)
<< frame_header();
has_expected_frame_type_ = false;
- if (GetHpackDecoder()->HandleControlFrameHeadersComplete(nullptr)) {
+ auto* decoder = GetHpackDecoder();
+ if (decoder->HandleControlFrameHeadersComplete(nullptr)) {
visitor()->OnHeaderFrameEnd(stream_id());
} else {
- SetSpdyErrorAndNotify(SpdyFramerError::SPDY_DECOMPRESS_FAILURE);
+ SetSpdyErrorAndNotify(
+ HpackDecodingErrorToSpdyFramerError(decoder->error()));
return;
}
const Http2FrameHeader& first = frame_type() == Http2FrameType::CONTINUATION
diff --git a/spdy/core/http2_frame_decoder_adapter.h b/spdy/core/http2_frame_decoder_adapter.h
index 2bbb9f1..4a67833 100644
--- a/spdy/core/http2_frame_decoder_adapter.h
+++ b/spdy/core/http2_frame_decoder_adapter.h
@@ -76,6 +76,25 @@
SPDY_INVALID_CONTROL_FRAME_SIZE, // Control frame not sized to spec
SPDY_OVERSIZED_PAYLOAD, // Payload size was too large
+ // HttpDecoder or HttpDecoderAdapter error.
+ // See HpackDecodingError for description of each error code.
+ SPDY_HPACK_INDEX_VARINT_ERROR,
+ SPDY_HPACK_NAME_LENGTH_VARINT_ERROR,
+ SPDY_HPACK_VALUE_LENGTH_VARINT_ERROR,
+ SPDY_HPACK_NAME_TOO_LONG,
+ SPDY_HPACK_VALUE_TOO_LONG,
+ SPDY_HPACK_NAME_HUFFMAN_ERROR,
+ SPDY_HPACK_VALUE_HUFFMAN_ERROR,
+ SPDY_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE,
+ SPDY_HPACK_INVALID_INDEX,
+ SPDY_HPACK_INVALID_NAME_INDEX,
+ SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED,
+ SPDY_HPACK_INITIAL_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK,
+ SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING,
+ SPDY_HPACK_TRUNCATED_BLOCK,
+ SPDY_HPACK_FRAGMENT_TOO_LONG,
+ SPDY_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT,
+
LAST_ERROR, // Must be the last entry in the enum.
};
diff --git a/spdy/platform/api/spdy_flags.h b/spdy/platform/api/spdy_flags.h
index dc95427..7d9345e 100644
--- a/spdy/platform/api/spdy_flags.h
+++ b/spdy/platform/api/spdy_flags.h
@@ -10,6 +10,7 @@
#define GetSpdyReloadableFlag(flag) GetSpdyReloadableFlagImpl(flag)
#define GetSpdyRestartFlag(flag) GetSpdyRestartFlagImpl(flag)
+#define SPDY_CODE_COUNT SPDY_CODE_COUNT_IMPL
#define SPDY_CODE_COUNT_N SPDY_CODE_COUNT_N_IMPL
#endif // QUICHE_SPDY_PLATFORM_API_SPDY_FLAGS_H_