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_