In HTTP/3, write Priority on control stream before writing headers.
Currently the priority is in gQUIC fashion, where we only use the weight to build priority queue.
Priority might be sent on the control stream before handshake is confirmed. So this CL modifies QuicSendControlStream to send stream type and settings before any other data is sent.
gfe-relnote: v99 only, not in prod.
PiperOrigin-RevId: 256285943
Change-Id: Iaf72f9d6256a2692b284e3f6142755ff0d04d710
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc
index b50c3bb..ff81ebf 100644
--- a/quic/core/http/quic_spdy_stream_test.cc
+++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -166,9 +166,14 @@
}
void Initialize(bool stream_should_process_data) {
+ InitializeWithPerspective(stream_should_process_data,
+ Perspective::IS_SERVER);
+ }
+
+ void InitializeWithPerspective(bool stream_should_process_data,
+ Perspective perspective) {
connection_ = new StrictMock<MockQuicConnection>(
- &helper_, &alarm_factory_, Perspective::IS_SERVER,
- SupportedVersions(GetParam()));
+ &helper_, &alarm_factory_, perspective, SupportedVersions(GetParam()));
session_ = QuicMakeUnique<StrictMock<MockQuicSpdySession>>(connection_);
session_->Initialize();
ON_CALL(*session_, WritevData(_, _, _, _, _))
@@ -1163,6 +1168,42 @@
EXPECT_TRUE(stream_->fin_sent());
}
+TEST_P(QuicSpdyStreamTest, ClientWritesPriority) {
+ if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+ // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
+ // enabled and fix it.
+ return;
+ }
+
+ InitializeWithPerspective(kShouldProcessData, Perspective::IS_CLIENT);
+
+ if (VersionUsesQpack(GetParam().transport_version)) {
+ // In this case, TestStream::WriteHeadersImpl() does not prevent writes.
+ // Six writes include priority for headers, headers frame header, headers
+ // frame, priority of trailers, trailing headers frame header, and trailers.
+ EXPECT_CALL(*session_, WritevData(stream_, stream_->id(), _, _, _))
+ .Times(4);
+ auto send_control_stream =
+ QuicSpdySessionPeer::GetSendControlStream(session_.get());
+ // The control stream will write 3 times, including stream type, settings
+ // frame, priority for headers.
+ EXPECT_CALL(*session_, WritevData(send_control_stream,
+ send_control_stream->id(), _, _, _))
+ .Times(3);
+ }
+
+ // Write the initial headers, without a FIN.
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
+ stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
+
+ // Writing trailers implicitly sends a FIN.
+ SpdyHeaderBlock trailers;
+ trailers["trailer key"] = "trailer value";
+ EXPECT_CALL(*stream_, WriteHeadersMock(true));
+ stream_->WriteTrailers(std::move(trailers), nullptr);
+ EXPECT_TRUE(stream_->fin_sent());
+}
+
// Test that when writing trailers, the trailers that are actually sent to the
// peer contain the final offset field indicating last byte of data.
TEST_P(QuicSpdyStreamTest, WritingTrailersFinalOffset) {