Close connection on incoming PRIORITY_UPDATE frame with invalid stream ID.

gfe-relnote: n/a, change to QUIC v99-only code.  Protected by existing disabled gfe2_reloadable_flag_quic_enable_version_99.
PiperOrigin-RevId: 290870791
Change-Id: Ie618cfe2479ae1f7f0151b0bc03a939aec9e87b6
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index 301e1d1..db93a86 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -504,7 +504,19 @@
     return true;
   }
 
-  // TODO(b/147306124): Signal error on invalid stream_id.
+  QuicStreamCount advertised_max_incoming_bidirectional_streams =
+      GetAdvertisedMaxIncomingBidirectionalStreams();
+  if (advertised_max_incoming_bidirectional_streams == 0 ||
+      stream_id > QuicUtils::GetFirstBidirectionalStreamId(
+                      transport_version(), Perspective::IS_CLIENT) +
+                      QuicUtils::StreamIdDelta(transport_version()) *
+                          (advertised_max_incoming_bidirectional_streams - 1)) {
+    connection()->CloseConnection(
+        QUIC_INVALID_STREAM_ID,
+        "PRIORITY_UPDATE frame received for invalid stream.",
+        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+    return false;
+  }
 
   MaybeSetStreamPriority(stream_id, spdy::SpdyStreamPrecedence(urgency));
 
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index 5f3ea29..16ec7b6 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -1509,6 +1509,12 @@
       GetNumOpenOutgoingStreams());
 }
 
+QuicStreamCount QuicSession::GetAdvertisedMaxIncomingBidirectionalStreams()
+    const {
+  DCHECK(VersionHasIetfQuicFrames(transport_version()));
+  return v99_streamid_manager_.advertised_max_incoming_bidirectional_streams();
+}
+
 QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
   DCHECK(!QuicContainsKey(pending_stream_map_, stream_id));
   if (QuicUtils::IsCryptoStreamId(transport_version(), stream_id)) {
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h
index f473156..84ba8e1 100644
--- a/quic/core/quic_session.h
+++ b/quic/core/quic_session.h
@@ -544,6 +544,10 @@
   // Returns the number of open dynamic streams.
   uint64_t GetNumOpenDynamicStreams() const;
 
+  // Returns the maximum bidirectional streams parameter sent with the handshake
+  // as a transport parameter, or in the most recent MAX_STREAMS frame.
+  QuicStreamCount GetAdvertisedMaxIncomingBidirectionalStreams() const;
+
   // Performs the work required to close |stream_id|.  If |locally_reset|
   // then the stream has been reset by this endpoint, not by the peer.
   virtual void CloseStreamInner(QuicStreamId stream_id, bool locally_reset);