15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_proxy_client_socket.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> // min 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/callback_helpers.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 135e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/auth.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_cache.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_handler_factory.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_response_headers.h" 21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/http/proxy_connect_redirect_http_stream.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_http_utils.h" 237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpdyProxyClientSocket::SpdyProxyClientSocket( 28a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const base::WeakPtr<SpdyStream>& spdy_stream, 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& user_agent, 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HostPortPair& endpoint, 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& url, 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HostPortPair& proxy_server, 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const BoundNetLog& source_net_log, 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuthCache* auth_cache, 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpAuthHandlerFactory* auth_handler_factory) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : next_state_(STATE_DISCONNECTED), 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spdy_stream_(spdy_stream), 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) endpoint_(endpoint), 39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) auth_(new HttpAuthController(HttpAuth::AUTH_PROXY, 40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) GURL("https://" + proxy_server.ToString()), 41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) auth_cache, 42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) auth_handler_factory)), 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_buffer_len_(0), 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buffer_len_(0), 45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch was_ever_used_(false), 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch redirect_has_load_timing_info_(false), 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net_log_(BoundNetLog::Make(spdy_stream->net_log().net_log(), 48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NetLog::SOURCE_PROXY_CLIENT_SOCKET)), 49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) weak_factory_(this), 50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) write_callback_weak_factory_(this) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_.method = "CONNECT"; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_.url = url; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!user_agent.empty()) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_agent); 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) source_net_log.source().ToEventParametersCallback()); 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net_log_.AddEvent( 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NetLog::TYPE_SPDY_PROXY_CLIENT_SESSION, 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) spdy_stream->net_log().source().ToEventParametersCallback()); 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spdy_stream_->SetDelegate(this); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was_ever_used_ = spdy_stream_->WasEverUsed(); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpdyProxyClientSocket::~SpdyProxyClientSocket() { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Disconnect(); 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const HttpResponseInfo* SpdyProxyClientSocket::GetConnectResponseInfo() const { 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return response_.headers.get() ? &response_ : NULL; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const scoped_refptr<HttpAuthController>& 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpdyProxyClientSocket::GetAuthController() const { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return auth_; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdyProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A SPDY Stream can only handle a single request, so the underlying 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // stream may not be reused and a new SpdyProxyClientSocket must be 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // created (possibly on top of the same SPDY Session). 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DISCONNECTED; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdyProxyClientSocket::IsUsingSpdy() const { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NextProto SpdyProxyClientSocket::GetProtocolNegotiated() const { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Save the negotiated protocol 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSLInfo ssl_info; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool was_npn_negotiated; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NextProto protocol_negotiated; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spdy_stream_->GetSSLInfo(&ssl_info, &was_npn_negotiated, 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &protocol_negotiated); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return protocol_negotiated; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() { 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return new ProxyConnectRedirectHttpStream( 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch redirect_has_load_timing_info_ ? &redirect_load_timing_info_ : NULL); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sends a SYN_STREAM frame to the proxy with a CONNECT request 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for the specified endpoint. Waits for the server to send back 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a SYN_REPLY frame. OK will be returned if the status is 200. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In any of these cases, Read() may be called to retrieve the HTTP 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// response body. Any other return values should be considered fatal. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(rch): handle 407 proxy auth requested correctly, perhaps 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// by creating a new stream for the subsequent request. 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(rch): create a more appropriate error code to disambiguate 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the HTTPS Proxy tunnel failure from an HTTP Proxy tunnel failure. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdyProxyClientSocket::Connect(const CompletionCallback& callback) { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(read_callback_.is_null()); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_state_ == STATE_OPEN) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(STATE_DISCONNECTED, next_state_); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_GENERATE_AUTH_TOKEN; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = DoLoop(OK); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv == ERR_IO_PENDING) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_callback_ = callback; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdyProxyClientSocket::Disconnect() { 133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) read_buffer_queue_.Clear(); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_buffer_ = NULL; 135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_buffer_len_ = 0; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_callback_.Reset(); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buffer_len_ = 0; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_callback_.Reset(); 140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) write_callback_weak_factory_.InvalidateWeakPtrs(); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DISCONNECTED; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (spdy_stream_.get()) { 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will cause OnClose to be invoked, which takes care of 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // cleaning up all the internal state. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spdy_stream_->Cancel(); 148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!spdy_stream_.get()); 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdyProxyClientSocket::IsConnected() const { 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return next_state_ == STATE_OPEN; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdyProxyClientSocket::IsConnectedAndIdle() const { 157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return IsConnected() && read_buffer_queue_.IsEmpty() && 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) spdy_stream_->IsOpen(); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BoundNetLog& SpdyProxyClientSocket::NetLog() const { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return net_log_; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdyProxyClientSocket::SetSubresourceSpeculation() { 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(rch): what should this implementation be? 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdyProxyClientSocket::SetOmniboxSpeculation() { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(rch): what should this implementation be? 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdyProxyClientSocket::WasEverUsed() const { 174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return was_ever_used_ || (spdy_stream_.get() && spdy_stream_->WasEverUsed()); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdyProxyClientSocket::UsingTCPFastOpen() const { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdyProxyClientSocket::WasNpnNegotiated() const { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NextProto SpdyProxyClientSocket::GetNegotiatedProtocol() const { 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return kProtoUnknown; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdyProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool was_npn_negotiated; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NextProto protocol_negotiated; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return spdy_stream_->GetSSLInfo(ssl_info, &was_npn_negotiated, 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &protocol_negotiated); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len, 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback) { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(read_callback_.is_null()); 199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!user_buffer_.get()); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_state_ == STATE_DISCONNECTED) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_SOCKET_NOT_CONNECTED; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (next_state_ == STATE_CLOSED && read_buffer_queue_.IsEmpty()) { 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(next_state_ == STATE_OPEN || next_state_ == STATE_CLOSED); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(buf); 210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t result = PopulateUserReadBuffer(buf->data(), buf_len); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == 0) { 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_buffer_ = buf; 213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_buffer_len_ = static_cast<size_t>(buf_len); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!callback.is_null()); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_callback_ = callback; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_IO_PENDING; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_buffer_ = NULL; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)size_t SpdyProxyClientSocket::PopulateUserReadBuffer(char* data, size_t len) { 223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return read_buffer_queue_.Dequeue(data, len); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdyProxyClientSocket::Write(IOBuffer* buf, int buf_len, 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(write_callback_.is_null()); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_state_ != STATE_OPEN) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_SOCKET_NOT_CONNECTED; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 232868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(spdy_stream_.get()); 23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) spdy_stream_->SendData(buf, buf_len, MORE_DATA_TO_SEND); 23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, 23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) buf_len, buf->data()); 23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) write_callback_ = callback; 23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) write_buffer_len_ = buf_len; 23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return ERR_IO_PENDING; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 241c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochint SpdyProxyClientSocket::SetReceiveBufferSize(int32 size) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since this StreamSocket sits on top of a shared SpdySession, it 243c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // is not safe for callers to change this underlying socket. 244c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return ERR_NOT_IMPLEMENTED; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 247c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochint SpdyProxyClientSocket::SetSendBufferSize(int32 size) { 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since this StreamSocket sits on top of a shared SpdySession, it 249c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // is not safe for callers to change this underlying socket. 250c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return ERR_NOT_IMPLEMENTED; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdyProxyClientSocket::GetPeerAddress(IPEndPoint* address) const { 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsConnected()) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_SOCKET_NOT_CONNECTED; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return spdy_stream_->GetPeerAddress(address); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdyProxyClientSocket::GetLocalAddress(IPEndPoint* address) const { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsConnected()) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_SOCKET_NOT_CONNECTED; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return spdy_stream_->GetLocalAddress(address); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdyProxyClientSocket::LogBlockedTunnelResponse() const { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyClientSocket::LogBlockedTunnelResponse( 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.headers->response_code(), 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_.url, 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* is_https_proxy = */ true); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SpdyProxyClientSocket::RunCallback(const CompletionCallback& callback, 273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int result) const { 274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) callback.Run(result); 275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdyProxyClientSocket::OnIOComplete(int result) { 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(STATE_DISCONNECTED, next_state_); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = DoLoop(result); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv != ERR_IO_PENDING) { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CompletionCallback c = read_callback_; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_callback_.Reset(); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c.Run(rv); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdyProxyClientSocket::DoLoop(int last_io_result) { 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(next_state_, STATE_DISCONNECTED); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = last_io_result; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) State state = next_state_; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DISCONNECTED; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (state) { 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_GENERATE_AUTH_TOKEN: 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(OK, rv); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoGenerateAuthToken(); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_GENERATE_AUTH_TOKEN_COMPLETE: 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoGenerateAuthTokenComplete(rv); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_SEND_REQUEST: 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(OK, rv); 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoSendRequest(); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_SEND_REQUEST_COMPLETE: 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.EndEventWithNetErrorCode( 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoSendRequestComplete(rv); 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (rv >= 0 || rv == ERR_IO_PENDING) { 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Emit extra event so can use the same events as 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // HttpProxyClientSocket. 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net_log_.BeginEvent( 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS); 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_READ_REPLY_COMPLETE: 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoReadReplyComplete(rv); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.EndEventWithNetErrorCode( 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "bad state"; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ERR_UNEXPECTED; 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED && 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ != STATE_OPEN); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdyProxyClientSocket::DoGenerateAuthToken() { 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return auth_->MaybeGenerateAuthToken( 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &request_, 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&SpdyProxyClientSocket::OnIOComplete, 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) weak_factory_.GetWeakPtr()), 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdyProxyClientSocket::DoGenerateAuthTokenComplete(int result) { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(ERR_IO_PENDING, result); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == OK) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_SEND_REQUEST; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdyProxyClientSocket::DoSendRequest() { 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_SEND_REQUEST_COMPLETE; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add Proxy-Authentication header if necessary. 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpRequestHeaders authorization_headers; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (auth_->HaveAuth()) { 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth_->AddAuthorizationHeader(&authorization_headers); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string request_line; 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpRequestHeaders request_headers; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BuildTunnelRequest(request_, authorization_headers, endpoint_, &request_line, 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &request_headers); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.AddEvent( 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&HttpRequestHeaders::NetLogCallback, 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(&request_headers), 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &request_line)); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_.extra_headers.MergeFrom(request_headers); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock()); 370116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch CreateSpdyHeadersFromHttpRequest(request_, request_headers, 371116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch spdy_stream_->GetProtocolVersion(), true, 372116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch headers.get()); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reset the URL to be the endpoint of the connection 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (spdy_stream_->GetProtocolVersion() > 2) { 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*headers)[":path"] = endpoint_.ToString(); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->erase(":scheme"); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*headers)["url"] = endpoint_.ToString(); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->erase("scheme"); 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return spdy_stream_->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdyProxyClientSocket::DoSendRequestComplete(int result) { 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result < 0) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wait for SYN_REPLY frame from the server 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_READ_REPLY_COMPLETE; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_IO_PENDING; 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdyProxyClientSocket::DoReadReplyComplete(int result) { 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We enter this method directly from DoSendRequestComplete, since 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we are notified by a callback when the SYN_REPLY frame arrives 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result < 0) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Require the "HTTP/1.x" status line for SSL CONNECT. 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_TUNNEL_CONNECTION_FAILED; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.AddEvent( 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers)); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (response_.headers->response_code()) { 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 200: // OK 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_OPEN; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 302: // Found / Moved Temporarily 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to return a sanitized response so we can follow auth redirects. 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we can't, fail the tunnel connection. 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SanitizeProxyRedirect(&response_, request_.url)) { 418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch redirect_has_load_timing_info_ = 419eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch spdy_stream_->GetLoadTimingInfo(&redirect_load_timing_info_); 420cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Note that this triggers a RST_STREAM_CANCEL. 421eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch spdy_stream_->DetachDelegate(); 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DISCONNECTED; 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_HTTPS_PROXY_TUNNEL_RESPONSE; 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LogBlockedTunnelResponse(); 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_TUNNEL_CONNECTION_FAILED; 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 407: // Proxy Authentication Required 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_OPEN; 431868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore response to avoid letting the proxy impersonate the target 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // server. (See http://crbug.com/137891.) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LogBlockedTunnelResponse(); 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_TUNNEL_CONNECTION_FAILED; 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SpdyStream::Delegate methods: 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called when SYN frame has been sent. 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if no more data to be sent after SYN frame. 44490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SpdyProxyClientSocket::OnRequestHeadersSent() { 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE); 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OnIOComplete(OK); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 450eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdyResponseHeadersStatus SpdyProxyClientSocket::OnResponseHeadersUpdated( 451eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const SpdyHeaderBlock& response_headers) { 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we've already received the reply, existing headers are too late. 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(mbelshe): figure out a way to make HEADERS frames useful after the 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // initial response. 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_state_ != STATE_READ_REPLY_COMPLETE) 456eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return RESPONSE_HEADERS_ARE_COMPLETE; 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Save the response 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!SpdyHeadersToHttpResponse( 460eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch response_headers, spdy_stream_->GetProtocolVersion(), &response_)) 461eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return RESPONSE_HEADERS_ARE_INCOMPLETE; 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 463eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch OnIOComplete(OK); 464eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return RESPONSE_HEADERS_ARE_COMPLETE; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Called when data is received or on EOF (if |buffer| is NULL). 468eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SpdyProxyClientSocket::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) { 469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (buffer) { 470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, 471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) buffer->GetRemainingSize(), 472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) buffer->GetRemainingData()); 473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) read_buffer_queue_.Enqueue(buffer.Pass()); 474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, 0, NULL); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!read_callback_.is_null()) { 479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int rv = PopulateUserReadBuffer(user_buffer_->data(), user_buffer_len_); 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CompletionCallback c = read_callback_; 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_callback_.Reset(); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_buffer_ = NULL; 483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_buffer_len_ = 0; 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c.Run(rv); 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 48890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SpdyProxyClientSocket::OnDataSent() { 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!write_callback_.is_null()); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 49190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int rv = write_buffer_len_; 49290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) write_buffer_len_ = 0; 493c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 494c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Proxy write callbacks result in deep callback chains. Post to allow the 495c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // stream's write callback chain to unwind (see crbug.com/355511). 496c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::MessageLoop::current()->PostTask( 497c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch FROM_HERE, 498f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&SpdyProxyClientSocket::RunCallback, 499f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) write_callback_weak_factory_.GetWeakPtr(), 500f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ResetAndReturn(&write_callback_), 501f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) rv)); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdyProxyClientSocket::OnClose(int status) { 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was_ever_used_ = spdy_stream_->WasEverUsed(); 506a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) spdy_stream_.reset(); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool connecting = next_state_ != STATE_DISCONNECTED && 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ < STATE_OPEN; 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_state_ == STATE_OPEN) 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CLOSED; 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DISCONNECTED; 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WeakPtr<SpdyProxyClientSocket> weak_ptr = weak_factory_.GetWeakPtr(); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CompletionCallback write_callback = write_callback_; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_callback_.Reset(); 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buffer_len_ = 0; 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we're in the middle of connecting, we need to make sure 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we invoke the connect callback. 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (connecting) { 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!read_callback_.is_null()); 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CompletionCallback read_callback = read_callback_; 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_callback_.Reset(); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_callback.Run(status); 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!read_callback_.is_null()) { 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have a read_callback_, the we need to make sure we call it back. 529c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OnDataReceived(scoped_ptr<SpdyBuffer>()); 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This may have been deleted by read_callback_, so check first. 532868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (weak_ptr.get() && !write_callback.is_null()) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_callback.Run(ERR_CONNECTION_CLOSED); 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 537