gfe-relnote: Add stream creating error codes. Protected by gfe2_reloadable_flag_quic_enable_version_draft_25_v3 and gfe2_reloadable_flag_quic_enable_version_draft_27.
PiperOrigin-RevId: 300663069
Change-Id: I4828df1f984e94ed35fa63660f7d399100eef9da
diff --git a/quic/core/http/quic_server_session_base_test.cc b/quic/core/http/quic_server_session_base_test.cc
index ee5e8dc..98cdf49 100644
--- a/quic/core/http/quic_server_session_base_test.cc
+++ b/quic/core/http/quic_server_session_base_test.cc
@@ -438,7 +438,11 @@
TEST_P(QuicServerSessionBaseTest, GetEvenIncomingError) {
// Incoming streams on the server session must be odd.
- EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _));
+ const QuicErrorCode expected_error =
+ VersionHasIetfQuicFrames(transport_version())
+ ? QUIC_HTTP_STREAM_WRONG_DIRECTION
+ : QUIC_INVALID_STREAM_ID;
+ EXPECT_CALL(*connection_, CloseConnection(expected_error, _, _));
EXPECT_EQ(nullptr, QuicServerSessionBasePeer::GetOrCreateStream(
session_.get(),
session_->next_outgoing_unidirectional_stream_id()));
diff --git a/quic/core/http/quic_spdy_client_session.cc b/quic/core/http/quic_spdy_client_session.cc
index 70f79e9..b7130c3 100644
--- a/quic/core/http/quic_spdy_client_session.cc
+++ b/quic/core/http/quic_spdy_client_session.cc
@@ -135,9 +135,8 @@
<< "Already received goaway.";
return false;
}
- if (QuicUtils::IsClientInitiatedStreamId(transport_version(), id) ||
- (VersionHasIetfQuicFrames(transport_version()) &&
- QuicUtils::IsBidirectionalStreamId(id))) {
+
+ if (QuicUtils::IsClientInitiatedStreamId(transport_version(), id)) {
QUIC_LOG(WARNING) << "Received invalid push stream id " << id;
connection()->CloseConnection(
QUIC_INVALID_STREAM_ID,
@@ -145,6 +144,16 @@
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return false;
}
+
+ if (VersionHasIetfQuicFrames(transport_version()) &&
+ QuicUtils::IsBidirectionalStreamId(id)) {
+ connection()->CloseConnection(
+ QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM,
+ "Server created bidirectional stream.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+
return true;
}
diff --git a/quic/core/http/quic_spdy_client_session_test.cc b/quic/core/http/quic_spdy_client_session_test.cc
index 06912c3..15a9736 100644
--- a/quic/core/http/quic_spdy_client_session_test.cc
+++ b/quic/core/http/quic_spdy_client_session_test.cc
@@ -895,7 +895,9 @@
TEST_P(QuicSpdyClientSessionTest,
TryToCreateServerInitiatedBidirectionalStream) {
if (VersionHasIetfQuicFrames(connection_->transport_version())) {
- EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _));
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM, _, _));
} else {
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
}
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index c8d28c1..f211046 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -1186,9 +1186,8 @@
quiche::QuicheStringPiece type) {
QUIC_PEER_BUG << quiche::QuicheStrCat("Received a duplicate ", type,
" stream: Closing connection.");
- // TODO(b/124216424): Change to HTTP_STREAM_CREATION_ERROR.
CloseConnectionWithDetails(
- QUIC_INVALID_STREAM_ID,
+ QUIC_HTTP_DUPLICATE_UNIDIRECTIONAL_STREAM,
quiche::QuicheStrCat(type, " stream is received twice."));
}
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 635b3c3..0412a76 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -2698,7 +2698,7 @@
QuicStreamFrame data2(id2, false, 0, quiche::QuicheStringPiece(type1, 1));
EXPECT_CALL(debug_visitor, OnPeerControlStreamCreated(id2)).Times(0);
EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_STREAM_ID,
+ CloseConnection(QUIC_HTTP_DUPLICATE_UNIDIRECTIONAL_STREAM,
"Control stream is received twice.", _));
EXPECT_QUIC_PEER_BUG(
session_.OnStreamFrame(data2),
@@ -2717,7 +2717,7 @@
QuicStreamFrame data4(id4, false, 0, quiche::QuicheStringPiece(type2, 1));
EXPECT_CALL(debug_visitor, OnPeerQpackEncoderStreamCreated(id4)).Times(0);
EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_STREAM_ID,
+ CloseConnection(QUIC_HTTP_DUPLICATE_UNIDIRECTIONAL_STREAM,
"QPACK encoder stream is received twice.", _));
EXPECT_QUIC_PEER_BUG(
session_.OnStreamFrame(data4),
@@ -2736,7 +2736,7 @@
QuicStreamFrame data6(id6, false, 0, quiche::QuicheStringPiece(type3, 1));
EXPECT_CALL(debug_visitor, OnPeerQpackDecoderStreamCreated(id6)).Times(0);
EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_STREAM_ID,
+ CloseConnection(QUIC_HTTP_DUPLICATE_UNIDIRECTIONAL_STREAM,
"QPACK decoder stream is received twice.", _));
EXPECT_QUIC_PEER_BUG(
session_.OnStreamFrame(data6),
diff --git a/quic/core/quic_error_codes.cc b/quic/core/quic_error_codes.cc
index e16da69..e24e839 100644
--- a/quic/core/quic_error_codes.cc
+++ b/quic/core/quic_error_codes.cc
@@ -171,6 +171,9 @@
RETURN_STRING_LITERAL(QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM);
RETURN_STRING_LITERAL(QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_SPDY_STREAM);
RETURN_STRING_LITERAL(QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_CONTROL_STREAM);
+ RETURN_STRING_LITERAL(QUIC_HTTP_DUPLICATE_UNIDIRECTIONAL_STREAM);
+ RETURN_STRING_LITERAL(QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM);
+ RETURN_STRING_LITERAL(QUIC_HTTP_STREAM_WRONG_DIRECTION);
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);
diff --git a/quic/core/quic_error_codes.h b/quic/core/quic_error_codes.h
index 557edfa..3ef34a5 100644
--- a/quic/core/quic_error_codes.h
+++ b/quic/core/quic_error_codes.h
@@ -366,6 +366,13 @@
// An invalid sequence of frames normally allowed on the control stream is
// received.
QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_CONTROL_STREAM = 152,
+ // A second instance of a unidirectional stream of a certain type is created.
+ QUIC_HTTP_DUPLICATE_UNIDIRECTIONAL_STREAM = 153,
+ // Client receives a server-initiated bidirectional stream.
+ QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM = 154,
+ // Server opens stream with stream ID corresponding to client-initiated
+ // stream or vice versa.
+ QUIC_HTTP_STREAM_WRONG_DIRECTION = 155,
// HPACK header block decoding errors.
// Index varint beyond implementation limit.
@@ -402,7 +409,7 @@
QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT = 150,
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 153,
+ QUIC_LAST_ERROR = 156,
};
// 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_session.cc b/quic/core/quic_session.cc
index ad16ce3..44561e1 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -1182,6 +1182,12 @@
DCHECK(!IsClosedStream(stream_id));
// Received a frame for a locally-created stream that is not currently
// active. This is an error.
+ if (VersionHasIetfQuicFrames(transport_version())) {
+ connection()->CloseConnection(
+ QUIC_HTTP_STREAM_WRONG_DIRECTION, "Data for nonexistent stream",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
connection()->CloseConnection(
QUIC_INVALID_STREAM_ID, "Data for nonexistent stream",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc
index 2daef86..427f7a1 100644
--- a/quic/core/quic_session_test.cc
+++ b/quic/core/quic_session_test.cc
@@ -2055,6 +2055,22 @@
QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(&session_).size());
}
+TEST_P(QuicSessionTestClient, IncomingStreamWithClientInitiatedStreamId) {
+ const QuicErrorCode expected_error =
+ VersionHasIetfQuicFrames(transport_version())
+ ? QUIC_HTTP_STREAM_WRONG_DIRECTION
+ : QUIC_INVALID_STREAM_ID;
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(expected_error, "Data for nonexistent stream",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET));
+
+ QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(1),
+ /* fin = */ false, /* offset = */ 0,
+ quiche::QuicheStringPiece("foo"));
+ session_.OnStreamFrame(frame);
+}
+
TEST_P(QuicSessionTestServer, ZombieStreams) {
TestStream* stream2 = session_.CreateOutgoingBidirectionalStream();
QuicStreamPeer::SetStreamBytesWritten(3, stream2);
@@ -2704,7 +2720,7 @@
QuicStopSendingFrame frame(1, GetNthServerInitiatedBidirectionalId(123456),
123);
- EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID,
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_STREAM_WRONG_DIRECTION,
"Data for nonexistent stream", _))
.Times(1);
session_.OnStopSendingFrame(frame);
@@ -2833,6 +2849,22 @@
/*set_alternative_decrypter=*/false, /*latch_once_used=*/false));
}
+TEST_P(QuicSessionTestServer, IncomingStreamWithServerInitiatedStreamId) {
+ const QuicErrorCode expected_error =
+ VersionHasIetfQuicFrames(transport_version())
+ ? QUIC_HTTP_STREAM_WRONG_DIRECTION
+ : QUIC_INVALID_STREAM_ID;
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(expected_error, "Data for nonexistent stream",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET));
+
+ QuicStreamFrame frame(GetNthServerInitiatedBidirectionalId(1),
+ /* fin = */ false, /* offset = */ 0,
+ quiche::QuicheStringPiece("foo"));
+ session_.OnStreamFrame(frame);
+}
+
// A client test class that can be used when the automatic configuration is not
// desired.
class QuicSessionTestClientUnconfigured : public QuicSessionTestBase {
diff --git a/quic/core/quic_types.cc b/quic/core/quic_types.cc
index d1e76be..5198eec 100644
--- a/quic/core/quic_types.cc
+++ b/quic/core/quic_types.cc
@@ -479,6 +479,16 @@
return {false,
{static_cast<uint64_t>(
QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_UNEXPECTED)}};
+ case QUIC_HTTP_DUPLICATE_UNIDIRECTIONAL_STREAM:
+ return {false,
+ {static_cast<uint64_t>(
+ QuicHttp3ErrorCode::IETF_QUIC_HTTP3_STREAM_CREATION_ERROR)}};
+ case QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM:
+ return {false,
+ {static_cast<uint64_t>(
+ QuicHttp3ErrorCode::IETF_QUIC_HTTP3_STREAM_CREATION_ERROR)}};
+ case QUIC_HTTP_STREAM_WRONG_DIRECTION:
+ return {true, {static_cast<uint64_t>(STREAM_STATE_ERROR)}};
case QUIC_HPACK_INDEX_VARINT_ERROR:
return {false, {static_cast<uint64_t>(QUIC_HPACK_INDEX_VARINT_ERROR)}};
case QUIC_HPACK_NAME_LENGTH_VARINT_ERROR:
diff --git a/quic/tools/quic_simple_server_session_test.cc b/quic/tools/quic_simple_server_session_test.cc
index 250f3ca..d82bd08 100644
--- a/quic/tools/quic_simple_server_session_test.cc
+++ b/quic/tools/quic_simple_server_session_test.cc
@@ -564,7 +564,10 @@
TEST_P(QuicSimpleServerSessionTest, GetEvenIncomingError) {
// Tests that calling GetOrCreateStream() on an outgoing stream not
// promised yet should result close connection.
- EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID,
+ const QuicErrorCode expected_error = VersionUsesHttp3(transport_version())
+ ? QUIC_HTTP_STREAM_WRONG_DIRECTION
+ : QUIC_INVALID_STREAM_ID;
+ EXPECT_CALL(*connection_, CloseConnection(expected_error,
"Data for nonexistent stream", _));
EXPECT_EQ(nullptr,
QuicSessionPeer::GetOrCreateStream(