net: Allow HTTP/2 CONNECT fast open

SpdyProxyClientSocket waits for 200 OK before returning OK for Connect.

Change that behavior to returning OK immediately after CONNECT header.
This commit is contained in:
klzgrad 2018-01-29 13:02:09 -05:00
parent 426bbe31d5
commit 1ad9649508
2 changed files with 51 additions and 0 deletions

View File

@ -45,6 +45,10 @@ SpdyProxyClientSocket::SpdyProxyClientSocket(
write_buffer_len_(0),
was_ever_used_(false),
redirect_has_load_timing_info_(false),
// This is a hack to avoid messing up higher APIs.
// Should be false by default officially.
use_fastopen_(true),
read_headers_pending_(false),
net_log_(NetLogWithSource::Make(spdy_stream->net_log().net_log(),
NetLogSourceType::PROXY_CLIENT_SOCKET)),
source_dependency_(source_net_log.source()),
@ -314,6 +318,20 @@ int SpdyProxyClientSocket::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_ cannot be called.
if (!read_callback_)
rv = ERR_IO_PENDING;
// read_callback_ will be called with this error and be reset.
// Further data after that will be ignored.
next_state_ = STATE_DISCONNECTED;
} else {
// Does not call read_callback_ from here if headers are OK.
rv = ERR_IO_PENDING;
}
}
break;
default:
NOTREACHED() << "bad state";
@ -371,6 +389,32 @@ int SpdyProxyClientSocket::DoSendRequestComplete(int result) {
if (result < 0)
return result;
// This is better than TCP Fast Open style fake Connect().
//
// Fast Open should not be used for preconnects as preconnects need actual
// connections set up. Hence there is a need to check the incoming socket for
// available bytes and configure whether a socket should be Fast Open. But
// fake Connect() make it difficult to check the incoming socket because it
// immediately returns and there is not enough time to get the first read
// from the incoming socket.
//
// The other (wrong) way that pushes the read of incoming socket as late as
// possible is to pass in an early read callback and call it and then send
// available bytes here. This way is wrong because it does not work with late
// binding, which causes sockets opened in this way to be potentially bound
// to the wrong socket requests.
//
// The current approach is to return OK in Connect() before
// STATE_READ_REPLY_COMPLETE, which is completed later. If it is completed
// during a Read and there is an error, the error is returned to the callback
// of the Read; otherwise the error is ignored and subsequent Read/Write
// should discover STATE_DISCONNECTED.
if (use_fastopen_) {
read_headers_pending_ = true;
next_state_ = STATE_OPEN;
return OK;
}
// Wait for HEADERS frame from the server
next_state_ = STATE_READ_REPLY_COMPLETE;
return ERR_IO_PENDING;
@ -438,6 +482,10 @@ void SpdyProxyClientSocket::OnHeadersSent() {
void SpdyProxyClientSocket::OnHeadersReceived(
const SpdyHeaderBlock& response_headers) {
if (use_fastopen_ && read_headers_pending_ && next_state_ == STATE_OPEN) {
next_state_ = STATE_READ_REPLY_COMPLETE;
}
// If we've already received the reply, existing headers are too late.
// TODO(mbelshe): figure out a way to make HEADERS frames useful after the
// initial response.

View File

@ -170,6 +170,9 @@ class NET_EXPORT_PRIVATE SpdyProxyClientSocket : public ProxyClientSocket,
bool redirect_has_load_timing_info_;
LoadTimingInfo redirect_load_timing_info_;
bool use_fastopen_;
bool read_headers_pending_;
const NetLogWithSource net_log_;
const NetLogSource source_dependency_;