From fd56d6f537418dc752ee136947a928b38e1e6bfa Mon Sep 17 00:00:00 2001 From: klzgrad Date: Thu, 17 Jan 2019 05:47:20 -0500 Subject: [PATCH] quic: Add support for HTTP/3 CONNECT Fast Open SpdyProxyClientSocket uses read_callback_ for both Connect() and Read(), and its OnIOComplete() calls read_callback_, thus its fast connect code checks read_callback_. The code was ported to QuicProxyClientSocket without much change. But QuicProxyClientSocket uses a separate connect_callback_ apart from read_callback_, and its OnIOComplete() calls connect_callback_, thus when headers are received after Connect() it doesn't need to check read_callback_ and should always avoid calling connect_callback_. --- src/net/quic/quic_proxy_client_socket.cc | 29 ++++++++++++++++++++++++ src/net/quic/quic_proxy_client_socket.h | 6 +++++ 2 files changed, 35 insertions(+) diff --git a/src/net/quic/quic_proxy_client_socket.cc b/src/net/quic/quic_proxy_client_socket.cc index a663ea71f8..83fdb1fb97 100644 --- a/src/net/quic/quic_proxy_client_socket.cc +++ b/src/net/quic/quic_proxy_client_socket.cc @@ -41,6 +41,8 @@ QuicProxyClientSocket::QuicProxyClientSocket( proxy_chain_index_(proxy_chain_index), proxy_delegate_(proxy_delegate), user_agent_(user_agent), + use_fastopen_(false), + read_headers_pending_(false), net_log_(net_log) { DCHECK(stream_->IsOpen()); @@ -303,6 +305,16 @@ int QuicProxyClientSocket::DoLoop(int last_io_result) { rv = DoReadReplyComplete(rv); net_log_.EndEventWithNetErrorCode( NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv); + if (use_fastopen_ && read_headers_pending_) { + read_headers_pending_ = false; + if (rv < 0) { + // read_callback_ will be called with this error and be reset. + // Further data after that will be ignored. + next_state_ = STATE_DISCONNECTED; + } + // Prevents calling connect_callback_. + rv = ERR_IO_PENDING; + } break; default: NOTREACHED() << "bad state"; @@ -343,6 +355,11 @@ int QuicProxyClientSocket::DoSendRequest() { HttpRequestHeaders proxy_delegate_headers; proxy_delegate_->OnBeforeTunnelRequest(proxy_chain_, proxy_chain_index_, &proxy_delegate_headers); + 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); } @@ -383,6 +400,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) @@ -431,6 +453,13 @@ int QuicProxyClientSocket::DoReadReplyComplete(int result) { void QuicProxyClientSocket::OnReadResponseHeadersComplete(int result) { // Convert the now-populated spdy::Http2HeaderBlock to HttpResponseInfo + if (use_fastopen_ && read_headers_pending_) { + 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 618aa53b5a..029015a7b1 100644 --- a/src/net/quic/quic_proxy_client_socket.h +++ b/src/net/quic/quic_proxy_client_socket.h @@ -145,6 +145,12 @@ class NET_EXPORT_PRIVATE QuicProxyClientSocket : public ProxyClientSocket { std::string user_agent_; + // Session connect timing info. + LoadTimingInfo::ConnectTiming connect_timing_; + + bool use_fastopen_; + bool read_headers_pending_; + const NetLogWithSource net_log_; // The default weak pointer factory.