Close connection on QPACK encoder or decoder stream errors.

gfe-relnote: n/a, change to QUIC v99-only code.  Protected by existing disabled gfe2_reloadable_flag_quic_enable_version_99.
PiperOrigin-RevId: 268434745
Change-Id: Ie69e360cacd7b431373fddf1e5221304ec522000
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index 53ec3cc..a2bb509 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -402,18 +402,22 @@
       2 * max_inbound_header_list_size_);
 }
 
-void QuicSpdySession::OnDecoderStreamError(QuicStringPiece /*error_message*/) {
+void QuicSpdySession::OnDecoderStreamError(QuicStringPiece error_message) {
   DCHECK(VersionUsesQpack(transport_version()));
 
-  // TODO(112770235): Signal connection error on decoder stream errors.
-  QUIC_NOTREACHED();
+  // TODO(b/124216424): Use HTTP_QPACK_DECODER_STREAM_ERROR.
+  CloseConnectionWithDetails(
+      QUIC_DECOMPRESSION_FAILURE,
+      QuicStrCat("Decoder stream error: ", error_message));
 }
 
-void QuicSpdySession::OnEncoderStreamError(QuicStringPiece /*error_message*/) {
+void QuicSpdySession::OnEncoderStreamError(QuicStringPiece error_message) {
   DCHECK(VersionUsesQpack(transport_version()));
 
-  // TODO(112770235): Signal connection error on encoder stream errors.
-  QUIC_NOTREACHED();
+  // TODO(b/124216424): Use HTTP_QPACK_ENCODER_STREAM_ERROR.
+  CloseConnectionWithDetails(
+      QUIC_DECOMPRESSION_FAILURE,
+      QuicStrCat("Encoder stream error: ", error_message));
 }
 
 void QuicSpdySession::OnStreamHeadersPriority(
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index e5d50b2..f5bab97 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -2473,6 +2473,48 @@
       "Received a duplicate QPACK decoder stream: Closing connection.");
 }
 
+TEST_P(QuicSpdySessionTestClient, EncoderStreamError) {
+  if (!VersionUsesQpack(transport_version())) {
+    return;
+  }
+
+  std::string data = QuicTextUtils::HexDecode(
+      "02"    // Encoder stream.
+      "00");  // Duplicate entry 0, but no entries exist.
+
+  QuicStreamId stream_id =
+      GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
+
+  QuicStreamFrame frame(stream_id, /* fin = */ false, /* offset = */ 0, data);
+
+  EXPECT_CALL(
+      *connection_,
+      CloseConnection(QUIC_DECOMPRESSION_FAILURE,
+                      "Encoder stream error: Invalid relative index.", _));
+  session_.OnStreamFrame(frame);
+}
+
+TEST_P(QuicSpdySessionTestClient, DecoderStreamError) {
+  if (!VersionUsesQpack(transport_version())) {
+    return;
+  }
+
+  std::string data = QuicTextUtils::HexDecode(
+      "03"    // Decoder stream.
+      "00");  // Insert Count Increment with forbidden increment value of zero.
+
+  QuicStreamId stream_id =
+      GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
+
+  QuicStreamFrame frame(stream_id, /* fin = */ false, /* offset = */ 0, data);
+
+  EXPECT_CALL(
+      *connection_,
+      CloseConnection(QUIC_DECOMPRESSION_FAILURE,
+                      "Decoder stream error: Invalid increment value 0.", _));
+  session_.OnStreamFrame(frame);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic