Correctly handle ignore_read_data case when sequencer gets unblocked.

Notes:
The divergence of code on ignore_read_data_ is a well exercised pattern (quic/core/quic_stream_sequencer.cc;l=126-130;bpv=1;bpt=0;rcl=834059230) in that data should not be passed up when application asks to ignore them.

Protected by FLAGS_quic_reloadable_flag_quic_fix_ignore_read_data_when_unblocked.

PiperOrigin-RevId: 885296351
diff --git a/quiche/common/quiche_feature_flags_list.h b/quiche/common/quiche_feature_flags_list.h
index 8c58b90..709670c 100755
--- a/quiche/common/quiche_feature_flags_list.h
+++ b/quiche/common/quiche_feature_flags_list.h
@@ -43,6 +43,7 @@
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_enobufs_blocked, true, true, "If true, ENOBUFS socket errors are reported as socket blocked instead of socket failure.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_fin_before_completed_http_headers, false, true, "If true, close the connection with error if FIN is received before finish receiving the whole HTTP headers.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_fix_gap_filling_ack_logic, false, false, "If true, fix the gap filling ack logic in QuicAckFrame.")
+QUICHE_FLAG(bool, quiche_reloadable_flag_quic_fix_ignore_read_data_when_unblocked, false, false, "If true, correctly handle ignore_read_data case when sequencer gets unblocked.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_fix_timeouts, true, true, "If true, postpone setting handshake timeout to infinite to handshake complete.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_include_datagrams_in_willing_to_write, false, false, "If true, checks for queued datagrams when determining if a connection is willing to write.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_move_clock_now, false, false, "If true, move the call to clock.Now() in QuicPacketReader::ReadAndDispatchPackets to after socket_api_.ReadMultiplePackets().")
diff --git a/quiche/quic/core/http/quic_spdy_stream_test.cc b/quiche/quic/core/http/quic_spdy_stream_test.cc
index 8acea52..3038037 100644
--- a/quiche/quic/core/http/quic_spdy_stream_test.cc
+++ b/quiche/quic/core/http/quic_spdy_stream_test.cc
@@ -3860,15 +3860,15 @@
   EXPECT_TRUE(stream_->sequencer()->HasBytesToRead());
   EXPECT_TRUE(QuicSpdyStreamPeer::BodyManager(stream_).HasBytesToRead());
 
-  // QUIC gets blocked.
-  stream_->sequencer()->SetBlockedUntilFlush();
-
   // In Envoy QUIC, StopReading can be called after local reset.
   stream_->StopReading();
   // Sequencer is not closed but the bytes in body_manager is cleared.
   EXPECT_FALSE(stream_->sequencer()->IsClosed());
   EXPECT_FALSE(QuicSpdyStreamPeer::BodyManager(stream_).HasBytesToRead());
 
+  // QUIC gets blocked.
+  stream_->sequencer()->SetBlockedUntilFlush();
+
   // FIN does not close the read side since the stream is blocked.
   QuicStreamFrame frame2(GetNthClientInitiatedBidirectionalId(0), /*fin=*/true,
                          offset, "second body");
@@ -3888,7 +3888,11 @@
   // QUIC gets unblocked.
   stream_->sequencer()->SetUnblocked();
 
-  EXPECT_FALSE(stream_->read_side_closed());
+  if (GetQuicReloadableFlag(quic_fix_ignore_read_data_when_unblocked)) {
+    EXPECT_TRUE(stream_->read_side_closed());
+  } else {
+    EXPECT_FALSE(stream_->read_side_closed());
+  }
 }
 
 }  // namespace
diff --git a/quiche/quic/core/quic_stream_sequencer.cc b/quiche/quic/core/quic_stream_sequencer.cc
index 13a1668..dcb6252 100644
--- a/quiche/quic/core/quic_stream_sequencer.cc
+++ b/quiche/quic/core/quic_stream_sequencer.cc
@@ -24,6 +24,7 @@
 #include "quiche/quic/platform/api/quic_flags.h"
 #include "quiche/quic/platform/api/quic_logging.h"
 #include "quiche/quic/platform/api/quic_stack_trace.h"
+#include "quiche/common/platform/api/quiche_flag_utils.h"
 
 namespace quic {
 
@@ -265,6 +266,16 @@
 
 void QuicStreamSequencer::SetUnblocked() {
   blocked_ = false;
+  if (GetQuicReloadableFlag(quic_fix_ignore_read_data_when_unblocked)) {
+    QUICHE_RELOADABLE_FLAG_COUNT_N(quic_fix_ignore_read_data_when_unblocked, 1,
+                                   2);
+    if (ignore_read_data_) {
+      QUICHE_RELOADABLE_FLAG_COUNT_N(quic_fix_ignore_read_data_when_unblocked,
+                                     2, 2);
+      FlushBufferedFrames();
+      return;
+    }
+  }
   if (IsClosed() || HasBytesToRead()) {
     stream_->OnDataAvailable();
   }