http_proxy_client_socket.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_proxy_client_socket.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stringprintf.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/base/auth.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/host_port_pair.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/io_buffer.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_log.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_util.h"
1521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "net/http/http_basic_stream.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_net_log_params.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_network_session.h"
18731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "net/http/http_proxy_utils.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_request_info.h"
20731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "net/http/http_response_headers.h"
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/http/http_stream_parser.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/socket/client_socket_handle.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace net {
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochHttpProxyClientSocket::HttpProxyClientSocket(
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ClientSocketHandle* transport_socket,
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const GURL& request_url,
293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const std::string& user_agent,
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const HostPortPair& endpoint,
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const HostPortPair& proxy_server,
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    HttpAuthCache* http_auth_cache,
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    HttpAuthHandlerFactory* http_auth_handler_factory,
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    bool tunnel,
3521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    bool using_spdy,
3621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    bool is_https_proxy)
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : ALLOW_THIS_IN_INITIALIZER_LIST(
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          io_callback_(this, &HttpProxyClientSocket::OnIOComplete)),
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      next_state_(STATE_NONE),
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      user_callback_(NULL),
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      transport_(transport_socket),
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      endpoint_(endpoint),
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      auth_(tunnel ?
443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          new HttpAuthController(HttpAuth::AUTH_PROXY,
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                 GURL("http://" + proxy_server.ToString()),
463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                 http_auth_cache,
473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                 http_auth_handler_factory)
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          : NULL),
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tunnel_(tunnel),
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      using_spdy_(using_spdy),
5121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      is_https_proxy_(is_https_proxy),
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net_log_(transport_socket->socket()->NetLog()) {
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Synthesize the bits of a request that we actually use.
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_.url = request_url;
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_.method = "GET";
563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!user_agent.empty())
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                     user_agent);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochHttpProxyClientSocket::~HttpProxyClientSocket() {
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Disconnect();
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
6572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint HttpProxyClientSocket::RestartWithAuth(CompletionCallback* callback) {
6672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK_EQ(STATE_NONE, next_state_);
6772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(!user_callback_);
6872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
6972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int rv = PrepareForAuthRestart();
7072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (rv != OK)
7172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return rv;
7272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
7372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  rv = DoLoop(OK);
7472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (rv == ERR_IO_PENDING)
7572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    user_callback_ = callback;
7672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return rv;
7772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
7872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
7972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const {
8072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return response_.headers ? &response_ : NULL;
8172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
8272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
8394dee9037a31fbf43ed22eaa2a84fb4e7cd5569eKristian MonsenHttpStream* HttpProxyClientSocket::CreateConnectResponseStream() {
8494dee9037a31fbf43ed22eaa2a84fb4e7cd5569eKristian Monsen  return new HttpBasicStream(transport_.release(),
8594dee9037a31fbf43ed22eaa2a84fb4e7cd5569eKristian Monsen                             http_stream_parser_.release(), false);
8694dee9037a31fbf43ed22eaa2a84fb4e7cd5569eKristian Monsen}
8794dee9037a31fbf43ed22eaa2a84fb4e7cd5569eKristian Monsen
887b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
897b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen// TODO(kristianm): handle the case when wait_for_connect is true
907b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen// (sync requests)
917b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
927b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsenint HttpProxyClientSocket::Connect(CompletionCallback* callback
937b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
947b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                                   , bool wait_for_connect
957b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
967b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                                  ) {
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(transport_.get());
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(transport_->socket());
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!user_callback_);
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(rch): figure out the right way to set up a tunnel with SPDY.
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // This approach sends the complete HTTPS request to the proxy
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // which allows the proxy to see "private" data.  Instead, we should
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // create an SSL tunnel to the origin server using the CONNECT method
1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // inside a single SPDY stream.
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (using_spdy_ || !tunnel_)
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    next_state_ = STATE_DONE;
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (next_state_ == STATE_DONE)
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return OK;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(STATE_NONE, next_state_);
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_GENERATE_AUTH_TOKEN;
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = DoLoop(OK);
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv == ERR_IO_PENDING)
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    user_callback_ = callback;
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HttpProxyClientSocket::Disconnect() {
12121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (transport_.get())
12221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    transport_->socket()->Disconnect();
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Reset other states to make sure they aren't mistakenly used later.
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // These are the states initialized by Connect().
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_NONE;
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  user_callback_ = NULL;
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpProxyClientSocket::IsConnected() const {
1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return next_state_ == STATE_DONE && transport_->socket()->IsConnected();
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpProxyClientSocket::IsConnectedAndIdle() const {
1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return next_state_ == STATE_DONE &&
1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    transport_->socket()->IsConnectedAndIdle();
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
13921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenconst BoundNetLog& HttpProxyClientSocket::NetLog() const {
14021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return net_log_;
14121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
14221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid HttpProxyClientSocket::SetSubresourceSpeculation() {
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (transport_.get() && transport_->socket()) {
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    transport_->socket()->SetSubresourceSpeculation();
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NOTREACHED();
1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid HttpProxyClientSocket::SetOmniboxSpeculation() {
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (transport_.get() && transport_->socket()) {
1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    transport_->socket()->SetOmniboxSpeculation();
1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NOTREACHED();
1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool HttpProxyClientSocket::WasEverUsed() const {
1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (transport_.get() && transport_->socket()) {
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return transport_->socket()->WasEverUsed();
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NOTREACHED();
1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return false;
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
167513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool HttpProxyClientSocket::UsingTCPFastOpen() const {
168513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (transport_.get() && transport_->socket()) {
169513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return transport_->socket()->UsingTCPFastOpen();
170513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
171513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  NOTREACHED();
172513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return false;
173513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
174513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len,
1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                CompletionCallback* callback) {
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!user_callback_);
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (next_state_ != STATE_DONE) {
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We're trying to read the body of the response but we're still trying
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // to establish an SSL tunnel through the proxy.  We can't read these
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // bytes when establishing a tunnel because they might be controlled by
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // an active network attacker.  We don't worry about this for HTTP
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // because an active network attacker can already control HTTP sessions.
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We reach this case when the user cancels a 407 proxy auth prompt.
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // See http://crbug.com/8473.
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK_EQ(407, response_.headers->response_code());
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LogBlockedTunnelResponse(response_.headers->response_code());
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_TUNNEL_CONNECTION_FAILED;
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->Read(buf, buf_len, callback);
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len,
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 CompletionCallback* callback) {
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(STATE_DONE, next_state_);
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!user_callback_);
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->Write(buf, buf_len, callback);
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpProxyClientSocket::SetReceiveBufferSize(int32 size) {
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->SetReceiveBufferSize(size);
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpProxyClientSocket::SetSendBufferSize(int32 size) {
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->SetSendBufferSize(size);
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::GetPeerAddress(AddressList* address) const {
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->GetPeerAddress(address);
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
21572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint HttpProxyClientSocket::PrepareForAuthRestart() {
21672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!response_.headers.get())
21772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return ERR_CONNECTION_RESET;
21872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
21972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  bool keep_alive = false;
22072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (response_.headers->IsKeepAlive() &&
22172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      http_stream_parser_->CanFindEndOfResponse()) {
22272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!http_stream_parser_->IsResponseBodyComplete()) {
22372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      next_state_ = STATE_DRAIN_BODY;
22472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      drain_buf_ = new IOBuffer(kDrainBodyBufferSize);
22572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return OK;
22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
22772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    keep_alive = true;
22872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
22972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
23072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // We don't need to drain the response body, so we act as if we had drained
23172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // the response body.
23272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return DidDrainBodyForAuthRestart(keep_alive);
23372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
23472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) {
23672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (keep_alive && transport_->socket()->IsConnectedAndIdle()) {
23772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    next_state_ = STATE_GENERATE_AUTH_TOKEN;
23872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    transport_->set_is_reused(true);
23972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
24072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // This assumes that the underlying transport socket is a TCP socket,
24172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // since only TCP sockets are restartable.
24272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    next_state_ = STATE_TCP_RESTART;
24372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    transport_->socket()->Disconnect();
24472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
24572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
24672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Reset the other member variables.
24772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  drain_buf_ = NULL;
24872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  parser_buf_ = NULL;
24972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  http_stream_parser_.reset();
25072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  request_line_.clear();
25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  request_headers_.Clear();
25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  response_ = HttpResponseInfo();
25372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return OK;
25472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
25672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint HttpProxyClientSocket::HandleAuthChallenge() {
25772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(response_.headers);
25872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int rv = auth_->HandleAuthChallenge(response_.headers, false, true, net_log_);
26072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  response_.auth_challenge = auth_->auth_info();
26172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (rv == OK)
26272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return ERR_PROXY_AUTH_REQUESTED;
26372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
26472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return rv;
26572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
26672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
26772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const {
26872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  LOG(WARNING) << "Blocked proxy response with status " << response_code
26972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen               << " to CONNECT request for "
27072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen               << GetHostAndPort(request_.url) << ".";
27172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
27272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HttpProxyClientSocket::DoCallback(int result) {
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(ERR_IO_PENDING, result);
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(user_callback_);
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Since Run() may result in Read being called,
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // clear user_callback_ up front.
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CompletionCallback* c = user_callback_;
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  user_callback_ = NULL;
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  c->Run(result);
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HttpProxyClientSocket::OnIOComplete(int result) {
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(STATE_NONE, next_state_);
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(STATE_DONE, next_state_);
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = DoLoop(result);
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv != ERR_IO_PENDING)
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DoCallback(rv);
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoLoop(int last_io_result) {
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(next_state_, STATE_NONE);
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(next_state_, STATE_DONE);
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = last_io_result;
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  do {
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    State state = next_state_;
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    next_state_ = STATE_NONE;
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (state) {
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_GENERATE_AUTH_TOKEN:
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(OK, rv);
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoGenerateAuthToken();
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoGenerateAuthTokenComplete(rv);
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_SEND_REQUEST:
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(OK, rv);
30972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        net_log_.BeginEvent(
31072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, NULL);
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoSendRequest();
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_SEND_REQUEST_COMPLETE:
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoSendRequestComplete(rv);
31572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        net_log_.EndEventWithNetErrorCode(
31672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_READ_HEADERS:
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(OK, rv);
32072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        net_log_.BeginEvent(
32172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, NULL);
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoReadHeaders();
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_READ_HEADERS_COMPLETE:
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoReadHeadersComplete(rv);
32672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        net_log_.EndEventWithNetErrorCode(
32772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_DRAIN_BODY:
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(OK, rv);
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoDrainBody();
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_DRAIN_BODY_COMPLETE:
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoDrainBodyComplete(rv);
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
3363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      case STATE_TCP_RESTART:
3373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        DCHECK_EQ(OK, rv);
3383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        rv = DoTCPRestart();
3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        break;
3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      case STATE_TCP_RESTART_COMPLETE:
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        rv = DoTCPRestartComplete(rv);
3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        break;
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_DONE:
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED() << "bad state";
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = ERR_UNEXPECTED;
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick           next_state_ != STATE_DONE);
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoGenerateAuthToken() {
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return auth_->MaybeGenerateAuthToken(&request_, &io_callback_, net_log_);
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(ERR_IO_PENDING, result);
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result == OK)
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    next_state_ = STATE_SEND_REQUEST;
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoSendRequest() {
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_SEND_REQUEST_COMPLETE;
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This is constructed lazily (instead of within our Start method), so that
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we have proxy info available.
3724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (request_line_.empty()) {
3734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    DCHECK(request_headers_.IsEmpty());
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HttpRequestHeaders authorization_headers;
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (auth_->HaveAuth())
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      auth_->AddAuthorizationHeader(&authorization_headers);
377731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BuildTunnelRequest(request_, authorization_headers, endpoint_,
3784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                       &request_line_, &request_headers_);
379731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (net_log_.IsLoggingAllEvents()) {
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net_log_.AddEvent(
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
382513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          make_scoped_refptr(new NetLogHttpRequestParameter(
3834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch              request_line_, request_headers_)));
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  parser_buf_ = new GrowableIOBuffer();
3883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  http_stream_parser_.reset(
3893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      new HttpStreamParser(transport_.get(), &request_, parser_buf_, net_log_));
3904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return http_stream_parser_->SendRequest(request_line_, request_headers_, NULL,
3913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                          &response_, &io_callback_);
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoSendRequestComplete(int result) {
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result < 0)
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_READ_HEADERS;
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return OK;
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoReadHeaders() {
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_READ_HEADERS_COMPLETE;
4043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return http_stream_parser_->ReadResponseHeaders(&io_callback_);
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoReadHeadersComplete(int result) {
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result < 0)
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Require the "HTTP/1.x" status line for SSL CONNECT.
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_TUNNEL_CONNECTION_FAILED;
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
415731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (net_log_.IsLoggingAllEvents()) {
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net_log_.AddEvent(
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
418513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers)));
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (response_.headers->response_code()) {
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 200:  // OK
4233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (http_stream_parser_->IsMoreDataBuffered())
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // The proxy sent extraneous data after the headers.
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return ERR_TUNNEL_CONNECTION_FAILED;
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      next_state_ = STATE_DONE;
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return OK;
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We aren't able to CONNECT to the remote host through the proxy.  We
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // need to be very suspicious about the response because an active network
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // attacker can force us into this state by masquerading as the proxy.
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The only safe thing to do here is to fail the connection because our
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // client is expecting an SSL protected response.
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // See http://crbug.com/7338.
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 407:  // Proxy Authentication Required
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We need this status code to allow proxy authentication.  Our
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // authentication code is smart enough to avoid being tricked by an
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // active network attacker.
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The next state is intentionally not set as it should be STATE_NONE;
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return HandleAuthChallenge();
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
44421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (is_https_proxy_)
44521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // For all other status codes, we conservatively fail the CONNECT
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // request.
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We lose something by doing this.  We have seen proxy 403, 404, and
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // 501 response bodies that contain a useful error message.  For
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // example, Squid uses a 404 response to report the DNS error: "The
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // domain name does not exist."
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LogBlockedTunnelResponse(response_.headers->response_code());
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ERR_TUNNEL_CONNECTION_FAILED;
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoDrainBody() {
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(drain_buf_);
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(transport_->is_initialized());
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_DRAIN_BODY_COMPLETE;
4613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return http_stream_parser_->ReadResponseBody(drain_buf_, kDrainBodyBufferSize,
4623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                               &io_callback_);
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoDrainBodyComplete(int result) {
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result < 0)
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (http_stream_parser_->IsResponseBodyComplete())
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DidDrainBodyForAuthRestart(true);
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Keep draining.
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_DRAIN_BODY;
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return OK;
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4777b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
4787b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen// TODO(kristianm): Check if we can find out if Connect should block
4797b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
4803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint HttpProxyClientSocket::DoTCPRestart() {
4813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  next_state_ = STATE_TCP_RESTART_COMPLETE;
4827b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen  return transport_->socket()->Connect(&io_callback_
4837b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
4847b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                                       , false
4857b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
4867b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                                      );
4873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint HttpProxyClientSocket::DoTCPRestartComplete(int result) {
4903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (result != OK)
4913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return result;
4923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  next_state_ = STATE_GENERATE_AUTH_TOKEN;
4943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return result;
4953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace net
498