Add support for HTTP/3 control stream.
Upon initialization, QuicSpdySession will create a write_unidirectional stream
and write stream type and settings when crypto handshake is completed.
The peer will receive the stream type and create a read_unidirectional stream
that reads the settings.
gfe-relnote: version 99 only. Not in prod.
PiperOrigin-RevId: 252650934
Change-Id: I708280eb94dea3d6eb7e54b96ce8ee91e2b8684f
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index bd12a90..6bd587f 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -1530,7 +1530,10 @@
size_t client_max_open_outgoing_unidirectional_streams =
client_session->connection()->transport_version() == QUIC_VERSION_99
? QuicSessionPeer::v99_streamid_manager(client_session)
- ->max_allowed_outgoing_unidirectional_streams()
+ ->max_allowed_outgoing_unidirectional_streams() -
+ QuicSessionPeer::v99_unidirectional_stream_id_manager(
+ client_session)
+ ->outgoing_static_stream_count()
: QuicSessionPeer::GetStreamIdManager(client_session)
->max_open_outgoing_streams();
EXPECT_EQ(kServerMaxIncomingDynamicStreams,
@@ -1548,7 +1551,10 @@
size_t server_max_open_outgoing_unidirectional_streams =
server_session->connection()->transport_version() == QUIC_VERSION_99
? QuicSessionPeer::v99_streamid_manager(server_session)
- ->max_allowed_outgoing_unidirectional_streams()
+ ->max_allowed_outgoing_unidirectional_streams() -
+ QuicSessionPeer::v99_unidirectional_stream_id_manager(
+ server_session)
+ ->outgoing_static_stream_count()
: QuicSessionPeer::GetStreamIdManager(server_session)
->max_open_outgoing_streams();
EXPECT_EQ(kClientMaxIncomingDynamicStreams,
@@ -2048,9 +2054,13 @@
crypto_stream->flow_controller()),
kStreamIFCW);
}
- EXPECT_EQ(kSessionIFCW,
- QuicFlowControllerPeer::SendWindowSize(
- client_->client()->client_session()->flow_controller()));
+ // When stream type is enabled, control streams will send settings and
+ // contribute to flow control windows, so this expectation is no longer valid.
+ if (!VersionHasStreamType(transport_version)) {
+ EXPECT_EQ(kSessionIFCW,
+ QuicFlowControllerPeer::SendWindowSize(
+ client_->client()->client_session()->flow_controller()));
+ }
// Send a request with no body, and verify that the connection level window
// has not been affected.
@@ -2092,6 +2102,40 @@
server_thread_->Pause();
QuicSpdySession* const client_session = client_->client()->client_session();
auto* server_session = static_cast<QuicSpdySession*>(GetServerSession());
+
+ if (VersionHasStreamType(client_->client()
+ ->client_session()
+ ->connection()
+ ->transport_version())) {
+ // Settings frame will be sent through control streams, which contribute
+ // to the session's flow controller. And due to the timing issue described
+ // below, the settings frame might not be received.
+ HttpEncoder encoder;
+ SettingsFrame settings;
+ settings.values[6] = kDefaultMaxUncompressedHeaderSize;
+ std::unique_ptr<char[]> buffer;
+ auto header_length = encoder.SerializeSettingsFrame(settings, &buffer);
+ QuicByteCount win_difference1 = QuicFlowControllerPeer::ReceiveWindowSize(
+ server_session->flow_controller()) -
+ QuicFlowControllerPeer::SendWindowSize(
+ client_session->flow_controller());
+ QuicByteCount win_difference2 = QuicFlowControllerPeer::ReceiveWindowSize(
+ client_session->flow_controller()) -
+ QuicFlowControllerPeer::SendWindowSize(
+ server_session->flow_controller());
+ EXPECT_TRUE(win_difference1 == 0 ||
+ win_difference1 ==
+ header_length +
+ QuicDataWriter::GetVarInt62Len(kControlStream));
+ EXPECT_TRUE(win_difference2 == 0 ||
+ win_difference2 ==
+ header_length +
+ QuicDataWriter::GetVarInt62Len(kControlStream));
+ // The test returns early because in this version, headers stream no longer
+ // sends settings.
+ return;
+ }
+
ExpectFlowControlsSynced(client_session->flow_controller(),
server_session->flow_controller());
if (!QuicVersionUsesCryptoFrames(client_->client()