Index: net/spdy/spdy_proxy_client_socket.cc |
diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc |
deleted file mode 100644 |
index 661cfd99a7be6a60fe18edb209d21d33a21160ee..0000000000000000000000000000000000000000 |
--- a/net/spdy/spdy_proxy_client_socket.cc |
+++ /dev/null |
@@ -1,540 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "net/spdy/spdy_proxy_client_socket.h" |
- |
-#include <algorithm> // min |
- |
-#include "base/bind.h" |
-#include "base/bind_helpers.h" |
-#include "base/callback_helpers.h" |
-#include "base/logging.h" |
-#include "base/strings/string_util.h" |
-#include "base/values.h" |
-#include "net/base/auth.h" |
-#include "net/base/io_buffer.h" |
-#include "net/base/net_util.h" |
-#include "net/http/http_auth_cache.h" |
-#include "net/http/http_auth_handler_factory.h" |
-#include "net/http/http_response_headers.h" |
-#include "net/http/proxy_connect_redirect_http_stream.h" |
-#include "net/spdy/spdy_http_utils.h" |
-#include "url/gurl.h" |
- |
-namespace net { |
- |
-SpdyProxyClientSocket::SpdyProxyClientSocket( |
- const base::WeakPtr<SpdyStream>& spdy_stream, |
- const std::string& user_agent, |
- const HostPortPair& endpoint, |
- const GURL& url, |
- const HostPortPair& proxy_server, |
- const BoundNetLog& source_net_log, |
- HttpAuthCache* auth_cache, |
- HttpAuthHandlerFactory* auth_handler_factory) |
- : next_state_(STATE_DISCONNECTED), |
- spdy_stream_(spdy_stream), |
- endpoint_(endpoint), |
- auth_(new HttpAuthController(HttpAuth::AUTH_PROXY, |
- GURL("https://" + proxy_server.ToString()), |
- auth_cache, |
- auth_handler_factory)), |
- user_buffer_len_(0), |
- write_buffer_len_(0), |
- was_ever_used_(false), |
- redirect_has_load_timing_info_(false), |
- net_log_(BoundNetLog::Make(spdy_stream->net_log().net_log(), |
- NetLog::SOURCE_PROXY_CLIENT_SOCKET)), |
- weak_factory_(this), |
- write_callback_weak_factory_(this) { |
- request_.method = "CONNECT"; |
- request_.url = url; |
- if (!user_agent.empty()) |
- request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, |
- user_agent); |
- |
- net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, |
- source_net_log.source().ToEventParametersCallback()); |
- net_log_.AddEvent( |
- NetLog::TYPE_SPDY_PROXY_CLIENT_SESSION, |
- spdy_stream->net_log().source().ToEventParametersCallback()); |
- |
- spdy_stream_->SetDelegate(this); |
- was_ever_used_ = spdy_stream_->WasEverUsed(); |
-} |
- |
-SpdyProxyClientSocket::~SpdyProxyClientSocket() { |
- Disconnect(); |
- net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); |
-} |
- |
-const HttpResponseInfo* SpdyProxyClientSocket::GetConnectResponseInfo() const { |
- return response_.headers.get() ? &response_ : NULL; |
-} |
- |
-const scoped_refptr<HttpAuthController>& |
-SpdyProxyClientSocket::GetAuthController() const { |
- return auth_; |
-} |
- |
-int SpdyProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) { |
- // A SPDY Stream can only handle a single request, so the underlying |
- // stream may not be reused and a new SpdyProxyClientSocket must be |
- // created (possibly on top of the same SPDY Session). |
- next_state_ = STATE_DISCONNECTED; |
- return OK; |
-} |
- |
-bool SpdyProxyClientSocket::IsUsingSpdy() const { |
- return true; |
-} |
- |
-NextProto SpdyProxyClientSocket::GetProtocolNegotiated() const { |
- // Save the negotiated protocol |
- SSLInfo ssl_info; |
- bool was_npn_negotiated; |
- NextProto protocol_negotiated; |
- spdy_stream_->GetSSLInfo(&ssl_info, &was_npn_negotiated, |
- &protocol_negotiated); |
- return protocol_negotiated; |
-} |
- |
-HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() { |
- return new ProxyConnectRedirectHttpStream( |
- redirect_has_load_timing_info_ ? &redirect_load_timing_info_ : NULL); |
-} |
- |
-// Sends a SYN_STREAM frame to the proxy with a CONNECT request |
-// for the specified endpoint. Waits for the server to send back |
-// a SYN_REPLY frame. OK will be returned if the status is 200. |
-// ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status. |
-// In any of these cases, Read() may be called to retrieve the HTTP |
-// response body. Any other return values should be considered fatal. |
-// TODO(rch): handle 407 proxy auth requested correctly, perhaps |
-// by creating a new stream for the subsequent request. |
-// TODO(rch): create a more appropriate error code to disambiguate |
-// the HTTPS Proxy tunnel failure from an HTTP Proxy tunnel failure. |
-int SpdyProxyClientSocket::Connect(const CompletionCallback& callback) { |
- DCHECK(read_callback_.is_null()); |
- if (next_state_ == STATE_OPEN) |
- return OK; |
- |
- DCHECK_EQ(STATE_DISCONNECTED, next_state_); |
- next_state_ = STATE_GENERATE_AUTH_TOKEN; |
- |
- int rv = DoLoop(OK); |
- if (rv == ERR_IO_PENDING) |
- read_callback_ = callback; |
- return rv; |
-} |
- |
-void SpdyProxyClientSocket::Disconnect() { |
- read_buffer_queue_.Clear(); |
- user_buffer_ = NULL; |
- user_buffer_len_ = 0; |
- read_callback_.Reset(); |
- |
- write_buffer_len_ = 0; |
- write_callback_.Reset(); |
- write_callback_weak_factory_.InvalidateWeakPtrs(); |
- |
- next_state_ = STATE_DISCONNECTED; |
- |
- if (spdy_stream_.get()) { |
- // This will cause OnClose to be invoked, which takes care of |
- // cleaning up all the internal state. |
- spdy_stream_->Cancel(); |
- DCHECK(!spdy_stream_.get()); |
- } |
-} |
- |
-bool SpdyProxyClientSocket::IsConnected() const { |
- return next_state_ == STATE_OPEN; |
-} |
- |
-bool SpdyProxyClientSocket::IsConnectedAndIdle() const { |
- return IsConnected() && read_buffer_queue_.IsEmpty() && |
- spdy_stream_->IsOpen(); |
-} |
- |
-const BoundNetLog& SpdyProxyClientSocket::NetLog() const { |
- return net_log_; |
-} |
- |
-void SpdyProxyClientSocket::SetSubresourceSpeculation() { |
- // TODO(rch): what should this implementation be? |
-} |
- |
-void SpdyProxyClientSocket::SetOmniboxSpeculation() { |
- // TODO(rch): what should this implementation be? |
-} |
- |
-bool SpdyProxyClientSocket::WasEverUsed() const { |
- return was_ever_used_ || (spdy_stream_.get() && spdy_stream_->WasEverUsed()); |
-} |
- |
-bool SpdyProxyClientSocket::UsingTCPFastOpen() const { |
- return false; |
-} |
- |
-bool SpdyProxyClientSocket::WasNpnNegotiated() const { |
- return false; |
-} |
- |
-NextProto SpdyProxyClientSocket::GetNegotiatedProtocol() const { |
- return kProtoUnknown; |
-} |
- |
-bool SpdyProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) { |
- bool was_npn_negotiated; |
- NextProto protocol_negotiated; |
- return spdy_stream_->GetSSLInfo(ssl_info, &was_npn_negotiated, |
- &protocol_negotiated); |
-} |
- |
-int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len, |
- const CompletionCallback& callback) { |
- DCHECK(read_callback_.is_null()); |
- DCHECK(!user_buffer_.get()); |
- |
- if (next_state_ == STATE_DISCONNECTED) |
- return ERR_SOCKET_NOT_CONNECTED; |
- |
- if (next_state_ == STATE_CLOSED && read_buffer_queue_.IsEmpty()) { |
- return 0; |
- } |
- |
- DCHECK(next_state_ == STATE_OPEN || next_state_ == STATE_CLOSED); |
- DCHECK(buf); |
- size_t result = PopulateUserReadBuffer(buf->data(), buf_len); |
- if (result == 0) { |
- user_buffer_ = buf; |
- user_buffer_len_ = static_cast<size_t>(buf_len); |
- DCHECK(!callback.is_null()); |
- read_callback_ = callback; |
- return ERR_IO_PENDING; |
- } |
- user_buffer_ = NULL; |
- return result; |
-} |
- |
-size_t SpdyProxyClientSocket::PopulateUserReadBuffer(char* data, size_t len) { |
- return read_buffer_queue_.Dequeue(data, len); |
-} |
- |
-int SpdyProxyClientSocket::Write(IOBuffer* buf, int buf_len, |
- const CompletionCallback& callback) { |
- DCHECK(write_callback_.is_null()); |
- if (next_state_ != STATE_OPEN) |
- return ERR_SOCKET_NOT_CONNECTED; |
- |
- DCHECK(spdy_stream_.get()); |
- spdy_stream_->SendData(buf, buf_len, MORE_DATA_TO_SEND); |
- net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, |
- buf_len, buf->data()); |
- write_callback_ = callback; |
- write_buffer_len_ = buf_len; |
- return ERR_IO_PENDING; |
-} |
- |
-int SpdyProxyClientSocket::SetReceiveBufferSize(int32 size) { |
- // Since this StreamSocket sits on top of a shared SpdySession, it |
- // is not safe for callers to change this underlying socket. |
- return ERR_NOT_IMPLEMENTED; |
-} |
- |
-int SpdyProxyClientSocket::SetSendBufferSize(int32 size) { |
- // Since this StreamSocket sits on top of a shared SpdySession, it |
- // is not safe for callers to change this underlying socket. |
- return ERR_NOT_IMPLEMENTED; |
-} |
- |
-int SpdyProxyClientSocket::GetPeerAddress(IPEndPoint* address) const { |
- if (!IsConnected()) |
- return ERR_SOCKET_NOT_CONNECTED; |
- return spdy_stream_->GetPeerAddress(address); |
-} |
- |
-int SpdyProxyClientSocket::GetLocalAddress(IPEndPoint* address) const { |
- if (!IsConnected()) |
- return ERR_SOCKET_NOT_CONNECTED; |
- return spdy_stream_->GetLocalAddress(address); |
-} |
- |
-void SpdyProxyClientSocket::LogBlockedTunnelResponse() const { |
- ProxyClientSocket::LogBlockedTunnelResponse( |
- response_.headers->response_code(), |
- request_.url, |
- /* is_https_proxy = */ true); |
-} |
- |
-void SpdyProxyClientSocket::RunCallback(const CompletionCallback& callback, |
- int result) const { |
- callback.Run(result); |
-} |
- |
-void SpdyProxyClientSocket::OnIOComplete(int result) { |
- DCHECK_NE(STATE_DISCONNECTED, next_state_); |
- int rv = DoLoop(result); |
- if (rv != ERR_IO_PENDING) { |
- CompletionCallback c = read_callback_; |
- read_callback_.Reset(); |
- c.Run(rv); |
- } |
-} |
- |
-int SpdyProxyClientSocket::DoLoop(int last_io_result) { |
- DCHECK_NE(next_state_, STATE_DISCONNECTED); |
- int rv = last_io_result; |
- do { |
- State state = next_state_; |
- next_state_ = STATE_DISCONNECTED; |
- switch (state) { |
- case STATE_GENERATE_AUTH_TOKEN: |
- DCHECK_EQ(OK, rv); |
- rv = DoGenerateAuthToken(); |
- break; |
- case STATE_GENERATE_AUTH_TOKEN_COMPLETE: |
- rv = DoGenerateAuthTokenComplete(rv); |
- break; |
- case STATE_SEND_REQUEST: |
- DCHECK_EQ(OK, rv); |
- net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST); |
- rv = DoSendRequest(); |
- break; |
- case STATE_SEND_REQUEST_COMPLETE: |
- net_log_.EndEventWithNetErrorCode( |
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv); |
- rv = DoSendRequestComplete(rv); |
- if (rv >= 0 || rv == ERR_IO_PENDING) { |
- // Emit extra event so can use the same events as |
- // HttpProxyClientSocket. |
- net_log_.BeginEvent( |
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS); |
- } |
- break; |
- case STATE_READ_REPLY_COMPLETE: |
- rv = DoReadReplyComplete(rv); |
- net_log_.EndEventWithNetErrorCode( |
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv); |
- break; |
- default: |
- NOTREACHED() << "bad state"; |
- rv = ERR_UNEXPECTED; |
- break; |
- } |
- } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED && |
- next_state_ != STATE_OPEN); |
- return rv; |
-} |
- |
-int SpdyProxyClientSocket::DoGenerateAuthToken() { |
- next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE; |
- return auth_->MaybeGenerateAuthToken( |
- &request_, |
- base::Bind(&SpdyProxyClientSocket::OnIOComplete, |
- weak_factory_.GetWeakPtr()), |
- net_log_); |
-} |
- |
-int SpdyProxyClientSocket::DoGenerateAuthTokenComplete(int result) { |
- DCHECK_NE(ERR_IO_PENDING, result); |
- if (result == OK) |
- next_state_ = STATE_SEND_REQUEST; |
- return result; |
-} |
- |
-int SpdyProxyClientSocket::DoSendRequest() { |
- next_state_ = STATE_SEND_REQUEST_COMPLETE; |
- |
- // Add Proxy-Authentication header if necessary. |
- HttpRequestHeaders authorization_headers; |
- if (auth_->HaveAuth()) { |
- auth_->AddAuthorizationHeader(&authorization_headers); |
- } |
- |
- std::string request_line; |
- HttpRequestHeaders request_headers; |
- BuildTunnelRequest(request_, authorization_headers, endpoint_, &request_line, |
- &request_headers); |
- |
- net_log_.AddEvent( |
- NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, |
- base::Bind(&HttpRequestHeaders::NetLogCallback, |
- base::Unretained(&request_headers), |
- &request_line)); |
- |
- request_.extra_headers.MergeFrom(request_headers); |
- scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock()); |
- CreateSpdyHeadersFromHttpRequest(request_, request_headers, |
- spdy_stream_->GetProtocolVersion(), true, |
- headers.get()); |
- // Reset the URL to be the endpoint of the connection |
- if (spdy_stream_->GetProtocolVersion() > 2) { |
- (*headers)[":path"] = endpoint_.ToString(); |
- headers->erase(":scheme"); |
- } else { |
- (*headers)["url"] = endpoint_.ToString(); |
- headers->erase("scheme"); |
- } |
- |
- return spdy_stream_->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND); |
-} |
- |
-int SpdyProxyClientSocket::DoSendRequestComplete(int result) { |
- if (result < 0) |
- return result; |
- |
- // Wait for SYN_REPLY frame from the server |
- next_state_ = STATE_READ_REPLY_COMPLETE; |
- return ERR_IO_PENDING; |
-} |
- |
-int SpdyProxyClientSocket::DoReadReplyComplete(int result) { |
- // We enter this method directly from DoSendRequestComplete, since |
- // we are notified by a callback when the SYN_REPLY frame arrives |
- |
- if (result < 0) |
- return result; |
- |
- // Require the "HTTP/1.x" status line for SSL CONNECT. |
- if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) |
- return ERR_TUNNEL_CONNECTION_FAILED; |
- |
- net_log_.AddEvent( |
- NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, |
- base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers)); |
- |
- switch (response_.headers->response_code()) { |
- case 200: // OK |
- next_state_ = STATE_OPEN; |
- return OK; |
- |
- case 302: // Found / Moved Temporarily |
- // Try to return a sanitized response so we can follow auth redirects. |
- // If we can't, fail the tunnel connection. |
- if (!SanitizeProxyRedirect(&response_)) { |
- LogBlockedTunnelResponse(); |
- return ERR_TUNNEL_CONNECTION_FAILED; |
- } |
- |
- redirect_has_load_timing_info_ = |
- spdy_stream_->GetLoadTimingInfo(&redirect_load_timing_info_); |
- // Note that this triggers a RST_STREAM_CANCEL. |
- spdy_stream_->DetachDelegate(); |
- next_state_ = STATE_DISCONNECTED; |
- return ERR_HTTPS_PROXY_TUNNEL_RESPONSE; |
- |
- case 407: // Proxy Authentication Required |
- next_state_ = STATE_OPEN; |
- if (!SanitizeProxyAuth(&response_)) { |
- LogBlockedTunnelResponse(); |
- return ERR_TUNNEL_CONNECTION_FAILED; |
- } |
- return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_); |
- |
- default: |
- // Ignore response to avoid letting the proxy impersonate the target |
- // server. (See http://crbug.com/137891.) |
- LogBlockedTunnelResponse(); |
- return ERR_TUNNEL_CONNECTION_FAILED; |
- } |
-} |
- |
-// SpdyStream::Delegate methods: |
-// Called when SYN frame has been sent. |
-// Returns true if no more data to be sent after SYN frame. |
-void SpdyProxyClientSocket::OnRequestHeadersSent() { |
- DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE); |
- |
- OnIOComplete(OK); |
-} |
- |
-SpdyResponseHeadersStatus SpdyProxyClientSocket::OnResponseHeadersUpdated( |
- const SpdyHeaderBlock& response_headers) { |
- // 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. |
- if (next_state_ != STATE_READ_REPLY_COMPLETE) |
- return RESPONSE_HEADERS_ARE_COMPLETE; |
- |
- // Save the response |
- if (!SpdyHeadersToHttpResponse( |
- response_headers, spdy_stream_->GetProtocolVersion(), &response_)) |
- return RESPONSE_HEADERS_ARE_INCOMPLETE; |
- |
- OnIOComplete(OK); |
- return RESPONSE_HEADERS_ARE_COMPLETE; |
-} |
- |
-// Called when data is received or on EOF (if |buffer| is NULL). |
-void SpdyProxyClientSocket::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) { |
- if (buffer) { |
- net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, |
- buffer->GetRemainingSize(), |
- buffer->GetRemainingData()); |
- read_buffer_queue_.Enqueue(buffer.Pass()); |
- } else { |
- net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, 0, NULL); |
- } |
- |
- if (!read_callback_.is_null()) { |
- int rv = PopulateUserReadBuffer(user_buffer_->data(), user_buffer_len_); |
- CompletionCallback c = read_callback_; |
- read_callback_.Reset(); |
- user_buffer_ = NULL; |
- user_buffer_len_ = 0; |
- c.Run(rv); |
- } |
-} |
- |
-void SpdyProxyClientSocket::OnDataSent() { |
- DCHECK(!write_callback_.is_null()); |
- |
- int rv = write_buffer_len_; |
- write_buffer_len_ = 0; |
- |
- // Proxy write callbacks result in deep callback chains. Post to allow the |
- // stream's write callback chain to unwind (see crbug.com/355511). |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&SpdyProxyClientSocket::RunCallback, |
- write_callback_weak_factory_.GetWeakPtr(), |
- ResetAndReturn(&write_callback_), |
- rv)); |
-} |
- |
-void SpdyProxyClientSocket::OnClose(int status) { |
- was_ever_used_ = spdy_stream_->WasEverUsed(); |
- spdy_stream_.reset(); |
- |
- bool connecting = next_state_ != STATE_DISCONNECTED && |
- next_state_ < STATE_OPEN; |
- if (next_state_ == STATE_OPEN) |
- next_state_ = STATE_CLOSED; |
- else |
- next_state_ = STATE_DISCONNECTED; |
- |
- base::WeakPtr<SpdyProxyClientSocket> weak_ptr = weak_factory_.GetWeakPtr(); |
- CompletionCallback write_callback = write_callback_; |
- write_callback_.Reset(); |
- write_buffer_len_ = 0; |
- |
- // If we're in the middle of connecting, we need to make sure |
- // we invoke the connect callback. |
- if (connecting) { |
- DCHECK(!read_callback_.is_null()); |
- CompletionCallback read_callback = read_callback_; |
- read_callback_.Reset(); |
- read_callback.Run(status); |
- } else if (!read_callback_.is_null()) { |
- // If we have a read_callback_, the we need to make sure we call it back. |
- OnDataReceived(scoped_ptr<SpdyBuffer>()); |
- } |
- // This may have been deleted by read_callback_, so check first. |
- if (weak_ptr.get() && !write_callback.is_null()) |
- write_callback.Run(ERR_CONNECTION_CLOSED); |
-} |
- |
-} // namespace net |