Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(340)

Side by Side Diff: net/http/http_proxy_client_socket.cc

Issue 9148011: Allow chrome to handle 407 auth challenges to CONNECT requests (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 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"
(...skipping 13 matching lines...) Expand all
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 HttpAuthCache* http_auth_cache, 34 HttpAuthController* http_auth_controller,
35 HttpAuthHandlerFactory* http_auth_handler_factory,
36 bool tunnel, 35 bool tunnel,
37 bool using_spdy, 36 bool using_spdy,
38 SSLClientSocket::NextProto protocol_negotiated, 37 SSLClientSocket::NextProto protocol_negotiated,
39 bool is_https_proxy) 38 bool is_https_proxy)
40 : ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_( 39 : ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(
41 base::Bind(&HttpProxyClientSocket::OnIOComplete, 40 base::Bind(&HttpProxyClientSocket::OnIOComplete,
42 base::Unretained(this)))), 41 base::Unretained(this)))),
43 next_state_(STATE_NONE), 42 next_state_(STATE_NONE),
44 transport_(transport_socket), 43 transport_(transport_socket),
45 endpoint_(endpoint), 44 endpoint_(endpoint),
46 auth_(tunnel ? 45 auth_(http_auth_controller),
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),
53 tunnel_(tunnel), 46 tunnel_(tunnel),
54 using_spdy_(using_spdy), 47 using_spdy_(using_spdy),
55 protocol_negotiated_(protocol_negotiated), 48 protocol_negotiated_(protocol_negotiated),
56 is_https_proxy_(is_https_proxy), 49 is_https_proxy_(is_https_proxy),
57 net_log_(transport_socket->socket()->NetLog()) { 50 net_log_(transport_socket->socket()->NetLog()) {
58 // Synthesize the bits of a request that we actually use. 51 // Synthesize the bits of a request that we actually use.
59 request_.url = request_url; 52 request_.url = request_url;
60 request_.method = "GET"; 53 request_.method = "GET";
61 if (!user_agent.empty()) 54 if (!user_agent.empty())
62 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, 55 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
63 user_agent); 56 user_agent);
64 } 57 }
65 58
66 HttpProxyClientSocket::~HttpProxyClientSocket() { 59 HttpProxyClientSocket::~HttpProxyClientSocket() {
67 Disconnect(); 60 Disconnect();
68 } 61 }
69 62
63 const
64 scoped_refptr<HttpAuthController>& HttpProxyClientSocket::GetAuthController() {
65 return auth_;
66 }
67
70 int HttpProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) { 68 int HttpProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) {
71 DCHECK_EQ(STATE_NONE, next_state_); 69 DCHECK_EQ(STATE_NONE, next_state_);
72 DCHECK(user_callback_.is_null()); 70 DCHECK(user_callback_.is_null());
73 71
74 int rv = PrepareForAuthRestart(); 72 int rv = PrepareForAuthRestart();
75 if (rv != OK) 73 if (rv != OK || next_state_ == STATE_NONE)
vandebo (ex-Chrome) 2012/01/20 20:49:29 This change isn't needed, rv will now be ERR_NO_KE
Ryan Hamilton 2012/01/20 21:51:35 Done.
Ryan Hamilton 2012/01/20 21:51:35 Done.
76 return rv; 74 return rv;
77 75
78 rv = DoLoop(OK); 76 rv = DoLoop(OK);
79 if (rv == ERR_IO_PENDING) { 77 if (rv == ERR_IO_PENDING) {
80 if (!callback.is_null()) 78 if (!callback.is_null())
81 user_callback_ = callback; 79 user_callback_ = callback;
82 } 80 }
83 81
84 return rv; 82 return rv;
85 } 83 }
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
251 // We don't need to drain the response body, so we act as if we had drained 249 // We don't need to drain the response body, so we act as if we had drained
252 // the response body. 250 // the response body.
253 return DidDrainBodyForAuthRestart(keep_alive); 251 return DidDrainBodyForAuthRestart(keep_alive);
254 } 252 }
255 253
256 int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) { 254 int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) {
257 if (keep_alive && transport_->socket()->IsConnectedAndIdle()) { 255 if (keep_alive && transport_->socket()->IsConnectedAndIdle()) {
258 next_state_ = STATE_GENERATE_AUTH_TOKEN; 256 next_state_ = STATE_GENERATE_AUTH_TOKEN;
259 transport_->set_is_reused(true); 257 transport_->set_is_reused(true);
260 } else { 258 } else {
261 // This assumes that the underlying transport socket is a TCP socket, 259 next_state_ = STATE_NONE;
262 // since only TCP sockets are restartable.
263 next_state_ = STATE_TCP_RESTART;
264 transport_->socket()->Disconnect();
vandebo (ex-Chrome) 2012/01/20 20:49:29 I think we still want to disconnect the socket, ot
Ryan Hamilton 2012/01/20 21:51:35 Done.
265 } 260 }
266 261
267 // Reset the other member variables. 262 // Reset the other member variables.
268 drain_buf_ = NULL; 263 drain_buf_ = NULL;
269 parser_buf_ = NULL; 264 parser_buf_ = NULL;
270 http_stream_parser_.reset(); 265 http_stream_parser_.reset();
271 request_line_.clear(); 266 request_line_.clear();
272 request_headers_.Clear(); 267 request_headers_.Clear();
273 response_ = HttpResponseInfo(); 268 response_ = HttpResponseInfo();
274 return OK; 269 return next_state_ == STATE_NONE ? ERR_NO_KEEP_ALIVE_ON_AUTH_RESTART : OK;
vandebo (ex-Chrome) 2012/01/20 20:49:29 nit: a tristate isn't necessary. int ret = OK at
Ryan Hamilton 2012/01/20 21:51:35 Done.
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
285 return rv;
286 } 270 }
287 271
288 void HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const { 272 void HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const {
289 LOG(WARNING) << "Blocked proxy response with status " << response_code 273 LOG(WARNING) << "Blocked proxy response with status " << response_code
290 << " to CONNECT request for " 274 << " to CONNECT request for "
291 << GetHostAndPort(request_.url) << "."; 275 << GetHostAndPort(request_.url) << ".";
292 } 276 }
293 277
294 void HttpProxyClientSocket::DoCallback(int result) { 278 void HttpProxyClientSocket::DoCallback(int result) {
295 DCHECK_NE(ERR_IO_PENDING, result); 279 DCHECK_NE(ERR_IO_PENDING, result);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 net_log_.EndEventWithNetErrorCode( 331 net_log_.EndEventWithNetErrorCode(
348 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv); 332 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
349 break; 333 break;
350 case STATE_DRAIN_BODY: 334 case STATE_DRAIN_BODY:
351 DCHECK_EQ(OK, rv); 335 DCHECK_EQ(OK, rv);
352 rv = DoDrainBody(); 336 rv = DoDrainBody();
353 break; 337 break;
354 case STATE_DRAIN_BODY_COMPLETE: 338 case STATE_DRAIN_BODY_COMPLETE:
355 rv = DoDrainBodyComplete(rv); 339 rv = DoDrainBodyComplete(rv);
356 break; 340 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;
364 case STATE_DONE: 341 case STATE_DONE:
365 break; 342 break;
366 default: 343 default:
367 NOTREACHED() << "bad state"; 344 NOTREACHED() << "bad state";
368 rv = ERR_UNEXPECTED; 345 rv = ERR_UNEXPECTED;
369 break; 346 break;
370 } 347 }
371 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE && 348 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
372 next_state_ != STATE_DONE); 349 next_state_ != STATE_DONE);
373 return rv; 350 return rv;
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 // need to be very suspicious about the response because an active network 429 // need to be very suspicious about the response because an active network
453 // attacker can force us into this state by masquerading as the proxy. 430 // attacker can force us into this state by masquerading as the proxy.
454 // The only safe thing to do here is to fail the connection because our 431 // The only safe thing to do here is to fail the connection because our
455 // client is expecting an SSL protected response. 432 // client is expecting an SSL protected response.
456 // See http://crbug.com/7338. 433 // See http://crbug.com/7338.
457 case 407: // Proxy Authentication Required 434 case 407: // Proxy Authentication Required
458 // We need this status code to allow proxy authentication. Our 435 // We need this status code to allow proxy authentication. Our
459 // authentication code is smart enough to avoid being tricked by an 436 // authentication code is smart enough to avoid being tricked by an
460 // active network attacker. 437 // active network attacker.
461 // The next state is intentionally not set as it should be STATE_NONE; 438 // The next state is intentionally not set as it should be STATE_NONE;
462 return HandleAuthChallenge(); 439 return HandleAuthChallenge(auth_, &response_, net_log_);
463 440
464 default: 441 default:
465 if (is_https_proxy_) 442 if (is_https_proxy_)
466 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE; 443 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
467 // For all other status codes, we conservatively fail the CONNECT 444 // For all other status codes, we conservatively fail the CONNECT
468 // request. 445 // request.
469 // We lose something by doing this. We have seen proxy 403, 404, and 446 // We lose something by doing this. We have seen proxy 403, 404, and
470 // 501 response bodies that contain a useful error message. For 447 // 501 response bodies that contain a useful error message. For
471 // example, Squid uses a 404 response to report the DNS error: "The 448 // example, Squid uses a 404 response to report the DNS error: "The
472 // domain name does not exist." 449 // domain name does not exist."
(...skipping 15 matching lines...) Expand all
488 return result; 465 return result;
489 466
490 if (http_stream_parser_->IsResponseBodyComplete()) 467 if (http_stream_parser_->IsResponseBodyComplete())
491 return DidDrainBodyForAuthRestart(true); 468 return DidDrainBodyForAuthRestart(true);
492 469
493 // Keep draining. 470 // Keep draining.
494 next_state_ = STATE_DRAIN_BODY; 471 next_state_ = STATE_DRAIN_BODY;
495 return OK; 472 return OK;
496 } 473 }
497 474
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
512 } // namespace net 475 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698