http_proxy_client_socket.cc revision 94dee9037a31fbf43ed22eaa2a84fb4e7cd5569e
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
6594dee9037a31fbf43ed22eaa2a84fb4e7cd5569eKristian MonsenHttpStream* HttpProxyClientSocket::CreateConnectResponseStream() {
6694dee9037a31fbf43ed22eaa2a84fb4e7cd5569eKristian Monsen  return new HttpBasicStream(transport_.release(),
6794dee9037a31fbf43ed22eaa2a84fb4e7cd5569eKristian Monsen                             http_stream_parser_.release(), false);
6894dee9037a31fbf43ed22eaa2a84fb4e7cd5569eKristian Monsen}
6994dee9037a31fbf43ed22eaa2a84fb4e7cd5569eKristian Monsen
707b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
717b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen// TODO(kristianm): handle the case when wait_for_connect is true
727b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen// (sync requests)
737b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
747b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsenint HttpProxyClientSocket::Connect(CompletionCallback* callback
757b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
767b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                                   , bool wait_for_connect
777b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
787b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                                  ) {
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(transport_.get());
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(transport_->socket());
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!user_callback_);
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(rch): figure out the right way to set up a tunnel with SPDY.
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // This approach sends the complete HTTPS request to the proxy
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // which allows the proxy to see "private" data.  Instead, we should
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // create an SSL tunnel to the origin server using the CONNECT method
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // inside a single SPDY stream.
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (using_spdy_ || !tunnel_)
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    next_state_ = STATE_DONE;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (next_state_ == STATE_DONE)
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return OK;
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(STATE_NONE, next_state_);
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_GENERATE_AUTH_TOKEN;
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = DoLoop(OK);
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv == ERR_IO_PENDING)
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    user_callback_ = callback;
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::RestartWithAuth(CompletionCallback* callback) {
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(STATE_NONE, next_state_);
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!user_callback_);
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = PrepareForAuthRestart();
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv != OK)
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return rv;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = DoLoop(OK);
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv == ERR_IO_PENDING)
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    user_callback_ = callback;
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::PrepareForAuthRestart() {
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!response_.headers.get())
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_CONNECTION_RESET;
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool keep_alive = false;
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (response_.headers->IsKeepAlive() &&
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      http_stream_parser_->CanFindEndOfResponse()) {
1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!http_stream_parser_->IsResponseBodyComplete()) {
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      next_state_ = STATE_DRAIN_BODY;
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      drain_buf_ = new IOBuffer(kDrainBodyBufferSize);
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return OK;
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    keep_alive = true;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't need to drain the response body, so we act as if we had drained
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the response body.
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return DidDrainBodyForAuthRestart(keep_alive);
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) {
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (keep_alive && transport_->socket()->IsConnectedAndIdle()) {
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    next_state_ = STATE_GENERATE_AUTH_TOKEN;
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    transport_->set_is_reused(true);
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // This assumes that the underlying transport socket is a TCP socket,
1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // since only TCP sockets are restartable.
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    next_state_ = STATE_TCP_RESTART;
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    transport_->socket()->Disconnect();
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Reset the other member variables.
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drain_buf_ = NULL;
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  parser_buf_ = NULL;
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  http_stream_parser_.reset();
1514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  request_line_.clear();
1524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  request_headers_.Clear();
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_ = HttpResponseInfo();
1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return OK;
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const {
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LOG(WARNING) << "Blocked proxy response with status " << response_code
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << " to CONNECT request for "
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << GetHostAndPort(request_.url) << ".";
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HttpProxyClientSocket::Disconnect() {
16421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (transport_.get())
16521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    transport_->socket()->Disconnect();
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Reset other states to make sure they aren't mistakenly used later.
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // These are the states initialized by Connect().
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_NONE;
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  user_callback_ = NULL;
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpProxyClientSocket::IsConnected() const {
1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return next_state_ == STATE_DONE && transport_->socket()->IsConnected();
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpProxyClientSocket::IsConnectedAndIdle() const {
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return next_state_ == STATE_DONE &&
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    transport_->socket()->IsConnectedAndIdle();
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenconst BoundNetLog& HttpProxyClientSocket::NetLog() const {
18321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return net_log_;
18421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
18521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid HttpProxyClientSocket::SetSubresourceSpeculation() {
1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (transport_.get() && transport_->socket()) {
1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    transport_->socket()->SetSubresourceSpeculation();
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NOTREACHED();
1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid HttpProxyClientSocket::SetOmniboxSpeculation() {
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (transport_.get() && transport_->socket()) {
1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    transport_->socket()->SetOmniboxSpeculation();
1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NOTREACHED();
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool HttpProxyClientSocket::WasEverUsed() const {
2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (transport_.get() && transport_->socket()) {
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return transport_->socket()->WasEverUsed();
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NOTREACHED();
2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return false;
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
210513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool HttpProxyClientSocket::UsingTCPFastOpen() const {
211513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (transport_.get() && transport_->socket()) {
212513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return transport_->socket()->UsingTCPFastOpen();
213513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
214513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  NOTREACHED();
215513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return false;
216513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
217513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len,
2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                CompletionCallback* callback) {
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!user_callback_);
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (next_state_ != STATE_DONE) {
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We're trying to read the body of the response but we're still trying
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // to establish an SSL tunnel through the proxy.  We can't read these
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // bytes when establishing a tunnel because they might be controlled by
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // an active network attacker.  We don't worry about this for HTTP
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // because an active network attacker can already control HTTP sessions.
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We reach this case when the user cancels a 407 proxy auth prompt.
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // See http://crbug.com/8473.
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK_EQ(407, response_.headers->response_code());
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LogBlockedTunnelResponse(response_.headers->response_code());
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_TUNNEL_CONNECTION_FAILED;
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->Read(buf, buf_len, callback);
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len,
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 CompletionCallback* callback) {
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(STATE_DONE, next_state_);
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!user_callback_);
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->Write(buf, buf_len, callback);
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpProxyClientSocket::SetReceiveBufferSize(int32 size) {
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->SetReceiveBufferSize(size);
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpProxyClientSocket::SetSendBufferSize(int32 size) {
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->SetSendBufferSize(size);
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::GetPeerAddress(AddressList* address) const {
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->GetPeerAddress(address);
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HttpProxyClientSocket::DoCallback(int result) {
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(ERR_IO_PENDING, result);
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(user_callback_);
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Since Run() may result in Read being called,
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // clear user_callback_ up front.
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CompletionCallback* c = user_callback_;
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  user_callback_ = NULL;
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  c->Run(result);
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HttpProxyClientSocket::OnIOComplete(int result) {
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(STATE_NONE, next_state_);
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(STATE_DONE, next_state_);
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = DoLoop(result);
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv != ERR_IO_PENDING)
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DoCallback(rv);
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoLoop(int last_io_result) {
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(next_state_, STATE_NONE);
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(next_state_, STATE_DONE);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = last_io_result;
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  do {
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    State state = next_state_;
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    next_state_ = STATE_NONE;
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (state) {
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_GENERATE_AUTH_TOKEN:
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(OK, rv);
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoGenerateAuthToken();
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoGenerateAuthTokenComplete(rv);
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_SEND_REQUEST:
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(OK, rv);
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST,
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            NULL);
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoSendRequest();
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_SEND_REQUEST_COMPLETE:
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoSendRequestComplete(rv);
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST,
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          NULL);
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_READ_HEADERS:
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(OK, rv);
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS,
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            NULL);
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoReadHeaders();
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_READ_HEADERS_COMPLETE:
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoReadHeadersComplete(rv);
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS,
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          NULL);
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_DRAIN_BODY:
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(OK, rv);
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoDrainBody();
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_DRAIN_BODY_COMPLETE:
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoDrainBodyComplete(rv);
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
3213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      case STATE_TCP_RESTART:
3223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        DCHECK_EQ(OK, rv);
3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        rv = DoTCPRestart();
3243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        break;
3253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      case STATE_TCP_RESTART_COMPLETE:
3263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        rv = DoTCPRestartComplete(rv);
3273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        break;
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_DONE:
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED() << "bad state";
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = ERR_UNEXPECTED;
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
3353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
3363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick           next_state_ != STATE_DONE);
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoGenerateAuthToken() {
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return auth_->MaybeGenerateAuthToken(&request_, &io_callback_, net_log_);
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(ERR_IO_PENDING, result);
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result == OK)
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    next_state_ = STATE_SEND_REQUEST;
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoSendRequest() {
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_SEND_REQUEST_COMPLETE;
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This is constructed lazily (instead of within our Start method), so that
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we have proxy info available.
3574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (request_line_.empty()) {
3584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    DCHECK(request_headers_.IsEmpty());
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HttpRequestHeaders authorization_headers;
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (auth_->HaveAuth())
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      auth_->AddAuthorizationHeader(&authorization_headers);
362731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BuildTunnelRequest(request_, authorization_headers, endpoint_,
3634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                       &request_line_, &request_headers_);
364731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (net_log_.IsLoggingAllEvents()) {
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net_log_.AddEvent(
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
367513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          make_scoped_refptr(new NetLogHttpRequestParameter(
3684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch              request_line_, request_headers_)));
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  parser_buf_ = new GrowableIOBuffer();
3733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  http_stream_parser_.reset(
3743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      new HttpStreamParser(transport_.get(), &request_, parser_buf_, net_log_));
3754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return http_stream_parser_->SendRequest(request_line_, request_headers_, NULL,
3763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                          &response_, &io_callback_);
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoSendRequestComplete(int result) {
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result < 0)
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_READ_HEADERS;
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return OK;
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoReadHeaders() {
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_READ_HEADERS_COMPLETE;
3893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return http_stream_parser_->ReadResponseHeaders(&io_callback_);
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoReadHeadersComplete(int result) {
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result < 0)
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Require the "HTTP/1.x" status line for SSL CONNECT.
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_TUNNEL_CONNECTION_FAILED;
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
400731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (net_log_.IsLoggingAllEvents()) {
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net_log_.AddEvent(
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
403513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers)));
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (response_.headers->response_code()) {
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 200:  // OK
4083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (http_stream_parser_->IsMoreDataBuffered())
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // The proxy sent extraneous data after the headers.
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return ERR_TUNNEL_CONNECTION_FAILED;
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      next_state_ = STATE_DONE;
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return OK;
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We aren't able to CONNECT to the remote host through the proxy.  We
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // need to be very suspicious about the response because an active network
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // attacker can force us into this state by masquerading as the proxy.
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The only safe thing to do here is to fail the connection because our
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // client is expecting an SSL protected response.
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // See http://crbug.com/7338.
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 407:  // Proxy Authentication Required
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We need this status code to allow proxy authentication.  Our
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // authentication code is smart enough to avoid being tricked by an
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // active network attacker.
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The next state is intentionally not set as it should be STATE_NONE;
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return HandleAuthChallenge();
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
42921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (is_https_proxy_)
43021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // For all other status codes, we conservatively fail the CONNECT
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // request.
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We lose something by doing this.  We have seen proxy 403, 404, and
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // 501 response bodies that contain a useful error message.  For
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // example, Squid uses a 404 response to report the DNS error: "The
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // domain name does not exist."
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LogBlockedTunnelResponse(response_.headers->response_code());
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ERR_TUNNEL_CONNECTION_FAILED;
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoDrainBody() {
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(drain_buf_);
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(transport_->is_initialized());
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_DRAIN_BODY_COMPLETE;
4463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return http_stream_parser_->ReadResponseBody(drain_buf_, kDrainBodyBufferSize,
4473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                               &io_callback_);
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoDrainBodyComplete(int result) {
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result < 0)
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (http_stream_parser_->IsResponseBodyComplete())
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DidDrainBodyForAuthRestart(true);
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Keep draining.
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_DRAIN_BODY;
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return OK;
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4627b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
4637b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen// TODO(kristianm): Check if we can find out if Connect should block
4647b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
4653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint HttpProxyClientSocket::DoTCPRestart() {
4663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  next_state_ = STATE_TCP_RESTART_COMPLETE;
4677b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen  return transport_->socket()->Connect(&io_callback_
4687b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
4697b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                                       , false
4707b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
4717b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                                      );
4723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint HttpProxyClientSocket::DoTCPRestartComplete(int result) {
4753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (result != OK)
4763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return result;
4773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  next_state_ = STATE_GENERATE_AUTH_TOKEN;
4793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return result;
4803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::HandleAuthChallenge() {
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(response_.headers);
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = auth_->HandleAuthChallenge(response_.headers, false, true, net_log_);
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_.auth_challenge = auth_->auth_info();
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv == OK)
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_PROXY_AUTH_REQUESTED;
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace net
494