Allow QuicSimpleServerStream to send CONNECT response This will allow us to support MASQUE CONNECT-UDP in a subsequent change. This class is not used in production and therefore does not require flag protection. PiperOrigin-RevId: 344288735 Change-Id: I4e5d75943b36b928e0db55ad5de435b19cb81355
diff --git a/quic/tools/quic_simple_server_stream.cc b/quic/tools/quic_simple_server_stream.cc index 93b4356..8fee04a 100644 --- a/quic/tools/quic_simple_server_stream.cc +++ b/quic/tools/quic_simple_server_stream.cc
@@ -7,6 +7,7 @@ #include <list> #include <utility> +#include "absl/strings/match.h" #include "absl/strings/numbers.h" #include "absl/strings/string_view.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h" @@ -63,6 +64,16 @@ SendErrorResponse(); } ConsumeHeaderList(); + if (!fin) { + // CONNECT and other CONNECT-like methods (such as CONNECT-UDP) require + // sending the response right after parsing the headers even though the FIN + // bit has not been received on the request stream. + auto it = request_headers_.find(":method"); + if (it != request_headers_.end() && + absl::StartsWith(it->second, "CONNECT")) { + SendResponse(); + } + } } void QuicSimpleServerStream::OnTrailingHeadersComplete(
diff --git a/quic/tools/quic_simple_server_stream_test.cc b/quic/tools/quic_simple_server_stream_test.cc index 4b21cca..c21088a 100644 --- a/quic/tools/quic_simple_server_stream_test.cc +++ b/quic/tools/quic_simple_server_stream_test.cc
@@ -76,12 +76,22 @@ void set_body(std::string body) { body_ = std::move(body); } const std::string& body() const { return body_; } int content_length() const { return content_length_; } + bool send_response_was_called() const { return send_response_was_called_; } absl::string_view GetHeader(absl::string_view key) const { auto it = request_headers_.find(key); DCHECK(it != request_headers_.end()); return it->second; } + + protected: + void SendResponse() override { + send_response_was_called_ = true; + QuicSimpleServerStream::SendResponse(); + } + + private: + bool send_response_was_called_ = false; }; namespace { @@ -782,6 +792,29 @@ stream_->OnStreamFrame(frame); } +TEST_P(QuicSimpleServerStreamTest, ConnectSendsResponseBeforeFinReceived) { + EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)) + .WillRepeatedly( + Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData)); + QuicHeaderList header_list; + header_list.OnHeaderBlockStart(); + header_list.OnHeader(":authority", "www.google.com:4433"); + header_list.OnHeader(":method", "CONNECT-SILLY"); + header_list.OnHeaderBlockEnd(128, 128); + EXPECT_CALL(*stream_, WriteHeadersMock(/*fin=*/false)); + stream_->OnStreamHeaderList(/*fin=*/false, kFakeFrameLen, header_list); + std::unique_ptr<char[]> buffer; + QuicByteCount header_length = + HttpEncoder::SerializeDataFrameHeader(body_.length(), &buffer); + std::string header = std::string(buffer.get(), header_length); + std::string data = UsesHttp3() ? header + body_ : body_; + stream_->OnStreamFrame( + QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data)); + EXPECT_EQ("CONNECT-SILLY", StreamHeadersValue(":method")); + EXPECT_EQ(body_, StreamBody()); + EXPECT_TRUE(stream_->send_response_was_called()); +} + } // namespace } // namespace test } // namespace quic