Close connection when stream receives wrong data regarding close offset.

gfe-relnote: protected by gfe2_reloadable_flag_quic_close_connection_on_wrong_offset.
PiperOrigin-RevId: 276352453
Change-Id: Ia4174e54d01a2d8c2aa10182940c1093c1a16ad8
diff --git a/quic/core/quic_stream.cc b/quic/core/quic_stream.cc
index 4b70bd4..aced2b9 100644
--- a/quic/core/quic_stream.cc
+++ b/quic/core/quic_stream.cc
@@ -9,6 +9,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
 #include "net/third_party/quiche/src/quic/core/quic_flow_controller.h"
 #include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
@@ -172,7 +173,12 @@
   }
 
   if (frame.offset + frame.data_length > sequencer_.close_offset()) {
-    Reset(QUIC_DATA_AFTER_CLOSE_OFFSET);
+    CloseConnectionWithDetails(
+        QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET,
+        QuicStrCat(
+            "Stream ", id_,
+            " received data with offset: ", frame.offset + frame.data_length,
+            ", which is beyond close offset: ", sequencer()->close_offset()));
     return;
   }
 
@@ -211,6 +217,20 @@
                                "Reset frame stream offset overflow.");
     return;
   }
+
+  const QuicStreamOffset kMaxOffset =
+      std::numeric_limits<QuicStreamOffset>::max();
+  if (sequencer()->close_offset() != kMaxOffset &&
+      frame.byte_offset != sequencer()->close_offset()) {
+    CloseConnectionWithDetails(
+        QUIC_STREAM_MULTIPLE_OFFSET,
+        QuicStrCat("Stream ", id_,
+                   " received new final offset: ", frame.byte_offset,
+                   ", which is different from close offset: ",
+                   sequencer()->close_offset()));
+    return;
+  }
+
   MaybeIncreaseHighestReceivedOffset(frame.byte_offset);
   if (flow_controller_.FlowControlViolation() ||
       connection_flow_controller_->FlowControlViolation()) {
@@ -402,7 +422,17 @@
   }
 
   if (frame.offset + frame.data_length > sequencer_.close_offset()) {
-    Reset(QUIC_DATA_AFTER_CLOSE_OFFSET);
+    if (!GetQuicReloadableFlag(quic_close_connection_on_wrong_offset)) {
+      Reset(QUIC_DATA_AFTER_CLOSE_OFFSET);
+      return;
+    }
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_close_connection_on_wrong_offset, 1, 2);
+    CloseConnectionWithDetails(
+        QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET,
+        QuicStrCat(
+            "Stream ", id_,
+            " received data with offset: ", frame.offset + frame.data_length,
+            ", which is beyond close offset: ", sequencer_.close_offset()));
     return;
   }
 
@@ -459,6 +489,23 @@
                                "Reset frame stream offset overflow.");
     return;
   }
+
+  if (GetQuicReloadableFlag(quic_close_connection_on_wrong_offset)) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_close_connection_on_wrong_offset, 2, 2);
+    const QuicStreamOffset kMaxOffset =
+        std::numeric_limits<QuicStreamOffset>::max();
+    if (sequencer()->close_offset() != kMaxOffset &&
+        frame.byte_offset != sequencer()->close_offset()) {
+      CloseConnectionWithDetails(
+          QUIC_STREAM_MULTIPLE_OFFSET,
+          QuicStrCat("Stream ", id_,
+                     " received new final offset: ", frame.byte_offset,
+                     ", which is different from close offset: ",
+                     sequencer_.close_offset()));
+      return;
+    }
+  }
+
   MaybeIncreaseHighestReceivedOffset(frame.byte_offset);
   if (flow_controller_->FlowControlViolation() ||
       connection_flow_controller_->FlowControlViolation()) {