From 70b6fc6f99ec38dc2216273e0baaa61b55308f8e Mon Sep 17 00:00:00 2001 From: klzgrad Date: Thu, 30 Apr 2026 22:39:10 +0800 Subject: [PATCH] net/quic: Support tunnel preamble requests --- src/net/quic/quic_proxy_client_socket.cc | 58 ++++++++++++++++++++++++ src/net/quic/quic_proxy_client_socket.h | 1 + 2 files changed, 59 insertions(+) diff --git a/src/net/quic/quic_proxy_client_socket.cc b/src/net/quic/quic_proxy_client_socket.cc index 9f9c5c634f..2cfb627ce8 100644 --- a/src/net/quic/quic_proxy_client_socket.cc +++ b/src/net/quic/quic_proxy_client_socket.cc @@ -53,6 +53,15 @@ QuicProxyClientSocket::QuicProxyClientSocket( request_.method = "CONNECT"; request_.url = GURL("https://" + endpoint.ToString()); + if (endpoint.host() == "preamble") { + preamble_index_ = endpoint.port(); + CHECK(!proxy_chain.is_direct()); + CHECK_EQ(proxy_chain_index, proxy_chain.length() - 1); + const ProxyServer& proxy_server = + proxy_chain.GetProxyServer(proxy_chain_index); + CHECK(proxy_server.is_secure_http_like()); + request_.url = GURL("https://" + proxy_server.host_port_pair().ToString()); + } net_log_.BeginEventReferencingSource(NetLogEventType::SOCKET_ALIVE, net_log_.source()); @@ -376,6 +385,12 @@ int QuicProxyClientSocket::DoCalculateHeaders() { } if (proxy_delegate_) { + if (preamble_index_.has_value()) { + proxy_delegate_->OnBeforePreambleRequest(proxy_chain_, proxy_chain_index_, + *preamble_index_, + proxy_delegate_headers_); + return OK; + } ASSIGN_OR_RETURN( proxy_delegate_headers_, proxy_delegate_->OnBeforeTunnelRequest( @@ -404,6 +419,36 @@ int QuicProxyClientSocket::DoCalculateHeadersComplete(int result) { // TODO(klzgrad): look into why Fast Open does not work. use_fastopen_ = true; } + if (preamble_index_.has_value()) { + authorization_headers_.Clear(); + std::optional method = + proxy_delegate_headers_.GetHeaderView("_method"); + if (method.has_value()) { + request_.method = *method; + proxy_delegate_headers_.RemoveHeader("_method"); + } else { + LOG(ERROR) << "Missing preamble method"; + return ERR_INVALID_ARGUMENT; + } + std::optional path = + proxy_delegate_headers_.GetHeaderView("_path"); + if (path.has_value()) { + RequestPriority priority = LOWEST; + if (*path == "/" || path->ends_with(".css")) { + priority = HIGHEST; + } else if (path->ends_with(".js")) { + priority = LOW; + } + uint8_t urgency = ConvertRequestPriorityToQuicPriority(priority); + stream_->SetPriority(quic::QuicStreamPriority( + quic::HttpStreamPriority{urgency, kDefaultPriorityIncremental})); + request_.url = request_.url.Resolve(*path); + proxy_delegate_headers_.RemoveHeader("_path"); + } else { + LOG(ERROR) << "Missing preamble path"; + return ERR_INVALID_ARGUMENT; + } + } request_.extra_headers.MergeFrom(proxy_delegate_headers_); return result; } @@ -423,6 +468,9 @@ int QuicProxyClientSocket::DoSendRequest() { CreateSpdyHeadersFromHttpRequest(request_, std::nullopt, request_.extra_headers, &headers); + if (preamble_index_.has_value()) { + return stream_->WriteHeaders(std::move(headers), true, nullptr); + } return stream_->WriteHeaders(std::move(headers), false, nullptr); } @@ -482,6 +530,11 @@ int QuicProxyClientSocket::DoProcessResponseHeaders() { next_state_ = STATE_PROCESS_RESPONSE_HEADERS_COMPLETE; if (proxy_delegate_) { + if (preamble_index_.has_value()) { + proxy_delegate_->OnPreambleHeadersReceived( + proxy_chain_, proxy_chain_index_, *preamble_index_, response_.headers); + return OK; + } return proxy_delegate_->OnTunnelHeadersReceived( proxy_chain_, proxy_chain_index_, *response_.headers, base::BindOnce(&QuicProxyClientSocket::OnIOComplete, @@ -502,6 +555,11 @@ int QuicProxyClientSocket::DoProcessResponseHeadersComplete(int result) { } int QuicProxyClientSocket::DoProcessResponseCode() { + if (preamble_index_.has_value()) { + // Ignores any response failures during preamble + next_state_ = STATE_CONNECT_COMPLETE; + return OK; + } switch (response_.headers->response_code()) { case 200: // OK next_state_ = STATE_CONNECT_COMPLETE; diff --git a/src/net/quic/quic_proxy_client_socket.h b/src/net/quic/quic_proxy_client_socket.h index df9cde7aab..4738a96ea7 100644 --- a/src/net/quic/quic_proxy_client_socket.h +++ b/src/net/quic/quic_proxy_client_socket.h @@ -168,6 +168,7 @@ class NET_EXPORT_PRIVATE QuicProxyClientSocket : public ProxyClientSocket { LoadTimingInfo::ConnectTiming connect_timing_; bool use_fastopen_; + std::optional preamble_index_; bool read_headers_pending_; const NetLogWithSource net_log_;