1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/http/http_proxy_client_socket.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/strings/string_util.h"
10#include "base/strings/stringprintf.h"
11#include "net/base/auth.h"
12#include "net/base/host_port_pair.h"
13#include "net/base/io_buffer.h"
14#include "net/base/net_log.h"
15#include "net/base/net_util.h"
16#include "net/http/http_basic_stream.h"
17#include "net/http/http_network_session.h"
18#include "net/http/http_request_info.h"
19#include "net/http/http_response_headers.h"
20#include "net/http/http_stream_parser.h"
21#include "net/http/proxy_connect_redirect_http_stream.h"
22#include "net/socket/client_socket_handle.h"
23#include "url/gurl.h"
24
25namespace net {
26
27HttpProxyClientSocket::HttpProxyClientSocket(
28    ClientSocketHandle* transport_socket,
29    const GURL& request_url,
30    const std::string& user_agent,
31    const HostPortPair& endpoint,
32    const HostPortPair& proxy_server,
33    HttpAuthCache* http_auth_cache,
34    HttpAuthHandlerFactory* http_auth_handler_factory,
35    bool tunnel,
36    bool using_spdy,
37    NextProto protocol_negotiated,
38    bool is_https_proxy)
39    : io_callback_(base::Bind(&HttpProxyClientSocket::OnIOComplete,
40                              base::Unretained(this))),
41      next_state_(STATE_NONE),
42      transport_(transport_socket),
43      endpoint_(endpoint),
44      auth_(tunnel ?
45          new HttpAuthController(HttpAuth::AUTH_PROXY,
46                                 GURL((is_https_proxy ? "https://" : "http://")
47                                      + proxy_server.ToString()),
48                                 http_auth_cache,
49                                 http_auth_handler_factory)
50          : NULL),
51      tunnel_(tunnel),
52      using_spdy_(using_spdy),
53      protocol_negotiated_(protocol_negotiated),
54      is_https_proxy_(is_https_proxy),
55      redirect_has_load_timing_info_(false),
56      net_log_(transport_socket->socket()->NetLog()) {
57  // Synthesize the bits of a request that we actually use.
58  request_.url = request_url;
59  request_.method = "GET";
60  if (!user_agent.empty())
61    request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
62                                     user_agent);
63}
64
65HttpProxyClientSocket::~HttpProxyClientSocket() {
66  Disconnect();
67}
68
69int HttpProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) {
70  DCHECK_EQ(STATE_NONE, next_state_);
71  DCHECK(user_callback_.is_null());
72
73  int rv = PrepareForAuthRestart();
74  if (rv != OK)
75    return rv;
76
77  rv = DoLoop(OK);
78  if (rv == ERR_IO_PENDING) {
79    if (!callback.is_null())
80      user_callback_ =  callback;
81  }
82
83  return rv;
84}
85
86const scoped_refptr<HttpAuthController>&
87HttpProxyClientSocket::GetAuthController() const {
88  return auth_;
89}
90
91bool HttpProxyClientSocket::IsUsingSpdy() const {
92  return using_spdy_;
93}
94
95NextProto HttpProxyClientSocket::GetProtocolNegotiated() const {
96  return protocol_negotiated_;
97}
98
99const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const {
100  return response_.headers.get() ? &response_ : NULL;
101}
102
103HttpStream* HttpProxyClientSocket::CreateConnectResponseStream() {
104  return new ProxyConnectRedirectHttpStream(
105      redirect_has_load_timing_info_ ? &redirect_load_timing_info_ : NULL);
106}
107
108
109int HttpProxyClientSocket::Connect(const CompletionCallback& callback) {
110  DCHECK(transport_.get());
111  DCHECK(transport_->socket());
112  DCHECK(user_callback_.is_null());
113
114  // TODO(rch): figure out the right way to set up a tunnel with SPDY.
115  // This approach sends the complete HTTPS request to the proxy
116  // which allows the proxy to see "private" data.  Instead, we should
117  // create an SSL tunnel to the origin server using the CONNECT method
118  // inside a single SPDY stream.
119  if (using_spdy_ || !tunnel_)
120    next_state_ = STATE_DONE;
121  if (next_state_ == STATE_DONE)
122    return OK;
123
124  DCHECK_EQ(STATE_NONE, next_state_);
125  next_state_ = STATE_GENERATE_AUTH_TOKEN;
126
127  int rv = DoLoop(OK);
128  if (rv == ERR_IO_PENDING)
129    user_callback_ = callback;
130  return rv;
131}
132
133void HttpProxyClientSocket::Disconnect() {
134  if (transport_.get())
135    transport_->socket()->Disconnect();
136
137  // Reset other states to make sure they aren't mistakenly used later.
138  // These are the states initialized by Connect().
139  next_state_ = STATE_NONE;
140  user_callback_.Reset();
141}
142
143bool HttpProxyClientSocket::IsConnected() const {
144  return next_state_ == STATE_DONE && transport_->socket()->IsConnected();
145}
146
147bool HttpProxyClientSocket::IsConnectedAndIdle() const {
148  return next_state_ == STATE_DONE &&
149    transport_->socket()->IsConnectedAndIdle();
150}
151
152const BoundNetLog& HttpProxyClientSocket::NetLog() const {
153  return net_log_;
154}
155
156void HttpProxyClientSocket::SetSubresourceSpeculation() {
157  if (transport_.get() && transport_->socket()) {
158    transport_->socket()->SetSubresourceSpeculation();
159  } else {
160    NOTREACHED();
161  }
162}
163
164void HttpProxyClientSocket::SetOmniboxSpeculation() {
165  if (transport_.get() && transport_->socket()) {
166    transport_->socket()->SetOmniboxSpeculation();
167  } else {
168    NOTREACHED();
169  }
170}
171
172bool HttpProxyClientSocket::WasEverUsed() const {
173  if (transport_.get() && transport_->socket()) {
174    return transport_->socket()->WasEverUsed();
175  }
176  NOTREACHED();
177  return false;
178}
179
180bool HttpProxyClientSocket::UsingTCPFastOpen() const {
181  if (transport_.get() && transport_->socket()) {
182    return transport_->socket()->UsingTCPFastOpen();
183  }
184  NOTREACHED();
185  return false;
186}
187
188bool HttpProxyClientSocket::WasNpnNegotiated() const {
189  if (transport_.get() && transport_->socket()) {
190    return transport_->socket()->WasNpnNegotiated();
191  }
192  NOTREACHED();
193  return false;
194}
195
196NextProto HttpProxyClientSocket::GetNegotiatedProtocol() const {
197  if (transport_.get() && transport_->socket()) {
198    return transport_->socket()->GetNegotiatedProtocol();
199  }
200  NOTREACHED();
201  return kProtoUnknown;
202}
203
204bool HttpProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
205  if (transport_.get() && transport_->socket()) {
206    return transport_->socket()->GetSSLInfo(ssl_info);
207  }
208  NOTREACHED();
209  return false;
210}
211
212int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len,
213                                const CompletionCallback& callback) {
214  DCHECK(user_callback_.is_null());
215  if (next_state_ != STATE_DONE) {
216    // We're trying to read the body of the response but we're still trying
217    // to establish an SSL tunnel through the proxy.  We can't read these
218    // bytes when establishing a tunnel because they might be controlled by
219    // an active network attacker.  We don't worry about this for HTTP
220    // because an active network attacker can already control HTTP sessions.
221    // We reach this case when the user cancels a 407 proxy auth prompt.
222    // See http://crbug.com/8473.
223    DCHECK_EQ(407, response_.headers->response_code());
224    LogBlockedTunnelResponse();
225
226    return ERR_TUNNEL_CONNECTION_FAILED;
227  }
228
229  return transport_->socket()->Read(buf, buf_len, callback);
230}
231
232int HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len,
233                                 const CompletionCallback& callback) {
234  DCHECK_EQ(STATE_DONE, next_state_);
235  DCHECK(user_callback_.is_null());
236
237  return transport_->socket()->Write(buf, buf_len, callback);
238}
239
240bool HttpProxyClientSocket::SetReceiveBufferSize(int32 size) {
241  return transport_->socket()->SetReceiveBufferSize(size);
242}
243
244bool HttpProxyClientSocket::SetSendBufferSize(int32 size) {
245  return transport_->socket()->SetSendBufferSize(size);
246}
247
248int HttpProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
249  return transport_->socket()->GetPeerAddress(address);
250}
251
252int HttpProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
253  return transport_->socket()->GetLocalAddress(address);
254}
255
256int HttpProxyClientSocket::PrepareForAuthRestart() {
257  if (!response_.headers.get())
258    return ERR_CONNECTION_RESET;
259
260  bool keep_alive = false;
261  if (response_.headers->IsKeepAlive() &&
262      http_stream_parser_->CanFindEndOfResponse()) {
263    if (!http_stream_parser_->IsResponseBodyComplete()) {
264      next_state_ = STATE_DRAIN_BODY;
265      drain_buf_ = new IOBuffer(kDrainBodyBufferSize);
266      return OK;
267    }
268    keep_alive = true;
269  }
270
271  // We don't need to drain the response body, so we act as if we had drained
272  // the response body.
273  return DidDrainBodyForAuthRestart(keep_alive);
274}
275
276int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) {
277  if (keep_alive && transport_->socket()->IsConnectedAndIdle()) {
278    next_state_ = STATE_GENERATE_AUTH_TOKEN;
279    transport_->set_is_reused(true);
280  } else {
281    // This assumes that the underlying transport socket is a TCP socket,
282    // since only TCP sockets are restartable.
283    next_state_ = STATE_TCP_RESTART;
284    transport_->socket()->Disconnect();
285  }
286
287  // Reset the other member variables.
288  drain_buf_ = NULL;
289  parser_buf_ = NULL;
290  http_stream_parser_.reset();
291  request_line_.clear();
292  request_headers_.Clear();
293  response_ = HttpResponseInfo();
294  return OK;
295}
296
297void HttpProxyClientSocket::LogBlockedTunnelResponse() const {
298  ProxyClientSocket::LogBlockedTunnelResponse(
299      response_.headers->response_code(),
300      request_.url,
301      is_https_proxy_);
302}
303
304void HttpProxyClientSocket::DoCallback(int result) {
305  DCHECK_NE(ERR_IO_PENDING, result);
306  DCHECK(!user_callback_.is_null());
307
308  // Since Run() may result in Read being called,
309  // clear user_callback_ up front.
310  CompletionCallback c = user_callback_;
311  user_callback_.Reset();
312  c.Run(result);
313}
314
315void HttpProxyClientSocket::OnIOComplete(int result) {
316  DCHECK_NE(STATE_NONE, next_state_);
317  DCHECK_NE(STATE_DONE, next_state_);
318  int rv = DoLoop(result);
319  if (rv != ERR_IO_PENDING)
320    DoCallback(rv);
321}
322
323int HttpProxyClientSocket::DoLoop(int last_io_result) {
324  DCHECK_NE(next_state_, STATE_NONE);
325  DCHECK_NE(next_state_, STATE_DONE);
326  int rv = last_io_result;
327  do {
328    State state = next_state_;
329    next_state_ = STATE_NONE;
330    switch (state) {
331      case STATE_GENERATE_AUTH_TOKEN:
332        DCHECK_EQ(OK, rv);
333        rv = DoGenerateAuthToken();
334        break;
335      case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
336        rv = DoGenerateAuthTokenComplete(rv);
337        break;
338      case STATE_SEND_REQUEST:
339        DCHECK_EQ(OK, rv);
340        net_log_.BeginEvent(
341            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
342        rv = DoSendRequest();
343        break;
344      case STATE_SEND_REQUEST_COMPLETE:
345        rv = DoSendRequestComplete(rv);
346        net_log_.EndEventWithNetErrorCode(
347            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
348        break;
349      case STATE_READ_HEADERS:
350        DCHECK_EQ(OK, rv);
351        net_log_.BeginEvent(
352            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
353        rv = DoReadHeaders();
354        break;
355      case STATE_READ_HEADERS_COMPLETE:
356        rv = DoReadHeadersComplete(rv);
357        net_log_.EndEventWithNetErrorCode(
358            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
359        break;
360      case STATE_DRAIN_BODY:
361        DCHECK_EQ(OK, rv);
362        rv = DoDrainBody();
363        break;
364      case STATE_DRAIN_BODY_COMPLETE:
365        rv = DoDrainBodyComplete(rv);
366        break;
367      case STATE_TCP_RESTART:
368        DCHECK_EQ(OK, rv);
369        rv = DoTCPRestart();
370        break;
371      case STATE_TCP_RESTART_COMPLETE:
372        rv = DoTCPRestartComplete(rv);
373        break;
374      case STATE_DONE:
375        break;
376      default:
377        NOTREACHED() << "bad state";
378        rv = ERR_UNEXPECTED;
379        break;
380    }
381  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
382           next_state_ != STATE_DONE);
383  return rv;
384}
385
386int HttpProxyClientSocket::DoGenerateAuthToken() {
387  next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
388  return auth_->MaybeGenerateAuthToken(&request_, io_callback_, net_log_);
389}
390
391int HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
392  DCHECK_NE(ERR_IO_PENDING, result);
393  if (result == OK)
394    next_state_ = STATE_SEND_REQUEST;
395  return result;
396}
397
398int HttpProxyClientSocket::DoSendRequest() {
399  next_state_ = STATE_SEND_REQUEST_COMPLETE;
400
401  // This is constructed lazily (instead of within our Start method), so that
402  // we have proxy info available.
403  if (request_line_.empty()) {
404    DCHECK(request_headers_.IsEmpty());
405    HttpRequestHeaders authorization_headers;
406    if (auth_->HaveAuth())
407      auth_->AddAuthorizationHeader(&authorization_headers);
408    BuildTunnelRequest(request_, authorization_headers, endpoint_,
409                       &request_line_, &request_headers_);
410
411    net_log_.AddEvent(
412        NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
413        base::Bind(&HttpRequestHeaders::NetLogCallback,
414                   base::Unretained(&request_headers_),
415                   &request_line_));
416  }
417
418  parser_buf_ = new GrowableIOBuffer();
419  http_stream_parser_.reset(new HttpStreamParser(
420      transport_.get(), &request_, parser_buf_.get(), net_log_));
421  return http_stream_parser_->SendRequest(
422      request_line_, request_headers_, &response_, io_callback_);
423}
424
425int HttpProxyClientSocket::DoSendRequestComplete(int result) {
426  if (result < 0)
427    return result;
428
429  next_state_ = STATE_READ_HEADERS;
430  return OK;
431}
432
433int HttpProxyClientSocket::DoReadHeaders() {
434  next_state_ = STATE_READ_HEADERS_COMPLETE;
435  return http_stream_parser_->ReadResponseHeaders(io_callback_);
436}
437
438int HttpProxyClientSocket::DoReadHeadersComplete(int result) {
439  if (result < 0)
440    return result;
441
442  // Require the "HTTP/1.x" status line for SSL CONNECT.
443  if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
444    return ERR_TUNNEL_CONNECTION_FAILED;
445
446  net_log_.AddEvent(
447      NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
448      base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers));
449
450  switch (response_.headers->response_code()) {
451    case 200:  // OK
452      if (http_stream_parser_->IsMoreDataBuffered())
453        // The proxy sent extraneous data after the headers.
454        return ERR_TUNNEL_CONNECTION_FAILED;
455
456      next_state_ = STATE_DONE;
457      return OK;
458
459      // We aren't able to CONNECT to the remote host through the proxy.  We
460      // need to be very suspicious about the response because an active network
461      // attacker can force us into this state by masquerading as the proxy.
462      // The only safe thing to do here is to fail the connection because our
463      // client is expecting an SSL protected response.
464      // See http://crbug.com/7338.
465
466    case 302:  // Found / Moved Temporarily
467      // Attempt to follow redirects from HTTPS proxies, but only if we can
468      // sanitize the response.  This still allows a rogue HTTPS proxy to
469      // redirect an HTTPS site load to a similar-looking site, but no longer
470      // allows it to impersonate the site the user requested.
471      if (is_https_proxy_ && SanitizeProxyRedirect(&response_, request_.url)) {
472        bool is_connection_reused = http_stream_parser_->IsConnectionReused();
473        redirect_has_load_timing_info_ =
474            transport_->GetLoadTimingInfo(
475                is_connection_reused, &redirect_load_timing_info_);
476        transport_.reset();
477        http_stream_parser_.reset();
478        return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
479      }
480
481      // We're not using an HTTPS proxy, or we couldn't sanitize the redirect.
482      LogBlockedTunnelResponse();
483      return ERR_TUNNEL_CONNECTION_FAILED;
484
485    case 407:  // Proxy Authentication Required
486      // We need this status code to allow proxy authentication.  Our
487      // authentication code is smart enough to avoid being tricked by an
488      // active network attacker.
489      // The next state is intentionally not set as it should be STATE_NONE;
490      return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_);
491
492    default:
493      // Ignore response to avoid letting the proxy impersonate the target
494      // server.  (See http://crbug.com/137891.)
495      // We lose something by doing this.  We have seen proxy 403, 404, and
496      // 501 response bodies that contain a useful error message.  For
497      // example, Squid uses a 404 response to report the DNS error: "The
498      // domain name does not exist."
499      LogBlockedTunnelResponse();
500      return ERR_TUNNEL_CONNECTION_FAILED;
501  }
502}
503
504int HttpProxyClientSocket::DoDrainBody() {
505  DCHECK(drain_buf_.get());
506  DCHECK(transport_->is_initialized());
507  next_state_ = STATE_DRAIN_BODY_COMPLETE;
508  return http_stream_parser_->ReadResponseBody(
509      drain_buf_.get(), kDrainBodyBufferSize, io_callback_);
510}
511
512int HttpProxyClientSocket::DoDrainBodyComplete(int result) {
513  if (result < 0)
514    return result;
515
516  if (http_stream_parser_->IsResponseBodyComplete())
517    return DidDrainBodyForAuthRestart(true);
518
519  // Keep draining.
520  next_state_ = STATE_DRAIN_BODY;
521  return OK;
522}
523
524int HttpProxyClientSocket::DoTCPRestart() {
525  next_state_ = STATE_TCP_RESTART_COMPLETE;
526  return transport_->socket()->Connect(
527      base::Bind(&HttpProxyClientSocket::OnIOComplete, base::Unretained(this)));
528}
529
530int HttpProxyClientSocket::DoTCPRestartComplete(int result) {
531  if (result != OK)
532    return result;
533
534  next_state_ = STATE_GENERATE_AUTH_TOKEN;
535  return result;
536}
537
538}  // namespace net
539