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)}};
}