OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/http/http_proxy_client_socket.h" | 5 #include "net/http/http_proxy_client_socket.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
10 #include "base/stringprintf.h" | 10 #include "base/stringprintf.h" |
11 #include "googleurl/src/gurl.h" | 11 #include "googleurl/src/gurl.h" |
(...skipping 12 matching lines...) Expand all Loading... |
24 #include "net/socket/client_socket_handle.h" | 24 #include "net/socket/client_socket_handle.h" |
25 | 25 |
26 namespace net { | 26 namespace net { |
27 | 27 |
28 HttpProxyClientSocket::HttpProxyClientSocket( | 28 HttpProxyClientSocket::HttpProxyClientSocket( |
29 ClientSocketHandle* transport_socket, | 29 ClientSocketHandle* transport_socket, |
30 const GURL& request_url, | 30 const GURL& request_url, |
31 const std::string& user_agent, | 31 const std::string& user_agent, |
32 const HostPortPair& endpoint, | 32 const HostPortPair& endpoint, |
33 const HostPortPair& proxy_server, | 33 const HostPortPair& proxy_server, |
34 HttpAuthController* http_auth_controller, | 34 HttpAuthCache* http_auth_cache, |
| 35 HttpAuthHandlerFactory* http_auth_handler_factory, |
35 bool tunnel, | 36 bool tunnel, |
36 bool using_spdy, | 37 bool using_spdy, |
37 SSLClientSocket::NextProto protocol_negotiated, | 38 SSLClientSocket::NextProto protocol_negotiated, |
38 bool is_https_proxy) | 39 bool is_https_proxy) |
39 : ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_( | 40 : ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_( |
40 base::Bind(&HttpProxyClientSocket::OnIOComplete, | 41 base::Bind(&HttpProxyClientSocket::OnIOComplete, |
41 base::Unretained(this)))), | 42 base::Unretained(this)))), |
42 next_state_(STATE_NONE), | 43 next_state_(STATE_NONE), |
43 transport_(transport_socket), | 44 transport_(transport_socket), |
44 endpoint_(endpoint), | 45 endpoint_(endpoint), |
45 auth_(http_auth_controller), | 46 auth_(tunnel ? |
| 47 new HttpAuthController(HttpAuth::AUTH_PROXY, |
| 48 GURL((is_https_proxy ? "https://" : "http://") |
| 49 + proxy_server.ToString()), |
| 50 http_auth_cache, |
| 51 http_auth_handler_factory) |
| 52 : NULL), |
46 tunnel_(tunnel), | 53 tunnel_(tunnel), |
47 using_spdy_(using_spdy), | 54 using_spdy_(using_spdy), |
48 protocol_negotiated_(protocol_negotiated), | 55 protocol_negotiated_(protocol_negotiated), |
49 is_https_proxy_(is_https_proxy), | 56 is_https_proxy_(is_https_proxy), |
50 net_log_(transport_socket->socket()->NetLog()) { | 57 net_log_(transport_socket->socket()->NetLog()) { |
51 // Synthesize the bits of a request that we actually use. | 58 // Synthesize the bits of a request that we actually use. |
52 request_.url = request_url; | 59 request_.url = request_url; |
53 request_.method = "GET"; | 60 request_.method = "GET"; |
54 if (!user_agent.empty()) | 61 if (!user_agent.empty()) |
55 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, | 62 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, |
56 user_agent); | 63 user_agent); |
57 } | 64 } |
58 | 65 |
59 HttpProxyClientSocket::~HttpProxyClientSocket() { | 66 HttpProxyClientSocket::~HttpProxyClientSocket() { |
60 Disconnect(); | 67 Disconnect(); |
61 } | 68 } |
62 | 69 |
63 const | |
64 scoped_refptr<HttpAuthController>& HttpProxyClientSocket::GetAuthController() { | |
65 return auth_; | |
66 } | |
67 | |
68 int HttpProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) { | 70 int HttpProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) { |
69 DCHECK_EQ(STATE_NONE, next_state_); | 71 DCHECK_EQ(STATE_NONE, next_state_); |
70 DCHECK(user_callback_.is_null()); | 72 DCHECK(user_callback_.is_null()); |
71 | 73 |
72 int rv = PrepareForAuthRestart(); | 74 int rv = PrepareForAuthRestart(); |
73 if (rv != OK) | 75 if (rv != OK) |
74 return rv; | 76 return rv; |
75 | 77 |
76 rv = DoLoop(OK); | 78 rv = DoLoop(OK); |
77 if (rv == ERR_IO_PENDING) { | 79 if (rv == ERR_IO_PENDING) { |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 } | 247 } |
246 keep_alive = true; | 248 keep_alive = true; |
247 } | 249 } |
248 | 250 |
249 // We don't need to drain the response body, so we act as if we had drained | 251 // We don't need to drain the response body, so we act as if we had drained |
250 // the response body. | 252 // the response body. |
251 return DidDrainBodyForAuthRestart(keep_alive); | 253 return DidDrainBodyForAuthRestart(keep_alive); |
252 } | 254 } |
253 | 255 |
254 int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) { | 256 int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) { |
255 int rv = OK; | |
256 if (keep_alive && transport_->socket()->IsConnectedAndIdle()) { | 257 if (keep_alive && transport_->socket()->IsConnectedAndIdle()) { |
257 next_state_ = STATE_GENERATE_AUTH_TOKEN; | 258 next_state_ = STATE_GENERATE_AUTH_TOKEN; |
258 transport_->set_is_reused(true); | 259 transport_->set_is_reused(true); |
259 } else { | 260 } else { |
260 next_state_ = STATE_NONE; | 261 // This assumes that the underlying transport socket is a TCP socket, |
| 262 // since only TCP sockets are restartable. |
| 263 next_state_ = STATE_TCP_RESTART; |
261 transport_->socket()->Disconnect(); | 264 transport_->socket()->Disconnect(); |
262 rv = ERR_NO_KEEP_ALIVE_ON_AUTH_RESTART; | |
263 } | 265 } |
264 | 266 |
265 // Reset the other member variables. | 267 // Reset the other member variables. |
266 drain_buf_ = NULL; | 268 drain_buf_ = NULL; |
267 parser_buf_ = NULL; | 269 parser_buf_ = NULL; |
268 http_stream_parser_.reset(); | 270 http_stream_parser_.reset(); |
269 request_line_.clear(); | 271 request_line_.clear(); |
270 request_headers_.Clear(); | 272 request_headers_.Clear(); |
271 response_ = HttpResponseInfo(); | 273 response_ = HttpResponseInfo(); |
| 274 return OK; |
| 275 } |
| 276 |
| 277 int HttpProxyClientSocket::HandleAuthChallenge() { |
| 278 DCHECK(response_.headers); |
| 279 |
| 280 int rv = auth_->HandleAuthChallenge(response_.headers, false, true, net_log_); |
| 281 response_.auth_challenge = auth_->auth_info(); |
| 282 if (rv == OK) |
| 283 return ERR_PROXY_AUTH_REQUESTED; |
| 284 |
272 return rv; | 285 return rv; |
273 } | 286 } |
274 | 287 |
275 void HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const { | 288 void HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const { |
276 LOG(WARNING) << "Blocked proxy response with status " << response_code | 289 LOG(WARNING) << "Blocked proxy response with status " << response_code |
277 << " to CONNECT request for " | 290 << " to CONNECT request for " |
278 << GetHostAndPort(request_.url) << "."; | 291 << GetHostAndPort(request_.url) << "."; |
279 } | 292 } |
280 | 293 |
281 void HttpProxyClientSocket::DoCallback(int result) { | 294 void HttpProxyClientSocket::DoCallback(int result) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
334 net_log_.EndEventWithNetErrorCode( | 347 net_log_.EndEventWithNetErrorCode( |
335 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv); | 348 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv); |
336 break; | 349 break; |
337 case STATE_DRAIN_BODY: | 350 case STATE_DRAIN_BODY: |
338 DCHECK_EQ(OK, rv); | 351 DCHECK_EQ(OK, rv); |
339 rv = DoDrainBody(); | 352 rv = DoDrainBody(); |
340 break; | 353 break; |
341 case STATE_DRAIN_BODY_COMPLETE: | 354 case STATE_DRAIN_BODY_COMPLETE: |
342 rv = DoDrainBodyComplete(rv); | 355 rv = DoDrainBodyComplete(rv); |
343 break; | 356 break; |
| 357 case STATE_TCP_RESTART: |
| 358 DCHECK_EQ(OK, rv); |
| 359 rv = DoTCPRestart(); |
| 360 break; |
| 361 case STATE_TCP_RESTART_COMPLETE: |
| 362 rv = DoTCPRestartComplete(rv); |
| 363 break; |
344 case STATE_DONE: | 364 case STATE_DONE: |
345 break; | 365 break; |
346 default: | 366 default: |
347 NOTREACHED() << "bad state"; | 367 NOTREACHED() << "bad state"; |
348 rv = ERR_UNEXPECTED; | 368 rv = ERR_UNEXPECTED; |
349 break; | 369 break; |
350 } | 370 } |
351 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE && | 371 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE && |
352 next_state_ != STATE_DONE); | 372 next_state_ != STATE_DONE); |
353 return rv; | 373 return rv; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 // need to be very suspicious about the response because an active network | 452 // need to be very suspicious about the response because an active network |
433 // attacker can force us into this state by masquerading as the proxy. | 453 // attacker can force us into this state by masquerading as the proxy. |
434 // The only safe thing to do here is to fail the connection because our | 454 // The only safe thing to do here is to fail the connection because our |
435 // client is expecting an SSL protected response. | 455 // client is expecting an SSL protected response. |
436 // See http://crbug.com/7338. | 456 // See http://crbug.com/7338. |
437 case 407: // Proxy Authentication Required | 457 case 407: // Proxy Authentication Required |
438 // We need this status code to allow proxy authentication. Our | 458 // We need this status code to allow proxy authentication. Our |
439 // authentication code is smart enough to avoid being tricked by an | 459 // authentication code is smart enough to avoid being tricked by an |
440 // active network attacker. | 460 // active network attacker. |
441 // The next state is intentionally not set as it should be STATE_NONE; | 461 // The next state is intentionally not set as it should be STATE_NONE; |
442 return HandleAuthChallenge(auth_, &response_, net_log_); | 462 return HandleAuthChallenge(); |
443 | 463 |
444 default: | 464 default: |
445 if (is_https_proxy_) | 465 if (is_https_proxy_) |
446 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE; | 466 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE; |
447 // For all other status codes, we conservatively fail the CONNECT | 467 // For all other status codes, we conservatively fail the CONNECT |
448 // request. | 468 // request. |
449 // We lose something by doing this. We have seen proxy 403, 404, and | 469 // We lose something by doing this. We have seen proxy 403, 404, and |
450 // 501 response bodies that contain a useful error message. For | 470 // 501 response bodies that contain a useful error message. For |
451 // example, Squid uses a 404 response to report the DNS error: "The | 471 // example, Squid uses a 404 response to report the DNS error: "The |
452 // domain name does not exist." | 472 // domain name does not exist." |
(...skipping 15 matching lines...) Expand all Loading... |
468 return result; | 488 return result; |
469 | 489 |
470 if (http_stream_parser_->IsResponseBodyComplete()) | 490 if (http_stream_parser_->IsResponseBodyComplete()) |
471 return DidDrainBodyForAuthRestart(true); | 491 return DidDrainBodyForAuthRestart(true); |
472 | 492 |
473 // Keep draining. | 493 // Keep draining. |
474 next_state_ = STATE_DRAIN_BODY; | 494 next_state_ = STATE_DRAIN_BODY; |
475 return OK; | 495 return OK; |
476 } | 496 } |
477 | 497 |
| 498 int HttpProxyClientSocket::DoTCPRestart() { |
| 499 next_state_ = STATE_TCP_RESTART_COMPLETE; |
| 500 return transport_->socket()->Connect( |
| 501 base::Bind(&HttpProxyClientSocket::OnIOComplete, base::Unretained(this))); |
| 502 } |
| 503 |
| 504 int HttpProxyClientSocket::DoTCPRestartComplete(int result) { |
| 505 if (result != OK) |
| 506 return result; |
| 507 |
| 508 next_state_ = STATE_GENERATE_AUTH_TOKEN; |
| 509 return result; |
| 510 } |
| 511 |
478 } // namespace net | 512 } // namespace net |
OLD | NEW |