Allow only one bookmark to be added for multiple fast starring
[chromium-blink-merge.git] / net / http / http_proxy_client_socket.cc
blobf5feb585bf2a1e35395ecb633ea56ce987cab6c8
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.
5 #include "net/http/http_proxy_client_socket.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/profiler/scoped_tracker.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/values.h"
13 #include "net/base/auth.h"
14 #include "net/base/host_port_pair.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_util.h"
17 #include "net/base/proxy_delegate.h"
18 #include "net/http/http_basic_stream.h"
19 #include "net/http/http_network_session.h"
20 #include "net/http/http_request_info.h"
21 #include "net/http/http_response_headers.h"
22 #include "net/http/http_stream_parser.h"
23 #include "net/http/proxy_connect_redirect_http_stream.h"
24 #include "net/log/net_log.h"
25 #include "net/socket/client_socket_handle.h"
26 #include "url/gurl.h"
28 namespace net {
30 HttpProxyClientSocket::HttpProxyClientSocket(
31 ClientSocketHandle* transport_socket,
32 const std::string& user_agent,
33 const HostPortPair& endpoint,
34 const HostPortPair& proxy_server,
35 HttpAuthCache* http_auth_cache,
36 HttpAuthHandlerFactory* http_auth_handler_factory,
37 bool tunnel,
38 bool using_spdy,
39 NextProto protocol_negotiated,
40 ProxyDelegate* proxy_delegate,
41 bool is_https_proxy)
42 : io_callback_(base::Bind(&HttpProxyClientSocket::OnIOComplete,
43 base::Unretained(this))),
44 next_state_(STATE_NONE),
45 transport_(transport_socket),
46 endpoint_(endpoint),
47 auth_(tunnel ?
48 new HttpAuthController(HttpAuth::AUTH_PROXY,
49 GURL((is_https_proxy ? "https://" : "http://")
50 + proxy_server.ToString()),
51 http_auth_cache,
52 http_auth_handler_factory)
53 : NULL),
54 tunnel_(tunnel),
55 using_spdy_(using_spdy),
56 protocol_negotiated_(protocol_negotiated),
57 is_https_proxy_(is_https_proxy),
58 redirect_has_load_timing_info_(false),
59 proxy_server_(proxy_server),
60 proxy_delegate_(proxy_delegate),
61 net_log_(transport_socket->socket()->NetLog()) {
62 // Synthesize the bits of a request that we actually use.
63 request_.url = GURL("https://" + endpoint.ToString());
64 request_.method = "CONNECT";
65 if (!user_agent.empty())
66 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
67 user_agent);
70 HttpProxyClientSocket::~HttpProxyClientSocket() {
71 Disconnect();
74 int HttpProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) {
75 DCHECK_EQ(STATE_NONE, next_state_);
76 DCHECK(user_callback_.is_null());
78 int rv = PrepareForAuthRestart();
79 if (rv != OK)
80 return rv;
82 rv = DoLoop(OK);
83 if (rv == ERR_IO_PENDING) {
84 if (!callback.is_null())
85 user_callback_ = callback;
88 return rv;
91 const scoped_refptr<HttpAuthController>&
92 HttpProxyClientSocket::GetAuthController() const {
93 return auth_;
96 bool HttpProxyClientSocket::IsUsingSpdy() const {
97 return using_spdy_;
100 NextProto HttpProxyClientSocket::GetProtocolNegotiated() const {
101 return protocol_negotiated_;
104 const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const {
105 return response_.headers.get() ? &response_ : NULL;
108 HttpStream* HttpProxyClientSocket::CreateConnectResponseStream() {
109 return new ProxyConnectRedirectHttpStream(
110 redirect_has_load_timing_info_ ? &redirect_load_timing_info_ : NULL);
114 int HttpProxyClientSocket::Connect(const CompletionCallback& callback) {
115 DCHECK(transport_.get());
116 DCHECK(transport_->socket());
117 DCHECK(user_callback_.is_null());
119 // TODO(rch): figure out the right way to set up a tunnel with SPDY.
120 // This approach sends the complete HTTPS request to the proxy
121 // which allows the proxy to see "private" data. Instead, we should
122 // create an SSL tunnel to the origin server using the CONNECT method
123 // inside a single SPDY stream.
124 if (using_spdy_ || !tunnel_)
125 next_state_ = STATE_DONE;
126 if (next_state_ == STATE_DONE)
127 return OK;
129 DCHECK_EQ(STATE_NONE, next_state_);
130 next_state_ = STATE_GENERATE_AUTH_TOKEN;
132 int rv = DoLoop(OK);
133 if (rv == ERR_IO_PENDING)
134 user_callback_ = callback;
135 return rv;
138 void HttpProxyClientSocket::Disconnect() {
139 if (transport_.get())
140 transport_->socket()->Disconnect();
142 // Reset other states to make sure they aren't mistakenly used later.
143 // These are the states initialized by Connect().
144 next_state_ = STATE_NONE;
145 user_callback_.Reset();
148 bool HttpProxyClientSocket::IsConnected() const {
149 return next_state_ == STATE_DONE && transport_->socket()->IsConnected();
152 bool HttpProxyClientSocket::IsConnectedAndIdle() const {
153 return next_state_ == STATE_DONE &&
154 transport_->socket()->IsConnectedAndIdle();
157 const BoundNetLog& HttpProxyClientSocket::NetLog() const {
158 return net_log_;
161 void HttpProxyClientSocket::SetSubresourceSpeculation() {
162 if (transport_.get() && transport_->socket()) {
163 transport_->socket()->SetSubresourceSpeculation();
164 } else {
165 NOTREACHED();
169 void HttpProxyClientSocket::SetOmniboxSpeculation() {
170 if (transport_.get() && transport_->socket()) {
171 transport_->socket()->SetOmniboxSpeculation();
172 } else {
173 NOTREACHED();
177 bool HttpProxyClientSocket::WasEverUsed() const {
178 if (transport_.get() && transport_->socket()) {
179 return transport_->socket()->WasEverUsed();
181 NOTREACHED();
182 return false;
185 bool HttpProxyClientSocket::UsingTCPFastOpen() const {
186 if (transport_.get() && transport_->socket()) {
187 return transport_->socket()->UsingTCPFastOpen();
189 NOTREACHED();
190 return false;
193 bool HttpProxyClientSocket::WasNpnNegotiated() const {
194 if (transport_.get() && transport_->socket()) {
195 return transport_->socket()->WasNpnNegotiated();
197 NOTREACHED();
198 return false;
201 NextProto HttpProxyClientSocket::GetNegotiatedProtocol() const {
202 if (transport_.get() && transport_->socket()) {
203 return transport_->socket()->GetNegotiatedProtocol();
205 NOTREACHED();
206 return kProtoUnknown;
209 bool HttpProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
210 if (transport_.get() && transport_->socket()) {
211 return transport_->socket()->GetSSLInfo(ssl_info);
213 NOTREACHED();
214 return false;
217 void HttpProxyClientSocket::GetConnectionAttempts(
218 ConnectionAttempts* out) const {
219 out->clear();
222 int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len,
223 const CompletionCallback& callback) {
224 DCHECK(user_callback_.is_null());
225 if (next_state_ != STATE_DONE) {
226 // We're trying to read the body of the response but we're still trying
227 // to establish an SSL tunnel through the proxy. We can't read these
228 // bytes when establishing a tunnel because they might be controlled by
229 // an active network attacker. We don't worry about this for HTTP
230 // because an active network attacker can already control HTTP sessions.
231 // We reach this case when the user cancels a 407 proxy auth prompt.
232 // See http://crbug.com/8473.
233 DCHECK_EQ(407, response_.headers->response_code());
234 LogBlockedTunnelResponse();
236 return ERR_TUNNEL_CONNECTION_FAILED;
239 return transport_->socket()->Read(buf, buf_len, callback);
242 int HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len,
243 const CompletionCallback& callback) {
244 DCHECK_EQ(STATE_DONE, next_state_);
245 DCHECK(user_callback_.is_null());
247 return transport_->socket()->Write(buf, buf_len, callback);
250 int HttpProxyClientSocket::SetReceiveBufferSize(int32 size) {
251 return transport_->socket()->SetReceiveBufferSize(size);
254 int HttpProxyClientSocket::SetSendBufferSize(int32 size) {
255 return transport_->socket()->SetSendBufferSize(size);
258 int HttpProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
259 return transport_->socket()->GetPeerAddress(address);
262 int HttpProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
263 return transport_->socket()->GetLocalAddress(address);
266 int HttpProxyClientSocket::PrepareForAuthRestart() {
267 if (!response_.headers.get())
268 return ERR_CONNECTION_RESET;
270 bool keep_alive = false;
271 if (response_.headers->IsKeepAlive() &&
272 http_stream_parser_->CanFindEndOfResponse()) {
273 if (!http_stream_parser_->IsResponseBodyComplete()) {
274 next_state_ = STATE_DRAIN_BODY;
275 drain_buf_ = new IOBuffer(kDrainBodyBufferSize);
276 return OK;
278 keep_alive = true;
281 // We don't need to drain the response body, so we act as if we had drained
282 // the response body.
283 return DidDrainBodyForAuthRestart(keep_alive);
286 int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) {
287 if (keep_alive && transport_->socket()->IsConnectedAndIdle()) {
288 next_state_ = STATE_GENERATE_AUTH_TOKEN;
289 transport_->set_reuse_type(ClientSocketHandle::REUSED_IDLE);
290 } else {
291 // This assumes that the underlying transport socket is a TCP socket,
292 // since only TCP sockets are restartable.
293 next_state_ = STATE_TCP_RESTART;
294 transport_->socket()->Disconnect();
297 // Reset the other member variables.
298 drain_buf_ = NULL;
299 parser_buf_ = NULL;
300 http_stream_parser_.reset();
301 request_line_.clear();
302 request_headers_.Clear();
303 response_ = HttpResponseInfo();
304 return OK;
307 void HttpProxyClientSocket::LogBlockedTunnelResponse() const {
308 ProxyClientSocket::LogBlockedTunnelResponse(
309 response_.headers->response_code(),
310 is_https_proxy_);
313 void HttpProxyClientSocket::DoCallback(int result) {
314 DCHECK_NE(ERR_IO_PENDING, result);
315 DCHECK(!user_callback_.is_null());
317 // Since Run() may result in Read being called,
318 // clear user_callback_ up front.
319 CompletionCallback c = user_callback_;
320 user_callback_.Reset();
321 c.Run(result);
324 void HttpProxyClientSocket::OnIOComplete(int result) {
325 DCHECK_NE(STATE_NONE, next_state_);
326 DCHECK_NE(STATE_DONE, next_state_);
327 int rv = DoLoop(result);
328 if (rv != ERR_IO_PENDING)
329 DoCallback(rv);
332 int HttpProxyClientSocket::DoLoop(int last_io_result) {
333 DCHECK_NE(next_state_, STATE_NONE);
334 DCHECK_NE(next_state_, STATE_DONE);
335 int rv = last_io_result;
336 do {
337 State state = next_state_;
338 next_state_ = STATE_NONE;
339 switch (state) {
340 case STATE_GENERATE_AUTH_TOKEN:
341 DCHECK_EQ(OK, rv);
342 rv = DoGenerateAuthToken();
343 break;
344 case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
345 rv = DoGenerateAuthTokenComplete(rv);
346 break;
347 case STATE_SEND_REQUEST:
348 DCHECK_EQ(OK, rv);
349 net_log_.BeginEvent(
350 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
351 rv = DoSendRequest();
352 break;
353 case STATE_SEND_REQUEST_COMPLETE:
354 rv = DoSendRequestComplete(rv);
355 net_log_.EndEventWithNetErrorCode(
356 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
357 break;
358 case STATE_READ_HEADERS:
359 DCHECK_EQ(OK, rv);
360 net_log_.BeginEvent(
361 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
362 rv = DoReadHeaders();
363 break;
364 case STATE_READ_HEADERS_COMPLETE:
365 rv = DoReadHeadersComplete(rv);
366 net_log_.EndEventWithNetErrorCode(
367 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
368 break;
369 case STATE_DRAIN_BODY:
370 DCHECK_EQ(OK, rv);
371 rv = DoDrainBody();
372 break;
373 case STATE_DRAIN_BODY_COMPLETE:
374 rv = DoDrainBodyComplete(rv);
375 break;
376 case STATE_TCP_RESTART:
377 DCHECK_EQ(OK, rv);
378 rv = DoTCPRestart();
379 break;
380 case STATE_TCP_RESTART_COMPLETE:
381 rv = DoTCPRestartComplete(rv);
382 break;
383 case STATE_DONE:
384 break;
385 default:
386 NOTREACHED() << "bad state";
387 rv = ERR_UNEXPECTED;
388 break;
390 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
391 next_state_ != STATE_DONE);
392 return rv;
395 int HttpProxyClientSocket::DoGenerateAuthToken() {
396 next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
397 return auth_->MaybeGenerateAuthToken(&request_, io_callback_, net_log_);
400 int HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
401 DCHECK_NE(ERR_IO_PENDING, result);
402 if (result == OK)
403 next_state_ = STATE_SEND_REQUEST;
404 return result;
407 int HttpProxyClientSocket::DoSendRequest() {
408 next_state_ = STATE_SEND_REQUEST_COMPLETE;
410 // This is constructed lazily (instead of within our Start method), so that
411 // we have proxy info available.
412 if (request_line_.empty()) {
413 DCHECK(request_headers_.IsEmpty());
414 HttpRequestHeaders authorization_headers;
415 if (auth_->HaveAuth())
416 auth_->AddAuthorizationHeader(&authorization_headers);
417 if (proxy_delegate_) {
418 proxy_delegate_->OnBeforeTunnelRequest(proxy_server_,
419 &authorization_headers);
421 std::string user_agent;
422 if (!request_.extra_headers.GetHeader(HttpRequestHeaders::kUserAgent,
423 &user_agent)) {
424 user_agent.clear();
426 BuildTunnelRequest(endpoint_, authorization_headers, user_agent,
427 &request_line_, &request_headers_);
429 net_log_.AddEvent(
430 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
431 base::Bind(&HttpRequestHeaders::NetLogCallback,
432 base::Unretained(&request_headers_),
433 &request_line_));
436 parser_buf_ = new GrowableIOBuffer();
437 http_stream_parser_.reset(new HttpStreamParser(
438 transport_.get(), &request_, parser_buf_.get(), net_log_));
439 return http_stream_parser_->SendRequest(
440 request_line_, request_headers_, &response_, io_callback_);
443 int HttpProxyClientSocket::DoSendRequestComplete(int result) {
444 if (result < 0)
445 return result;
447 next_state_ = STATE_READ_HEADERS;
448 return OK;
451 int HttpProxyClientSocket::DoReadHeaders() {
452 next_state_ = STATE_READ_HEADERS_COMPLETE;
453 return http_stream_parser_->ReadResponseHeaders(io_callback_);
456 int HttpProxyClientSocket::DoReadHeadersComplete(int result) {
457 if (result < 0)
458 return result;
460 // Require the "HTTP/1.x" status line for SSL CONNECT.
461 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
462 return ERR_TUNNEL_CONNECTION_FAILED;
464 net_log_.AddEvent(
465 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
466 base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers));
468 if (proxy_delegate_) {
469 proxy_delegate_->OnTunnelHeadersReceived(
470 HostPortPair::FromURL(request_.url),
471 proxy_server_,
472 *response_.headers);
475 switch (response_.headers->response_code()) {
476 case 200: // OK
477 if (http_stream_parser_->IsMoreDataBuffered())
478 // The proxy sent extraneous data after the headers.
479 return ERR_TUNNEL_CONNECTION_FAILED;
481 next_state_ = STATE_DONE;
482 return OK;
484 // We aren't able to CONNECT to the remote host through the proxy. We
485 // need to be very suspicious about the response because an active network
486 // attacker can force us into this state by masquerading as the proxy.
487 // The only safe thing to do here is to fail the connection because our
488 // client is expecting an SSL protected response.
489 // See http://crbug.com/7338.
491 case 302: // Found / Moved Temporarily
492 // Attempt to follow redirects from HTTPS proxies, but only if we can
493 // sanitize the response. This still allows a rogue HTTPS proxy to
494 // redirect an HTTPS site load to a similar-looking site, but no longer
495 // allows it to impersonate the site the user requested.
496 if (!is_https_proxy_ || !SanitizeProxyRedirect(&response_)) {
497 LogBlockedTunnelResponse();
498 return ERR_TUNNEL_CONNECTION_FAILED;
501 redirect_has_load_timing_info_ = transport_->GetLoadTimingInfo(
502 http_stream_parser_->IsConnectionReused(),
503 &redirect_load_timing_info_);
504 transport_.reset();
505 http_stream_parser_.reset();
506 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
508 case 407: // Proxy Authentication Required
509 // We need this status code to allow proxy authentication. Our
510 // authentication code is smart enough to avoid being tricked by an
511 // active network attacker.
512 // The next state is intentionally not set as it should be STATE_NONE;
513 if (!SanitizeProxyAuth(&response_)) {
514 LogBlockedTunnelResponse();
515 return ERR_TUNNEL_CONNECTION_FAILED;
517 return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_);
519 default:
520 // Ignore response to avoid letting the proxy impersonate the target
521 // server. (See http://crbug.com/137891.)
522 // We lose something by doing this. We have seen proxy 403, 404, and
523 // 501 response bodies that contain a useful error message. For
524 // example, Squid uses a 404 response to report the DNS error: "The
525 // domain name does not exist."
526 LogBlockedTunnelResponse();
527 return ERR_TUNNEL_CONNECTION_FAILED;
531 int HttpProxyClientSocket::DoDrainBody() {
532 DCHECK(drain_buf_.get());
533 DCHECK(transport_->is_initialized());
534 next_state_ = STATE_DRAIN_BODY_COMPLETE;
535 return http_stream_parser_->ReadResponseBody(
536 drain_buf_.get(), kDrainBodyBufferSize, io_callback_);
539 int HttpProxyClientSocket::DoDrainBodyComplete(int result) {
540 if (result < 0)
541 return result;
543 if (http_stream_parser_->IsResponseBodyComplete())
544 return DidDrainBodyForAuthRestart(true);
546 // Keep draining.
547 next_state_ = STATE_DRAIN_BODY;
548 return OK;
551 int HttpProxyClientSocket::DoTCPRestart() {
552 next_state_ = STATE_TCP_RESTART_COMPLETE;
553 return transport_->socket()->Connect(
554 base::Bind(&HttpProxyClientSocket::OnIOComplete, base::Unretained(this)));
557 int HttpProxyClientSocket::DoTCPRestartComplete(int result) {
558 // TODO(rvargas): Remove ScopedTracker below once crbug.com/462784 is fixed.
559 tracked_objects::ScopedTracker tracking_profile(
560 FROM_HERE_WITH_EXPLICIT_FUNCTION(
561 "462784 HttpProxyClientSocket::DoTCPRestartComplete"));
563 if (result != OK)
564 return result;
566 next_state_ = STATE_GENERATE_AUTH_TOKEN;
567 return result;
570 } // namespace net