In v99, close the connection if the peer sets the number of unidirectional stream less than the minimum required unidirectional streams.
The spec is reflected at https://quicwg.org/base-drafts/draft-ietf-quic-http.html#rfc.section.6.2
gfe-relnote: v99 only, not protected.
PiperOrigin-RevId: 267241053
Change-Id: I0fc9e909e90d023b5b99cc1a5bb6a37d5c592ab6
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 55de8b6..4b14600 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -13,6 +13,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h"
#include "net/third_party/quiche/src/quic/core/http/http_constants.h"
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
@@ -1514,6 +1515,23 @@
session_.OnConfigNegotiated();
}
+TEST_P(QuicSpdySessionTestServer, TooLowUnidirectionalStreamLimitHttp3) {
+ if (!VersionUsesQpack(transport_version()) ||
+ GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+ // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
+ // enabled and fix it.
+ return;
+ }
+
+ QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams(session_.config(),
+ 2u);
+
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(_, "New unidirectional stream limit is too low.", _));
+ session_.OnConfigNegotiated();
+}
+
// Test negotiation of custom server initial flow control window.
TEST_P(QuicSpdySessionTestServer, CustomFlowControlWindow) {
QuicTagVector copt;
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index 23935b3..464c4f5 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -963,7 +963,7 @@
void QuicSession::OnConfigNegotiated() {
connection_->SetFromConfig(config_);
- if (VersionHasIetfQuicFrames(connection_->transport_version())) {
+ if (VersionHasIetfQuicFrames(transport_version())) {
uint32_t max_streams = 0;
if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
diff --git a/quic/core/quic_stream_id_manager.cc b/quic/core/quic_stream_id_manager.cc
index 440b97a..f856ab0 100644
--- a/quic/core/quic_stream_id_manager.cc
+++ b/quic/core/quic_stream_id_manager.cc
@@ -98,6 +98,19 @@
// Used when configuration has been done and we have an initial
// maximum stream count from the peer.
bool QuicStreamIdManager::SetMaxOpenOutgoingStreams(size_t max_open_streams) {
+ if (unidirectional_ &&
+ max_open_streams <
+ session_->num_expected_unidirectional_static_streams()) {
+ // Requirement can be found at
+ // https://tools.ietf.org/html/draft-ietf-quic-http-22#section-6.2.
+ QUIC_DLOG(ERROR) << "Received max unidirectional stream "
+ << max_open_streams << " < "
+ << session_->num_expected_unidirectional_static_streams();
+ session_->connection()->CloseConnection(
+ QUIC_MAX_STREAMS_ERROR, "New unidirectional stream limit is too low.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
if (using_default_max_streams_) {
// This is the first MAX_STREAMS/transport negotiation we've received. Treat
// this a bit differently than later ones. The difference is that