diff --git a/src/net/quic/quic_chromium_client_stream.cc b/src/net/quic/quic_chromium_client_stream.cc index c3ecf2af98..851aa37613 100644 --- a/src/net/quic/quic_chromium_client_stream.cc +++ b/src/net/quic/quic_chromium_client_stream.cc @@ -874,6 +874,11 @@ int QuicChromiumClientStream::DeliverInitialHeaders( return ERR_INVALID_RESPONSE; } + // During proxy Fast Open, DeliverInitialHeaders() queued from + // OnInitialHeadersComplete() can be delayed after OnBodyAvailable(), + // which then does nothing and stalls ReadBody(). Resumes it here. + OnBodyAvailable(); + net_log_.AddEvent( NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_HEADERS, [&](NetLogCaptureMode capture_mode) { diff --git a/src/net/quic/quic_proxy_client_socket.cc b/src/net/quic/quic_proxy_client_socket.cc index 7ebbcf64e8..a886a90db7 100644 --- a/src/net/quic/quic_proxy_client_socket.cc +++ b/src/net/quic/quic_proxy_client_socket.cc @@ -270,6 +270,13 @@ void QuicProxyClientSocket::OnIOComplete(int result) { DCHECK_NE(STATE_DISCONNECTED, next_state_); int rv = DoLoop(result); if (rv != ERR_IO_PENDING) { + if (use_fastopen_ && read_headers_pending_ == false) { + if (rv != OK) + next_state_ = STATE_DISCONNECTED; + if (read_callback_ && rv != OK) + std::move(read_callback_).Run(rv); + return; + } // Connect() finished (successfully or unsuccessfully). DCHECK(!connect_callback_.is_null()); std::move(connect_callback_).Run(rv); @@ -387,6 +394,11 @@ int QuicProxyClientSocket::DoCalculateHeadersComplete(int result) { return result; } next_state_ = STATE_SEND_REQUEST; + if (proxy_delegate_headers_.HasHeader("fastopen")) { + proxy_delegate_headers_.RemoveHeader("fastopen"); + // TODO(klzgrad): look into why Fast Open does not work. + use_fastopen_ = true; + } request_.extra_headers.MergeFrom(proxy_delegate_headers_); return result; } @@ -431,6 +443,11 @@ int QuicProxyClientSocket::DoReadReply() { &response_header_block_, base::BindOnce(&QuicProxyClientSocket::OnReadResponseHeadersComplete, weak_factory_.GetWeakPtr())); + if (use_fastopen_ && rv == ERR_IO_PENDING) { + read_headers_pending_ = true; + next_state_ = STATE_CONNECT_COMPLETE; + return OK; + } if (rv == ERR_IO_PENDING) return ERR_IO_PENDING; if (rv < 0) @@ -499,6 +516,14 @@ int QuicProxyClientSocket::DoProcessResponseCode() { void QuicProxyClientSocket::OnReadResponseHeadersComplete(int result) { // Convert the now-populated quiche::HttpHeaderBlock to HttpResponseInfo + if (use_fastopen_ && read_headers_pending_) { + read_headers_pending_ = false; + if (next_state_ == STATE_DISCONNECTED) + return; + if (next_state_ == STATE_CONNECT_COMPLETE) + next_state_ = STATE_READ_REPLY_COMPLETE; + } + if (result > 0) result = ProcessResponseHeaders(response_header_block_); diff --git a/src/net/quic/quic_proxy_client_socket.h b/src/net/quic/quic_proxy_client_socket.h index eb74348630..b56eea831c 100644 --- a/src/net/quic/quic_proxy_client_socket.h +++ b/src/net/quic/quic_proxy_client_socket.h @@ -164,6 +164,9 @@ class NET_EXPORT_PRIVATE QuicProxyClientSocket : public ProxyClientSocket { std::string user_agent_; + bool use_fastopen_ = false; + std::optional read_headers_pending_; + const NetLogWithSource net_log_; // The default weak pointer factory.