Redo the logic for buffering incoming streams until SETTINGS arrive.

Currently, we stop buffering whenever we receive any setting value, but we notify the streams to be unblocked only whenever we finish processing the SETTINGS frame on the control stream.  This is inconsistent, and also has a bug where an empty SETTINGS frame does not unblock the connection.

This CL makes both occur at the same time, once, at the moment when the SETTINGS frame arrives on the control stream.

PiperOrigin-RevId: 542196032
diff --git a/quiche/quic/core/http/quic_spdy_session.cc b/quiche/quic/core/http/quic_spdy_session.cc
index e68b021..0e18ebb 100644
--- a/quiche/quic/core/http/quic_spdy_session.cc
+++ b/quiche/quic/core/http/quic_spdy_session.cc
@@ -465,9 +465,8 @@
       spdy_framer_visitor_(new SpdyFramerVisitor(this)),
       debug_visitor_(nullptr),
       destruction_indicator_(123456789),
-      allow_extended_connect_(
-          perspective() == Perspective::IS_SERVER &&
-          VersionUsesHttp3(transport_version())) {
+      allow_extended_connect_(perspective() == Perspective::IS_SERVER &&
+                              VersionUsesHttp3(transport_version())) {
   h2_deframer_.set_visitor(spdy_framer_visitor_.get());
   h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get());
   spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
@@ -1019,6 +1018,13 @@
       return false;
     }
   }
+
+  // This is the last point in the connection when we can receive new SETTINGS
+  // values (ALPS and settings from the session ticket come before, and only one
+  // SETTINGS frame per connection is allowed).  Notify all the streams that are
+  // blocking on having the definitive settings list.
+  QUICHE_DCHECK(!settings_received_);
+  settings_received_ = true;
   for (QuicStreamId stream_id : streams_waiting_for_settings_) {
     QUICHE_DCHECK(ShouldBufferRequestsUntilSettings());
     QuicSpdyStream* stream = GetOrCreateSpdyDataStream(stream_id);
@@ -1030,6 +1036,7 @@
     stream->OnDataAvailable();
   }
   streams_waiting_for_settings_.clear();
+
   return true;
 }
 
@@ -1065,8 +1072,6 @@
 }
 
 bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
-  any_settings_received_ = true;
-
   if (VersionUsesHttp3(transport_version())) {
     // SETTINGS frame received on the control stream.
     switch (id) {
@@ -1721,7 +1726,7 @@
     return true;
   }
 
-  return any_settings_received_;
+  return settings_received_;
 }
 
 void QuicSpdySession::OnStreamWaitingForClientSettings(QuicStreamId id) {
diff --git a/quiche/quic/core/http/quic_spdy_session.h b/quiche/quic/core/http/quic_spdy_session.h
index b2f8b44..74ecd4f 100644
--- a/quiche/quic/core/http/quic_spdy_session.h
+++ b/quiche/quic/core/http/quic_spdy_session.h
@@ -646,9 +646,8 @@
   // Whether the peer has indicated WebTransport support.
   bool peer_supports_webtransport_ = false;
 
-  // Whether any settings have been received, either from the peer or from a
-  // session ticket.
-  bool any_settings_received_ = false;
+  // Whether the SETTINGS frame has been received on the control stream.
+  bool settings_received_ = false;
 
   // If ShouldBufferRequestsUntilSettings() is true, all streams that are
   // blocked by that are tracked here.