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
95e14dcc5a172cad1c4716af7ab94121a73c0c698eAshish Sharma                                   , bool valid_uid
96e14dcc5a172cad1c4716af7ab94121a73c0c698eAshish Sharma                                   , uid_t calling_uid
977b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
987b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                                  ) {
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(transport_.get());
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(transport_->socket());
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!user_callback_);
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(rch): figure out the right way to set up a tunnel with SPDY.
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // This approach sends the complete HTTPS request to the proxy
1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // which allows the proxy to see "private" data.  Instead, we should
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // create an SSL tunnel to the origin server using the CONNECT method
1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // inside a single SPDY stream.
1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (using_spdy_ || !tunnel_)
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    next_state_ = STATE_DONE;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (next_state_ == STATE_DONE)
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return OK;
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(STATE_NONE, next_state_);
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_GENERATE_AUTH_TOKEN;
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = DoLoop(OK);
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv == ERR_IO_PENDING)
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    user_callback_ = callback;
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HttpProxyClientSocket::Disconnect() {
12321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (transport_.get())
12421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    transport_->socket()->Disconnect();
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Reset other states to make sure they aren't mistakenly used later.
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // These are the states initialized by Connect().
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_NONE;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  user_callback_ = NULL;
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpProxyClientSocket::IsConnected() const {
1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return next_state_ == STATE_DONE && transport_->socket()->IsConnected();
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpProxyClientSocket::IsConnectedAndIdle() const {
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return next_state_ == STATE_DONE &&
1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    transport_->socket()->IsConnectedAndIdle();
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenconst BoundNetLog& HttpProxyClientSocket::NetLog() const {
14221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return net_log_;
14321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
14421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid HttpProxyClientSocket::SetSubresourceSpeculation() {
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (transport_.get() && transport_->socket()) {
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    transport_->socket()->SetSubresourceSpeculation();
1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NOTREACHED();
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid HttpProxyClientSocket::SetOmniboxSpeculation() {
1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (transport_.get() && transport_->socket()) {
1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    transport_->socket()->SetOmniboxSpeculation();
1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NOTREACHED();
1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool HttpProxyClientSocket::WasEverUsed() const {
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (transport_.get() && transport_->socket()) {
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return transport_->socket()->WasEverUsed();
1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NOTREACHED();
1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return false;
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
169513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool HttpProxyClientSocket::UsingTCPFastOpen() const {
170513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (transport_.get() && transport_->socket()) {
171513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return transport_->socket()->UsingTCPFastOpen();
172513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
173513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  NOTREACHED();
174513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return false;
175513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
176513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len,
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                CompletionCallback* callback) {
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!user_callback_);
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (next_state_ != STATE_DONE) {
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We're trying to read the body of the response but we're still trying
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // to establish an SSL tunnel through the proxy.  We can't read these
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // bytes when establishing a tunnel because they might be controlled by
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // an active network attacker.  We don't worry about this for HTTP
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // because an active network attacker can already control HTTP sessions.
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We reach this case when the user cancels a 407 proxy auth prompt.
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // See http://crbug.com/8473.
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK_EQ(407, response_.headers->response_code());
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LogBlockedTunnelResponse(response_.headers->response_code());
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_TUNNEL_CONNECTION_FAILED;
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->Read(buf, buf_len, callback);
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len,
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 CompletionCallback* callback) {
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(STATE_DONE, next_state_);
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!user_callback_);
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->Write(buf, buf_len, callback);
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpProxyClientSocket::SetReceiveBufferSize(int32 size) {
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->SetReceiveBufferSize(size);
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpProxyClientSocket::SetSendBufferSize(int32 size) {
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->SetSendBufferSize(size);
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::GetPeerAddress(AddressList* address) const {
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->GetPeerAddress(address);
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint HttpProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return transport_->socket()->GetLocalAddress(address);
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
22172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint HttpProxyClientSocket::PrepareForAuthRestart() {
22272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!response_.headers.get())
22372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return ERR_CONNECTION_RESET;
22472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
22572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  bool keep_alive = false;
22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (response_.headers->IsKeepAlive() &&
22772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      http_stream_parser_->CanFindEndOfResponse()) {
22872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!http_stream_parser_->IsResponseBodyComplete()) {
22972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      next_state_ = STATE_DRAIN_BODY;
23072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      drain_buf_ = new IOBuffer(kDrainBodyBufferSize);
23172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return OK;
23272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
23372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    keep_alive = true;
23472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
23672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // We don't need to drain the response body, so we act as if we had drained
23772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // the response body.
23872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return DidDrainBodyForAuthRestart(keep_alive);
23972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
24072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
24172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) {
24272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (keep_alive && transport_->socket()->IsConnectedAndIdle()) {
24372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    next_state_ = STATE_GENERATE_AUTH_TOKEN;
24472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    transport_->set_is_reused(true);
24572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
24672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // This assumes that the underlying transport socket is a TCP socket,
24772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // since only TCP sockets are restartable.
24872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    next_state_ = STATE_TCP_RESTART;
24972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    transport_->socket()->Disconnect();
25072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Reset the other member variables.
25372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  drain_buf_ = NULL;
25472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  parser_buf_ = NULL;
25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  http_stream_parser_.reset();
25672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  request_line_.clear();
25772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  request_headers_.Clear();
25872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  response_ = HttpResponseInfo();
25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return OK;
26072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
26172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
26272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint HttpProxyClientSocket::HandleAuthChallenge() {
26372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(response_.headers);
26472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
26572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int rv = auth_->HandleAuthChallenge(response_.headers, false, true, net_log_);
26672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  response_.auth_challenge = auth_->auth_info();
26772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (rv == OK)
26872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return ERR_PROXY_AUTH_REQUESTED;
26972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
27072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return rv;
27172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
27272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
27372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const {
27472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  LOG(WARNING) << "Blocked proxy response with status " << response_code
27572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen               << " to CONNECT request for "
27672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen               << GetHostAndPort(request_.url) << ".";
27772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
27872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HttpProxyClientSocket::DoCallback(int result) {
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(ERR_IO_PENDING, result);
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(user_callback_);
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Since Run() may result in Read being called,
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // clear user_callback_ up front.
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CompletionCallback* c = user_callback_;
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  user_callback_ = NULL;
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  c->Run(result);
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HttpProxyClientSocket::OnIOComplete(int result) {
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(STATE_NONE, next_state_);
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(STATE_DONE, next_state_);
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = DoLoop(result);
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv != ERR_IO_PENDING)
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DoCallback(rv);
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoLoop(int last_io_result) {
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(next_state_, STATE_NONE);
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(next_state_, STATE_DONE);
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = last_io_result;
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  do {
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    State state = next_state_;
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    next_state_ = STATE_NONE;
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (state) {
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_GENERATE_AUTH_TOKEN:
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(OK, rv);
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoGenerateAuthToken();
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoGenerateAuthTokenComplete(rv);
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_SEND_REQUEST:
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(OK, rv);
31572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        net_log_.BeginEvent(
31672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, NULL);
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoSendRequest();
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_SEND_REQUEST_COMPLETE:
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoSendRequestComplete(rv);
32172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        net_log_.EndEventWithNetErrorCode(
32272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_READ_HEADERS:
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(OK, rv);
32672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        net_log_.BeginEvent(
32772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, NULL);
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoReadHeaders();
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_READ_HEADERS_COMPLETE:
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoReadHeadersComplete(rv);
33272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        net_log_.EndEventWithNetErrorCode(
33372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_DRAIN_BODY:
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(OK, rv);
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoDrainBody();
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_DRAIN_BODY_COMPLETE:
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = DoDrainBodyComplete(rv);
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      case STATE_TCP_RESTART:
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        DCHECK_EQ(OK, rv);
3443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        rv = DoTCPRestart();
3453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        break;
3463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      case STATE_TCP_RESTART_COMPLETE:
3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        rv = DoTCPRestartComplete(rv);
3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        break;
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_DONE:
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED() << "bad state";
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = ERR_UNEXPECTED;
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
3563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
3573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick           next_state_ != STATE_DONE);
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoGenerateAuthToken() {
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return auth_->MaybeGenerateAuthToken(&request_, &io_callback_, net_log_);
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(ERR_IO_PENDING, result);
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result == OK)
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    next_state_ = STATE_SEND_REQUEST;
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoSendRequest() {
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_SEND_REQUEST_COMPLETE;
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This is constructed lazily (instead of within our Start method), so that
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we have proxy info available.
3784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (request_line_.empty()) {
3794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    DCHECK(request_headers_.IsEmpty());
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HttpRequestHeaders authorization_headers;
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (auth_->HaveAuth())
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      auth_->AddAuthorizationHeader(&authorization_headers);
383731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BuildTunnelRequest(request_, authorization_headers, endpoint_,
3844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                       &request_line_, &request_headers_);
385731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (net_log_.IsLoggingAllEvents()) {
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net_log_.AddEvent(
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
388513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          make_scoped_refptr(new NetLogHttpRequestParameter(
3894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch              request_line_, request_headers_)));
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  parser_buf_ = new GrowableIOBuffer();
3943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  http_stream_parser_.reset(
3953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      new HttpStreamParser(transport_.get(), &request_, parser_buf_, net_log_));
3964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return http_stream_parser_->SendRequest(request_line_, request_headers_, NULL,
3973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                          &response_, &io_callback_);
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoSendRequestComplete(int result) {
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result < 0)
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_READ_HEADERS;
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return OK;
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoReadHeaders() {
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_READ_HEADERS_COMPLETE;
4103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return http_stream_parser_->ReadResponseHeaders(&io_callback_);
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoReadHeadersComplete(int result) {
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result < 0)
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Require the "HTTP/1.x" status line for SSL CONNECT.
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_TUNNEL_CONNECTION_FAILED;
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
421731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (net_log_.IsLoggingAllEvents()) {
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net_log_.AddEvent(
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
424513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers)));
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (response_.headers->response_code()) {
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 200:  // OK
4293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (http_stream_parser_->IsMoreDataBuffered())
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // The proxy sent extraneous data after the headers.
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return ERR_TUNNEL_CONNECTION_FAILED;
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      next_state_ = STATE_DONE;
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return OK;
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We aren't able to CONNECT to the remote host through the proxy.  We
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // need to be very suspicious about the response because an active network
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // attacker can force us into this state by masquerading as the proxy.
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The only safe thing to do here is to fail the connection because our
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // client is expecting an SSL protected response.
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // See http://crbug.com/7338.
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 407:  // Proxy Authentication Required
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We need this status code to allow proxy authentication.  Our
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // authentication code is smart enough to avoid being tricked by an
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // active network attacker.
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The next state is intentionally not set as it should be STATE_NONE;
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return HandleAuthChallenge();
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
45021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (is_https_proxy_)
45121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // For all other status codes, we conservatively fail the CONNECT
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // request.
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We lose something by doing this.  We have seen proxy 403, 404, and
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // 501 response bodies that contain a useful error message.  For
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // example, Squid uses a 404 response to report the DNS error: "The
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // domain name does not exist."
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LogBlockedTunnelResponse(response_.headers->response_code());
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ERR_TUNNEL_CONNECTION_FAILED;
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoDrainBody() {
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(drain_buf_);
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(transport_->is_initialized());
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_DRAIN_BODY_COMPLETE;
4673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return http_stream_parser_->ReadResponseBody(drain_buf_, kDrainBodyBufferSize,
4683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                               &io_callback_);
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint HttpProxyClientSocket::DoDrainBodyComplete(int result) {
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result < 0)
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (http_stream_parser_->IsResponseBodyComplete())
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DidDrainBodyForAuthRestart(true);
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Keep draining.
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_DRAIN_BODY;
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return OK;
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4837b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
4847b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen// TODO(kristianm): Check if we can find out if Connect should block
485e14dcc5a172cad1c4716af7ab94121a73c0c698eAshish Sharma// TODO(ashishsharma): Perhaps make ignore_limits, calling_uid, valid_uid part of ClientSocket
4867b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
4873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint HttpProxyClientSocket::DoTCPRestart() {
4883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  next_state_ = STATE_TCP_RESTART_COMPLETE;
4897b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen  return transport_->socket()->Connect(&io_callback_
4907b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
4917b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                                       , false
492e14dcc5a172cad1c4716af7ab94121a73c0c698eAshish Sharma                                       , false
493e14dcc5a172cad1c4716af7ab94121a73c0c698eAshish Sharma                                       , 0
4947b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
4957b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                                      );
4963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint HttpProxyClientSocket::DoTCPRestartComplete(int result) {
4993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (result != OK)
5003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return result;
5013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  next_state_ = STATE_GENERATE_AUTH_TOKEN;
5033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return result;
5043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace net
507