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