- add sources.
[platform/framework/web/crosswalk.git] / src / net / http / http_proxy_client_socket.cc
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
25 namespace net {
26
27 HttpProxyClientSocket::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
65 HttpProxyClientSocket::~HttpProxyClientSocket() {
66   Disconnect();
67 }
68
69 int 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
86 const scoped_refptr<HttpAuthController>&
87 HttpProxyClientSocket::GetAuthController() const {
88   return auth_;
89 }
90
91 bool HttpProxyClientSocket::IsUsingSpdy() const {
92   return using_spdy_;
93 }
94
95 NextProto HttpProxyClientSocket::GetProtocolNegotiated() const {
96   return protocol_negotiated_;
97 }
98
99 const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const {
100   return response_.headers.get() ? &response_ : NULL;
101 }
102
103 HttpStream* HttpProxyClientSocket::CreateConnectResponseStream() {
104   return new ProxyConnectRedirectHttpStream(
105       redirect_has_load_timing_info_ ? &redirect_load_timing_info_ : NULL);
106 }
107
108
109 int 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
133 void 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
143 bool HttpProxyClientSocket::IsConnected() const {
144   return next_state_ == STATE_DONE && transport_->socket()->IsConnected();
145 }
146
147 bool HttpProxyClientSocket::IsConnectedAndIdle() const {
148   return next_state_ == STATE_DONE &&
149     transport_->socket()->IsConnectedAndIdle();
150 }
151
152 const BoundNetLog& HttpProxyClientSocket::NetLog() const {
153   return net_log_;
154 }
155
156 void HttpProxyClientSocket::SetSubresourceSpeculation() {
157   if (transport_.get() && transport_->socket()) {
158     transport_->socket()->SetSubresourceSpeculation();
159   } else {
160     NOTREACHED();
161   }
162 }
163
164 void HttpProxyClientSocket::SetOmniboxSpeculation() {
165   if (transport_.get() && transport_->socket()) {
166     transport_->socket()->SetOmniboxSpeculation();
167   } else {
168     NOTREACHED();
169   }
170 }
171
172 bool HttpProxyClientSocket::WasEverUsed() const {
173   if (transport_.get() && transport_->socket()) {
174     return transport_->socket()->WasEverUsed();
175   }
176   NOTREACHED();
177   return false;
178 }
179
180 bool HttpProxyClientSocket::UsingTCPFastOpen() const {
181   if (transport_.get() && transport_->socket()) {
182     return transport_->socket()->UsingTCPFastOpen();
183   }
184   NOTREACHED();
185   return false;
186 }
187
188 bool HttpProxyClientSocket::WasNpnNegotiated() const {
189   if (transport_.get() && transport_->socket()) {
190     return transport_->socket()->WasNpnNegotiated();
191   }
192   NOTREACHED();
193   return false;
194 }
195
196 NextProto HttpProxyClientSocket::GetNegotiatedProtocol() const {
197   if (transport_.get() && transport_->socket()) {
198     return transport_->socket()->GetNegotiatedProtocol();
199   }
200   NOTREACHED();
201   return kProtoUnknown;
202 }
203
204 bool 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
212 int 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
232 int 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
240 bool HttpProxyClientSocket::SetReceiveBufferSize(int32 size) {
241   return transport_->socket()->SetReceiveBufferSize(size);
242 }
243
244 bool HttpProxyClientSocket::SetSendBufferSize(int32 size) {
245   return transport_->socket()->SetSendBufferSize(size);
246 }
247
248 int HttpProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
249   return transport_->socket()->GetPeerAddress(address);
250 }
251
252 int HttpProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
253   return transport_->socket()->GetLocalAddress(address);
254 }
255
256 int 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
276 int 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
297 void HttpProxyClientSocket::LogBlockedTunnelResponse() const {
298   ProxyClientSocket::LogBlockedTunnelResponse(
299       response_.headers->response_code(),
300       request_.url,
301       is_https_proxy_);
302 }
303
304 void 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
315 void 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
323 int 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
386 int HttpProxyClientSocket::DoGenerateAuthToken() {
387   next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
388   return auth_->MaybeGenerateAuthToken(&request_, io_callback_, net_log_);
389 }
390
391 int 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
398 int 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
425 int HttpProxyClientSocket::DoSendRequestComplete(int result) {
426   if (result < 0)
427     return result;
428
429   next_state_ = STATE_READ_HEADERS;
430   return OK;
431 }
432
433 int HttpProxyClientSocket::DoReadHeaders() {
434   next_state_ = STATE_READ_HEADERS_COMPLETE;
435   return http_stream_parser_->ReadResponseHeaders(io_callback_);
436 }
437
438 int 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
504 int 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
512 int 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
524 int HttpProxyClientSocket::DoTCPRestart() {
525   next_state_ = STATE_TCP_RESTART_COMPLETE;
526   return transport_->socket()->Connect(
527       base::Bind(&HttpProxyClientSocket::OnIOComplete, base::Unretained(this)));
528 }
529
530 int 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