Add HTTP/3 error codes, use them in HttpDecoder and for unexpected frames in QuicSpdyStream and QuicReceiveControlStream. ENUM_VALUE_OK=Only changing value of sentinel entry QUIC_LAST_ERROR. gfe-relnote: n/a, change to QUIC v99-only code. Protected by existing disabled gfe2_reloadable_flag_quic_enable_version_99. PiperOrigin-RevId: 290374408 Change-Id: I90837f021f0dd585f8015d2fcae37d0d0eacfed6
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc index f8a73f4..c5aa08c 100644 --- a/quic/core/http/http_decoder.cc +++ b/quic/core/http/http_decoder.cc
@@ -128,8 +128,7 @@ } if (current_frame_length_ > MaxFrameLength(current_frame_type_)) { - // TODO(b/124216424): Use HTTP_EXCESSIVE_LOAD. - RaiseError(QUIC_INVALID_FRAME_DATA, "Frame is too large"); + RaiseError(QUIC_HTTP_FRAME_TOO_LARGE, "Frame is too large."); return false; } @@ -155,7 +154,8 @@ // This edge case needs to be handled here, because ReadFramePayload() // does not get called if |current_frame_length_| is zero. if (current_frame_length_ == 0) { - RaiseError(QUIC_INVALID_FRAME_DATA, "Corrupt PUSH_PROMISE frame."); + RaiseError(QUIC_HTTP_FRAME_ERROR, + "PUSH_PROMISE frame with empty payload."); return false; } continue_processing = visitor_->OnPushPromiseFrameStart(header_length); @@ -225,7 +225,8 @@ DCHECK_EQ(0u, current_push_id_length_); current_push_id_length_ = reader->PeekVarInt62Length(); if (current_push_id_length_ > remaining_frame_length_) { - RaiseError(QUIC_INVALID_FRAME_DATA, "PUSH_PROMISE frame malformed."); + RaiseError(QUIC_HTTP_FRAME_ERROR, + "Unable to read PUSH_PROMISE push_id."); return false; } if (current_push_id_length_ > reader->BytesRemaining()) { @@ -336,12 +337,12 @@ CancelPushFrame frame; QuicDataReader reader(buffer_.data(), current_frame_length_); if (!reader.ReadVarInt62(&frame.push_id)) { - // TODO(b/124216424): Use HTTP_MALFORMED_FRAME. - RaiseError(QUIC_INVALID_FRAME_DATA, "Unable to read push_id"); + RaiseError(QUIC_HTTP_FRAME_ERROR, + "Unable to read CANCEL_PUSH push_id."); return false; } if (!reader.IsDoneReading()) { - RaiseError(QUIC_INVALID_FRAME_DATA, + RaiseError(QUIC_HTTP_FRAME_ERROR, "Superfluous data in CANCEL_PUSH frame."); return false; } @@ -370,13 +371,11 @@ "QuicStreamId from uint32_t to uint64_t."); uint64_t stream_id; if (!reader.ReadVarInt62(&stream_id)) { - // TODO(b/124216424): Use HTTP_MALFORMED_FRAME. - RaiseError(QUIC_INVALID_FRAME_DATA, "Unable to read GOAWAY stream_id"); + RaiseError(QUIC_HTTP_FRAME_ERROR, "Unable to read GOAWAY stream_id."); return false; } if (!reader.IsDoneReading()) { - RaiseError(QUIC_INVALID_FRAME_DATA, - "Superfluous data in GOAWAY frame."); + RaiseError(QUIC_HTTP_FRAME_ERROR, "Superfluous data in GOAWAY frame."); return false; } frame.stream_id = static_cast<QuicStreamId>(stream_id); @@ -387,12 +386,12 @@ QuicDataReader reader(buffer_.data(), current_frame_length_); MaxPushIdFrame frame; if (!reader.ReadVarInt62(&frame.push_id)) { - // TODO(b/124216424): Use HTTP_MALFORMED_FRAME. - RaiseError(QUIC_INVALID_FRAME_DATA, "Unable to read push_id"); + RaiseError(QUIC_HTTP_FRAME_ERROR, + "Unable to read MAX_PUSH_ID push_id."); return false; } if (!reader.IsDoneReading()) { - RaiseError(QUIC_INVALID_FRAME_DATA, + RaiseError(QUIC_HTTP_FRAME_ERROR, "Superfluous data in MAX_PUSH_ID frame."); return false; } @@ -403,12 +402,12 @@ QuicDataReader reader(buffer_.data(), current_frame_length_); DuplicatePushFrame frame; if (!reader.ReadVarInt62(&frame.push_id)) { - // TODO(b/124216424): Use HTTP_MALFORMED_FRAME. - RaiseError(QUIC_INVALID_FRAME_DATA, "Unable to read push_id"); + RaiseError(QUIC_HTTP_FRAME_ERROR, + "Unable to read DUPLICATE_PUSH push_id."); return false; } if (!reader.IsDoneReading()) { - RaiseError(QUIC_INVALID_FRAME_DATA, + RaiseError(QUIC_HTTP_FRAME_ERROR, "Superfluous data in DUPLICATE_PUSH frame."); return false; } @@ -513,22 +512,17 @@ while (!reader->IsDoneReading()) { uint64_t id; if (!reader->ReadVarInt62(&id)) { - // TODO(b/124216424): Use HTTP_MALFORMED_FRAME. - RaiseError(QUIC_INVALID_FRAME_DATA, - "Unable to read settings frame identifier"); + RaiseError(QUIC_HTTP_FRAME_ERROR, "Unable to read setting identifier."); return false; } uint64_t content; if (!reader->ReadVarInt62(&content)) { - // TODO(b/124216424): Use HTTP_MALFORMED_FRAME. - RaiseError(QUIC_INVALID_FRAME_DATA, - "Unable to read settings frame content"); + RaiseError(QUIC_HTTP_FRAME_ERROR, "Unable to read setting value."); return false; } auto result = frame->values.insert({id, content}); if (!result.second) { - // TODO(b/124216424): Use HTTP_SETTINGS_ERROR. - RaiseError(QUIC_INVALID_FRAME_DATA, "Duplicate SETTINGS identifier."); + RaiseError(QUIC_HTTP_FRAME_ERROR, "Duplicate setting identifier."); return false; } } @@ -539,16 +533,14 @@ PriorityUpdateFrame* frame) { uint8_t prioritized_element_type; if (!reader->ReadUInt8(&prioritized_element_type)) { - // TODO(b/124216424): Use HTTP_MALFORMED_FRAME. - RaiseError(QUIC_INVALID_FRAME_DATA, + RaiseError(QUIC_HTTP_FRAME_ERROR, "Unable to read prioritized element type."); return false; } if (prioritized_element_type != REQUEST_STREAM && prioritized_element_type != PUSH_STREAM) { - // TODO(b/124216424): Use HTTP_MALFORMED_FRAME. - RaiseError(QUIC_INVALID_FRAME_DATA, "Invalid prioritized element type."); + RaiseError(QUIC_HTTP_FRAME_ERROR, "Invalid prioritized element type."); return false; } @@ -556,9 +548,7 @@ static_cast<PrioritizedElementType>(prioritized_element_type); if (!reader->ReadVarInt62(&frame->prioritized_element_id)) { - // TODO(b/124216424): Use HTTP_MALFORMED_FRAME. - RaiseError(QUIC_INVALID_FRAME_DATA, - "Unable to read prioritized element id."); + RaiseError(QUIC_HTTP_FRAME_ERROR, "Unable to read prioritized element id."); return false; }
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc index 3a67395..7cd0853 100644 --- a/quic/core/http/http_decoder_test.cc +++ b/quic/core/http/http_decoder_test.cc
@@ -303,8 +303,8 @@ decoder.ProcessInput(input.data(), input.size()); - EXPECT_THAT(decoder.error(), IsError(QUIC_INVALID_FRAME_DATA)); - EXPECT_EQ("PUSH_PROMISE frame malformed.", decoder.error_detail()); + EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ("Unable to read PUSH_PROMISE push_id.", decoder.error_detail()); } { HttpDecoder decoder(&visitor_); @@ -315,8 +315,8 @@ decoder.ProcessInput(&c, 1); } - EXPECT_THAT(decoder.error(), IsError(QUIC_INVALID_FRAME_DATA)); - EXPECT_EQ("PUSH_PROMISE frame malformed.", decoder.error_detail()); + EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ("Unable to read PUSH_PROMISE push_id.", decoder.error_detail()); } } @@ -430,10 +430,10 @@ size_t payload_length; const char* const error_message; } kTestData[] = { - {1, "Unable to read settings frame identifier"}, - {5, "Unable to read settings frame content"}, - {7, "Unable to read settings frame identifier"}, - {12, "Unable to read settings frame content"}, + {1, "Unable to read setting identifier."}, + {5, "Unable to read setting value."}, + {7, "Unable to read setting identifier."}, + {12, "Unable to read setting value."}, }; for (const auto& test_data : kTestData) { @@ -450,7 +450,7 @@ QuicByteCount processed_bytes = decoder.ProcessInput(input.data(), input.size()); EXPECT_EQ(input.size(), processed_bytes); - EXPECT_THAT(decoder.error(), IsError(QUIC_INVALID_FRAME_DATA)); + EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR)); EXPECT_EQ(test_data.error_message, decoder.error_detail()); } } @@ -469,8 +469,8 @@ EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); - EXPECT_EQ("Duplicate SETTINGS identifier.", decoder_.error_detail()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ("Duplicate setting identifier.", decoder_.error_detail()); } TEST_F(HttpDecoderTest, DataFrame) { @@ -753,8 +753,8 @@ // Process the full frame. EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(2u, ProcessInput(input)); - EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); - EXPECT_EQ("Frame is too large", decoder_.error_detail()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_TOO_LARGE)); + EXPECT_EQ("Frame is too large.", decoder_.error_detail()); } TEST_F(HttpDecoderTest, MalformedSettingsFrame) { @@ -768,8 +768,8 @@ writer.WriteStringPiece("Malformed payload"); EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(5u, decoder_.ProcessInput(input, QUICHE_ARRAYSIZE(input))); - EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); - EXPECT_EQ("Frame is too large", decoder_.error_detail()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_TOO_LARGE)); + EXPECT_EQ("Frame is too large.", decoder_.error_detail()); } TEST_F(HttpDecoderTest, HeadersPausedThenData) { @@ -814,7 +814,7 @@ } kTestData[] = {{"\x03" // type (CANCEL_PUSH) "\x01" // length "\x40", // first byte of two-byte varint push id - "Unable to read push_id"}, + "Unable to read CANCEL_PUSH push_id."}, {"\x03" // type (CANCEL_PUSH) "\x04" // length "\x05" // valid push id @@ -823,7 +823,7 @@ {"\x0D" // type (MAX_PUSH_ID) "\x01" // length "\x40", // first byte of two-byte varint push id - "Unable to read push_id"}, + "Unable to read MAX_PUSH_ID push_id."}, {"\x0D" // type (MAX_PUSH_ID) "\x04" // length "\x05" // valid push id @@ -832,7 +832,7 @@ {"\x0E" // type (DUPLICATE_PUSH) "\x01" // length "\x40", // first byte of two-byte varint push id - "Unable to read push_id"}, + "Unable to read DUPLICATE_PUSH push_id."}, {"\x0E" // type (DUPLICATE_PUSH) "\x04" // length "\x05" // valid push id @@ -841,7 +841,7 @@ {"\x07" // type (GOAWAY) "\x01" // length "\x40", // first byte of two-byte varint stream id - "Unable to read GOAWAY stream_id"}, + "Unable to read GOAWAY stream_id."}, {"\x07" // type (GOAWAY) "\x04" // length "\x05" // valid stream id @@ -855,7 +855,7 @@ quiche::QuicheStringPiece input(test_data.input); decoder.ProcessInput(input.data(), input.size()); - EXPECT_THAT(decoder.error(), IsError(QUIC_INVALID_FRAME_DATA)); + EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR)); EXPECT_EQ(test_data.error_message, decoder.error_detail()); } { @@ -866,7 +866,7 @@ for (auto c : input) { decoder.ProcessInput(&c, 1); } - EXPECT_THAT(decoder.error(), IsError(QUIC_INVALID_FRAME_DATA)); + EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR)); EXPECT_EQ(test_data.error_message, decoder.error_detail()); } } @@ -879,8 +879,8 @@ EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); - EXPECT_EQ("Unable to read push_id", decoder_.error_detail()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ("Unable to read CANCEL_PUSH push_id.", decoder_.error_detail()); } TEST_F(HttpDecoderTest, EmptySettingsFrame) { @@ -906,8 +906,8 @@ EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); - EXPECT_EQ("Corrupt PUSH_PROMISE frame.", decoder_.error_detail()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ("PUSH_PROMISE frame with empty payload.", decoder_.error_detail()); } TEST_F(HttpDecoderTest, EmptyGoAwayFrame) { @@ -917,8 +917,8 @@ EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); - EXPECT_EQ("Unable to read GOAWAY stream_id", decoder_.error_detail()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ("Unable to read GOAWAY stream_id.", decoder_.error_detail()); } TEST_F(HttpDecoderTest, EmptyMaxPushIdFrame) { @@ -928,8 +928,8 @@ EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); - EXPECT_EQ("Unable to read push_id", decoder_.error_detail()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ("Unable to read MAX_PUSH_ID push_id.", decoder_.error_detail()); } TEST_F(HttpDecoderTest, EmptyDuplicatePushFrame) { @@ -939,8 +939,8 @@ EXPECT_CALL(visitor_, OnError(&decoder_)); EXPECT_EQ(input.size(), ProcessInput(input)); - EXPECT_THAT(decoder_.error(), IsError(QUIC_INVALID_FRAME_DATA)); - EXPECT_EQ("Unable to read push_id", decoder_.error_detail()); + EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ("Unable to read DUPLICATE_PUSH push_id.", decoder_.error_detail()); } TEST_F(HttpDecoderTest, LargeStreamIdInGoAway) { @@ -1068,7 +1068,7 @@ QuicByteCount processed_bytes = decoder.ProcessInput(input.data(), input.size()); EXPECT_EQ(input.size(), processed_bytes); - EXPECT_THAT(decoder.error(), IsError(QUIC_INVALID_FRAME_DATA)); + EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR)); EXPECT_EQ(test_data.error_message, decoder.error_detail()); } }
diff --git a/quic/core/http/quic_receive_control_stream.cc b/quic/core/http/quic_receive_control_stream.cc index 283b54e..f07e900 100644 --- a/quic/core/http/quic_receive_control_stream.cc +++ b/quic/core/http/quic_receive_control_stream.cc
@@ -24,9 +24,9 @@ HttpDecoderVisitor(const HttpDecoderVisitor&) = delete; HttpDecoderVisitor& operator=(const HttpDecoderVisitor&) = delete; - void OnError(HttpDecoder* /*decoder*/) override { + void OnError(HttpDecoder* decoder) override { stream_->session()->connection()->CloseConnection( - QUIC_HTTP_DECODER_ERROR, "Http decoder internal error", + decoder->error(), decoder->error_detail(), ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); } @@ -150,9 +150,8 @@ private: void CloseConnectionOnWrongFrame(quiche::QuicheStringPiece frame_type) { - // TODO(renjietang): Change to HTTP/3 error type. stream_->session()->connection()->CloseConnection( - QUIC_HTTP_DECODER_ERROR, + QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM, quiche::QuicheStrCat(frame_type, " frame received on control stream"), ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); }
diff --git a/quic/core/http/quic_receive_control_stream_test.cc b/quic/core/http/quic_receive_control_stream_test.cc index b603efc..c669f85 100644 --- a/quic/core/http/quic_receive_control_stream_test.cc +++ b/quic/core/http/quic_receive_control_stream_test.cc
@@ -214,7 +214,9 @@ std::string data = std::string(buffer.get(), header_length); QuicStreamFrame frame(receive_control_stream_->id(), false, 1, data); - EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_DECODER_ERROR, _, _)); + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM, _, _)); receive_control_stream_->OnStreamFrame(frame); } @@ -231,7 +233,9 @@ EXPECT_FALSE(session_.http3_goaway_received()); if (perspective() == Perspective::IS_SERVER) { - EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_DECODER_ERROR, _, _)); + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM, _, _)); } receive_control_stream_->OnStreamFrame(frame); @@ -249,8 +253,9 @@ push_promise, &buffer); QuicStreamFrame frame(receive_control_stream_->id(), false, 1, buffer.get(), length); - // TODO(lassey) Check for HTTP_WRONG_STREAM error code. - EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_DECODER_ERROR, _, _)) + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM, _, _)) .WillOnce( Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _));
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc index 195f92b..5d5c176 100644 --- a/quic/core/http/quic_spdy_stream.cc +++ b/quic/core/http/quic_spdy_stream.cc
@@ -40,9 +40,9 @@ HttpDecoderVisitor(const HttpDecoderVisitor&) = delete; HttpDecoderVisitor& operator=(const HttpDecoderVisitor&) = delete; - void OnError(HttpDecoder* /*decoder*/) override { + void OnError(HttpDecoder* decoder) override { stream_->session()->connection()->CloseConnection( - QUIC_HTTP_DECODER_ERROR, "Http decoder internal error", + decoder->error(), decoder->error_detail(), ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); } @@ -171,7 +171,7 @@ private: void CloseConnectionOnWrongFrame(quiche::QuicheStringPiece frame_type) { stream_->session()->connection()->CloseConnection( - QUIC_HTTP_DECODER_ERROR, + QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM, quiche::QuicheStrCat(frame_type, " frame received on data stream"), ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); }
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc index 164b119..8616ab7 100644 --- a/quic/core/http/quic_spdy_stream_test.cc +++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -497,7 +497,8 @@ QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0, quiche::QuicheStringPiece(data)); - EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_DECODER_ERROR, _, _)) + EXPECT_CALL(*connection_, + CloseConnection(QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM, _, _)) .WillOnce( (Invoke([this](QuicErrorCode error, const std::string& error_details, ConnectionCloseBehavior connection_close_behavior) { @@ -516,6 +517,39 @@ stream_->OnStreamFrame(frame); } +TEST_P(QuicSpdyStreamTest, Http3FrameError) { + if (!UsesHttp3()) { + return; + } + + Initialize(kShouldProcessData); + + // PUSH_PROMISE frame with empty payload is considered invalid. + std::string invalid_http3_frame = quiche::QuicheTextUtils::HexDecode("0500"); + QuicStreamFrame stream_frame(stream_->id(), /* fin = */ false, + /* offset = */ 0, invalid_http3_frame); + + EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_FRAME_ERROR, _, _)); + stream_->OnStreamFrame(stream_frame); +} + +TEST_P(QuicSpdyStreamTest, UnexpectedHttp3Frame) { + if (!UsesHttp3()) { + return; + } + + Initialize(kShouldProcessData); + + // SETTINGS frame with empty payload. + std::string settings = quiche::QuicheTextUtils::HexDecode("0400"); + QuicStreamFrame stream_frame(stream_->id(), /* fin = */ false, + /* offset = */ 0, settings); + + EXPECT_CALL(*connection_, + CloseConnection(QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM, _, _)); + stream_->OnStreamFrame(stream_frame); +} + TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBody) { Initialize(kShouldProcessData); @@ -2553,7 +2587,8 @@ EXPECT_EQ(0u, stream_->sequencer()->NumBytesConsumed()); - EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_DECODER_ERROR, _, _)) + EXPECT_CALL(*connection_, + CloseConnection(QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM, _, _)) .WillOnce( Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _));
diff --git a/quic/core/quic_error_codes.cc b/quic/core/quic_error_codes.cc index ae17f09..7aa0dff 100644 --- a/quic/core/quic_error_codes.cc +++ b/quic/core/quic_error_codes.cc
@@ -165,6 +165,10 @@ RETURN_STRING_LITERAL(QUIC_QPACK_DECODER_STREAM_ERROR); RETURN_STRING_LITERAL(QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET); RETURN_STRING_LITERAL(QUIC_STREAM_MULTIPLE_OFFSET); + RETURN_STRING_LITERAL(QUIC_HTTP_FRAME_TOO_LARGE); + 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_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 b6c2d50..9a08844 100644 --- a/quic/core/quic_error_codes.h +++ b/quic/core/quic_error_codes.h
@@ -353,8 +353,14 @@ // Received multiple close offset. QUIC_STREAM_MULTIPLE_OFFSET = 130, + // Internal error codes for HTTP/3 errors. + QUIC_HTTP_FRAME_TOO_LARGE = 131, + QUIC_HTTP_FRAME_ERROR = 132, + QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM = 133, + QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM = 134, + // No error. Used as bound while iterating. - QUIC_LAST_ERROR = 131, + QUIC_LAST_ERROR = 135, }; // 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 @@ -370,6 +376,27 @@ // Returns the name of the QuicErrorCode as a char* QUIC_EXPORT_PRIVATE const char* QuicErrorCodeToString(QuicErrorCode error); +// Wire values for HTTP/3 errors. +// https://quicwg.org/base-drafts/draft-ietf-quic-http.html#http-error-codes +enum class QuicHttp3ErrorCode { + IETF_QUIC_HTTP3_NO_ERROR = 0x100, + IETF_QUIC_HTTP3_GENERAL_PROTOCOL_ERROR = 0x101, + IETF_QUIC_HTTP3_INTERNAL_ERROR = 0x102, + IETF_QUIC_HTTP3_STREAM_CREATION_ERROR = 0x103, + IETF_QUIC_HTTP3_CLOSED_CRITICAL_STREAM = 0x104, + IETF_QUIC_HTTP3_FRAME_UNEXPECTED = 0x105, + IETF_QUIC_HTTP3_FRAME_ERROR = 0x106, + IETF_QUIC_HTTP3_EXCESSIVE_LOAD = 0x107, + IETF_QUIC_HTTP3_ID_ERROR = 0x108, + IETF_QUIC_HTTP3_SETTINGS_ERROR = 0x109, + IETF_QUIC_HTTP3_MISSING_SETTINGS = 0x10A, + IETF_QUIC_HTTP3_REQUEST_REJECTED = 0x10B, + IETF_QUIC_HTTP3_REQUEST_CANCELLED = 0x10C, + IETF_QUIC_HTTP3_REQUEST_INCOMPLETE = 0x10D, + IETF_QUIC_HTTP3_CONNECT_ERROR = 0x10F, + IETF_QUIC_HTTP3_VERSION_FALLBACK = 0x110, +}; + // Wire values for QPACK errors. // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#error-code-registration enum QuicHttpQpackErrorCode {
diff --git a/quic/core/quic_types.cc b/quic/core/quic_types.cc index 709f89a..351cd10 100644 --- a/quic/core/quic_types.cc +++ b/quic/core/quic_types.cc
@@ -425,6 +425,22 @@ {static_cast<uint64_t>(QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET)}}; case QUIC_STREAM_MULTIPLE_OFFSET: return {true, {static_cast<uint64_t>(QUIC_STREAM_MULTIPLE_OFFSET)}}; + case QUIC_HTTP_FRAME_TOO_LARGE: + return {false, + {static_cast<uint64_t>( + QuicHttp3ErrorCode::IETF_QUIC_HTTP3_EXCESSIVE_LOAD)}}; + case QUIC_HTTP_FRAME_ERROR: + return {false, + {static_cast<uint64_t>( + QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_ERROR)}}; + case QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM: + return {false, + {static_cast<uint64_t>( + QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_UNEXPECTED)}}; + case QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM: + return {false, + {static_cast<uint64_t>( + QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_UNEXPECTED)}}; case QUIC_LAST_ERROR: return {false, {static_cast<uint64_t>(QUIC_LAST_ERROR)}}; }