OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 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_network_transaction.h" | 5 #include "net/http/http_network_transaction.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/field_trial.h" | 8 #include "base/field_trial.h" |
9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
10 #include "base/histogram.h" | 10 #include "base/histogram.h" |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 pac_request_(NULL), | 289 pac_request_(NULL), |
290 connection_(new ClientSocketHandle), | 290 connection_(new ClientSocketHandle), |
291 reused_socket_(false), | 291 reused_socket_(false), |
292 headers_valid_(false), | 292 headers_valid_(false), |
293 logged_response_time_(false), | 293 logged_response_time_(false), |
294 using_ssl_(false), | 294 using_ssl_(false), |
295 using_spdy_(false), | 295 using_spdy_(false), |
296 alternate_protocol_mode_( | 296 alternate_protocol_mode_( |
297 g_use_alternate_protocols ? kUnspecified : | 297 g_use_alternate_protocols ? kUnspecified : |
298 kDoNotUseAlternateProtocol), | 298 kDoNotUseAlternateProtocol), |
299 embedded_identity_used_(false), | |
300 default_credentials_used_(false), | |
301 read_buf_len_(0), | 299 read_buf_len_(0), |
302 next_state_(STATE_NONE) { | 300 next_state_(STATE_NONE) { |
303 session->ssl_config_service()->GetSSLConfig(&ssl_config_); | 301 session->ssl_config_service()->GetSSLConfig(&ssl_config_); |
304 if (g_next_protos) | 302 if (g_next_protos) |
305 ssl_config_.next_protos = *g_next_protos; | 303 ssl_config_.next_protos = *g_next_protos; |
306 if (!g_tls_intolerant_servers) | 304 if (!g_tls_intolerant_servers) |
307 g_tls_intolerant_servers = new std::set<std::string>; | 305 g_tls_intolerant_servers = new std::set<std::string>; |
308 } | 306 } |
309 | 307 |
310 // static | 308 // static |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 | 388 |
391 int HttpNetworkTransaction::RestartWithAuth( | 389 int HttpNetworkTransaction::RestartWithAuth( |
392 const std::wstring& username, | 390 const std::wstring& username, |
393 const std::wstring& password, | 391 const std::wstring& password, |
394 CompletionCallback* callback) { | 392 CompletionCallback* callback) { |
395 HttpAuth::Target target = pending_auth_target_; | 393 HttpAuth::Target target = pending_auth_target_; |
396 if (target == HttpAuth::AUTH_NONE) { | 394 if (target == HttpAuth::AUTH_NONE) { |
397 NOTREACHED(); | 395 NOTREACHED(); |
398 return ERR_UNEXPECTED; | 396 return ERR_UNEXPECTED; |
399 } | 397 } |
400 | |
401 pending_auth_target_ = HttpAuth::AUTH_NONE; | 398 pending_auth_target_ = HttpAuth::AUTH_NONE; |
402 | 399 |
403 DCHECK(auth_identity_[target].invalid || | 400 auth_controllers_[target]->ResetAuth(username, password); |
404 (username.empty() && password.empty())); | |
405 | |
406 if (auth_identity_[target].invalid) { | |
407 // Update the username/password. | |
408 auth_identity_[target].source = HttpAuth::IDENT_SRC_EXTERNAL; | |
409 auth_identity_[target].invalid = false; | |
410 auth_identity_[target].username = username; | |
411 auth_identity_[target].password = password; | |
412 } | |
413 | 401 |
414 PrepareForAuthRestart(target); | 402 PrepareForAuthRestart(target); |
415 | 403 |
416 DCHECK(user_callback_ == NULL); | 404 DCHECK(user_callback_ == NULL); |
417 int rv = DoLoop(OK); | 405 int rv = DoLoop(OK); |
418 if (rv == ERR_IO_PENDING) | 406 if (rv == ERR_IO_PENDING) |
419 user_callback_ = callback; | 407 user_callback_ = callback; |
420 | 408 |
421 return rv; | 409 return rv; |
422 } | 410 } |
423 | 411 |
424 void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) { | 412 void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) { |
425 DCHECK(HaveAuth(target)); | 413 DCHECK(HaveAuth(target)); |
426 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP); | |
427 | |
428 // Add the auth entry to the cache before restarting. We don't know whether | |
429 // the identity is valid yet, but if it is valid we want other transactions | |
430 // to know about it. If an entry for (origin, handler->realm()) already | |
431 // exists, we update it. | |
432 // | |
433 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE or | |
434 // HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS, auth_identity_[target] contains | |
435 // no identity because identity is not required yet or we're using default | |
436 // credentials. | |
437 // | |
438 // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in | |
439 // round 1 and round 2, which is redundant but correct. It would be nice | |
440 // to add an auth entry to the cache only once, preferrably in round 1. | |
441 // See http://crbug.com/21015. | |
442 switch (auth_identity_[target].source) { | |
443 case HttpAuth::IDENT_SRC_NONE: | |
444 case HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS: | |
445 break; | |
446 default: | |
447 session_->auth_cache()->Add( | |
448 AuthOrigin(target), | |
449 auth_handler_[target]->realm(), | |
450 auth_handler_[target]->scheme(), | |
451 auth_handler_[target]->challenge(), | |
452 auth_identity_[target].username, | |
453 auth_identity_[target].password, | |
454 AuthPath(target)); | |
455 break; | |
456 } | |
457 | |
458 bool keep_alive = false; | 414 bool keep_alive = false; |
459 // Even if the server says the connection is keep-alive, we have to be | 415 // Even if the server says the connection is keep-alive, we have to be |
460 // able to find the end of each response in order to reuse the connection. | 416 // able to find the end of each response in order to reuse the connection. |
461 if (GetResponseHeaders()->IsKeepAlive() && | 417 if (GetResponseHeaders()->IsKeepAlive() && |
462 http_stream_->CanFindEndOfResponse()) { | 418 http_stream_->CanFindEndOfResponse()) { |
463 // If the response body hasn't been completely read, we need to drain | 419 // If the response body hasn't been completely read, we need to drain |
464 // it first. | 420 // it first. |
465 if (!http_stream_->IsResponseBodyComplete()) { | 421 if (!http_stream_->IsResponseBodyComplete()) { |
466 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; | 422 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; |
467 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket. | 423 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket. |
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
849 } | 805 } |
850 | 806 |
851 next_state_ = STATE_INIT_CONNECTION; | 807 next_state_ = STATE_INIT_CONNECTION; |
852 return OK; | 808 return OK; |
853 } | 809 } |
854 | 810 |
855 int HttpNetworkTransaction::DoInitConnection() { | 811 int HttpNetworkTransaction::DoInitConnection() { |
856 DCHECK(!connection_->is_initialized()); | 812 DCHECK(!connection_->is_initialized()); |
857 DCHECK(proxy_info_.proxy_server().is_valid()); | 813 DCHECK(proxy_info_.proxy_server().is_valid()); |
858 | 814 |
| 815 // Now that the proxy server has been resolved, create the auth_controllers_. |
| 816 for (int i = 0; i < HttpAuth::AUTH_NUM_TARGETS; i++) { |
| 817 HttpAuth::Target target = static_cast<HttpAuth::Target>(i); |
| 818 if (!auth_controllers_[target].get()) |
| 819 auth_controllers_[target].reset(new HttpAuthController(target, |
| 820 AuthURL(target), |
| 821 session_, |
| 822 net_log_)); |
| 823 } |
| 824 |
859 next_state_ = STATE_INIT_CONNECTION_COMPLETE; | 825 next_state_ = STATE_INIT_CONNECTION_COMPLETE; |
860 | 826 |
861 using_ssl_ = request_->url.SchemeIs("https") || | 827 using_ssl_ = request_->url.SchemeIs("https") || |
862 (alternate_protocol_mode_ == kUsingAlternateProtocol && | 828 (alternate_protocol_mode_ == kUsingAlternateProtocol && |
863 alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1); | 829 alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1); |
864 | 830 |
865 using_spdy_ = false; | 831 using_spdy_ = false; |
866 | 832 |
867 // Build the string used to uniquely identify connections of this type. | 833 // Build the string used to uniquely identify connections of this type. |
868 // Determine the host and port to connect to. | 834 // Determine the host and port to connect to. |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
996 | 962 |
997 void HttpNetworkTransaction::ClearTunnelState() { | 963 void HttpNetworkTransaction::ClearTunnelState() { |
998 http_stream_.reset(); | 964 http_stream_.reset(); |
999 request_headers_.clear(); | 965 request_headers_.clear(); |
1000 response_ = HttpResponseInfo(); | 966 response_ = HttpResponseInfo(); |
1001 headers_valid_ = false; | 967 headers_valid_ = false; |
1002 } | 968 } |
1003 | 969 |
1004 int HttpNetworkTransaction::DoTunnelGenerateAuthToken() { | 970 int HttpNetworkTransaction::DoTunnelGenerateAuthToken() { |
1005 next_state_ = STATE_TUNNEL_GENERATE_AUTH_TOKEN_COMPLETE; | 971 next_state_ = STATE_TUNNEL_GENERATE_AUTH_TOKEN_COMPLETE; |
1006 return MaybeGenerateAuthToken(HttpAuth::AUTH_PROXY); | 972 return auth_controllers_[HttpAuth::AUTH_PROXY]->MaybeGenerateAuthToken( |
| 973 request_, &io_callback_); |
1007 } | 974 } |
1008 | 975 |
1009 int HttpNetworkTransaction::DoTunnelGenerateAuthTokenComplete(int rv) { | 976 int HttpNetworkTransaction::DoTunnelGenerateAuthTokenComplete(int rv) { |
1010 DCHECK_NE(ERR_IO_PENDING, rv); | 977 DCHECK_NE(ERR_IO_PENDING, rv); |
1011 if (rv == OK) | 978 if (rv == OK) |
1012 next_state_ = STATE_TUNNEL_SEND_REQUEST; | 979 next_state_ = STATE_TUNNEL_SEND_REQUEST; |
1013 return rv; | 980 return rv; |
1014 } | 981 } |
1015 | 982 |
1016 int HttpNetworkTransaction::DoTunnelSendRequest() { | 983 int HttpNetworkTransaction::DoTunnelSendRequest() { |
1017 next_state_ = STATE_TUNNEL_SEND_REQUEST_COMPLETE; | 984 next_state_ = STATE_TUNNEL_SEND_REQUEST_COMPLETE; |
1018 | 985 |
1019 // This is constructed lazily (instead of within our Start method), so that | 986 // This is constructed lazily (instead of within our Start method), so that |
1020 // we have proxy info available. | 987 // we have proxy info available. |
1021 if (request_headers_.empty()) { | 988 if (request_headers_.empty()) { |
1022 HttpRequestHeaders authorization_headers; | 989 HttpRequestHeaders authorization_headers; |
1023 if (HaveAuth(HttpAuth::AUTH_PROXY)) | 990 if (HaveAuth(HttpAuth::AUTH_PROXY)) |
1024 AddAuthorizationHeader(HttpAuth::AUTH_PROXY, &authorization_headers); | 991 auth_controllers_[HttpAuth::AUTH_PROXY]->AddAuthorizationHeader( |
| 992 &authorization_headers); |
1025 std::string request_line; | 993 std::string request_line; |
1026 HttpRequestHeaders request_headers; | 994 HttpRequestHeaders request_headers; |
1027 BuildTunnelRequest(request_, authorization_headers, endpoint_, | 995 BuildTunnelRequest(request_, authorization_headers, endpoint_, |
1028 &request_line, &request_headers); | 996 &request_line, &request_headers); |
1029 if (net_log_.HasListener()) { | 997 if (net_log_.HasListener()) { |
1030 net_log_.AddEvent( | 998 net_log_.AddEvent( |
1031 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | 999 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, |
1032 new NetLogHttpRequestParameter( | 1000 new NetLogHttpRequestParameter( |
1033 request_line, request_headers)); | 1001 request_line, request_headers)); |
1034 } | 1002 } |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1206 } else { | 1174 } else { |
1207 result = HandleSSLHandshakeError(result); | 1175 result = HandleSSLHandshakeError(result); |
1208 } | 1176 } |
1209 return result; | 1177 return result; |
1210 } | 1178 } |
1211 | 1179 |
1212 int HttpNetworkTransaction::DoGenerateProxyAuthToken() { | 1180 int HttpNetworkTransaction::DoGenerateProxyAuthToken() { |
1213 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE; | 1181 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE; |
1214 if (!ShouldApplyProxyAuth()) | 1182 if (!ShouldApplyProxyAuth()) |
1215 return OK; | 1183 return OK; |
1216 return MaybeGenerateAuthToken(HttpAuth::AUTH_PROXY); | 1184 return auth_controllers_[HttpAuth::AUTH_PROXY]->MaybeGenerateAuthToken( |
| 1185 request_, &io_callback_); |
1217 } | 1186 } |
1218 | 1187 |
1219 int HttpNetworkTransaction::DoGenerateProxyAuthTokenComplete(int rv) { | 1188 int HttpNetworkTransaction::DoGenerateProxyAuthTokenComplete(int rv) { |
1220 DCHECK_NE(ERR_IO_PENDING, rv); | 1189 DCHECK_NE(ERR_IO_PENDING, rv); |
1221 if (rv == OK) | 1190 if (rv == OK) |
1222 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN; | 1191 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN; |
1223 return rv; | 1192 return rv; |
1224 } | 1193 } |
1225 | 1194 |
1226 int HttpNetworkTransaction::DoGenerateServerAuthToken() { | 1195 int HttpNetworkTransaction::DoGenerateServerAuthToken() { |
1227 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE; | 1196 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE; |
1228 if (!ShouldApplyServerAuth()) | 1197 if (!ShouldApplyServerAuth()) |
1229 return OK; | 1198 return OK; |
1230 return MaybeGenerateAuthToken(HttpAuth::AUTH_SERVER); | 1199 return auth_controllers_[HttpAuth::AUTH_SERVER]->MaybeGenerateAuthToken( |
| 1200 request_, &io_callback_); |
1231 } | 1201 } |
1232 | 1202 |
1233 int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) { | 1203 int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) { |
1234 DCHECK_NE(ERR_IO_PENDING, rv); | 1204 DCHECK_NE(ERR_IO_PENDING, rv); |
1235 if (rv == OK) | 1205 if (rv == OK) |
1236 next_state_ = STATE_SEND_REQUEST; | 1206 next_state_ = STATE_SEND_REQUEST; |
1237 return rv; | 1207 return rv; |
1238 } | 1208 } |
1239 | 1209 |
1240 int HttpNetworkTransaction::DoSendRequest() { | 1210 int HttpNetworkTransaction::DoSendRequest() { |
(...skipping 11 matching lines...) Expand all Loading... |
1252 // we have proxy info available. | 1222 // we have proxy info available. |
1253 if (request_headers_.empty()) { | 1223 if (request_headers_.empty()) { |
1254 // Figure out if we can/should add Proxy-Authentication & Authentication | 1224 // Figure out if we can/should add Proxy-Authentication & Authentication |
1255 // headers. | 1225 // headers. |
1256 HttpRequestHeaders authorization_headers; | 1226 HttpRequestHeaders authorization_headers; |
1257 bool have_proxy_auth = (ShouldApplyProxyAuth() && | 1227 bool have_proxy_auth = (ShouldApplyProxyAuth() && |
1258 HaveAuth(HttpAuth::AUTH_PROXY)); | 1228 HaveAuth(HttpAuth::AUTH_PROXY)); |
1259 bool have_server_auth = (ShouldApplyServerAuth() && | 1229 bool have_server_auth = (ShouldApplyServerAuth() && |
1260 HaveAuth(HttpAuth::AUTH_SERVER)); | 1230 HaveAuth(HttpAuth::AUTH_SERVER)); |
1261 if (have_proxy_auth) | 1231 if (have_proxy_auth) |
1262 AddAuthorizationHeader(HttpAuth::AUTH_PROXY, &authorization_headers); | 1232 auth_controllers_[HttpAuth::AUTH_PROXY]->AddAuthorizationHeader( |
| 1233 &authorization_headers); |
1263 if (have_server_auth) | 1234 if (have_server_auth) |
1264 AddAuthorizationHeader(HttpAuth::AUTH_SERVER, &authorization_headers); | 1235 auth_controllers_[HttpAuth::AUTH_SERVER]->AddAuthorizationHeader( |
| 1236 &authorization_headers); |
1265 std::string request_line; | 1237 std::string request_line; |
1266 HttpRequestHeaders request_headers; | 1238 HttpRequestHeaders request_headers; |
1267 BuildRequestHeaders(request_, authorization_headers, request_body, | 1239 BuildRequestHeaders(request_, authorization_headers, request_body, |
1268 !using_ssl_ && proxy_info_.is_http(), &request_line, | 1240 !using_ssl_ && proxy_info_.is_http(), &request_line, |
1269 &request_headers); | 1241 &request_headers); |
1270 | 1242 |
1271 if (session_->network_delegate()) | 1243 if (session_->network_delegate()) |
1272 session_->network_delegate()->OnSendHttpRequest(&request_headers); | 1244 session_->network_delegate()->OnSendHttpRequest(&request_headers); |
1273 | 1245 |
1274 if (net_log_.HasListener()) { | 1246 if (net_log_.HasListener()) { |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1402 SSLClientSocket* ssl_socket = | 1374 SSLClientSocket* ssl_socket = |
1403 reinterpret_cast<SSLClientSocket*>(connection_->socket()); | 1375 reinterpret_cast<SSLClientSocket*>(connection_->socket()); |
1404 ssl_socket->GetSSLInfo(&response_.ssl_info); | 1376 ssl_socket->GetSSLInfo(&response_.ssl_info); |
1405 } | 1377 } |
1406 | 1378 |
1407 headers_valid_ = true; | 1379 headers_valid_ = true; |
1408 return OK; | 1380 return OK; |
1409 } | 1381 } |
1410 | 1382 |
1411 int HttpNetworkTransaction::DoResolveCanonicalName() { | 1383 int HttpNetworkTransaction::DoResolveCanonicalName() { |
1412 DCHECK(auth_handler_[pending_auth_target_].get()); | 1384 DCHECK(auth_controllers_[pending_auth_target_].get()); |
1413 next_state_ = STATE_RESOLVE_CANONICAL_NAME_COMPLETE; | 1385 next_state_ = STATE_RESOLVE_CANONICAL_NAME_COMPLETE; |
1414 return auth_handler_[pending_auth_target_]-> | 1386 return auth_controllers_[pending_auth_target_]->ResolveCanonicalName( |
1415 ResolveCanonicalName(session_->host_resolver(), &io_callback_); | 1387 &io_callback_); |
1416 } | 1388 } |
1417 | 1389 |
1418 int HttpNetworkTransaction::DoResolveCanonicalNameComplete(int result) { | 1390 int HttpNetworkTransaction::DoResolveCanonicalNameComplete(int result) { |
1419 // The STATE_RESOLVE_CANONICAL_NAME state ends the Start sequence when the | 1391 // The STATE_RESOLVE_CANONICAL_NAME state ends the Start sequence when the |
1420 // canonical name of the server needs to be determined. Normally | 1392 // canonical name of the server needs to be determined. Normally |
1421 // DoReadHeadersComplete completes the sequence. The next state is | 1393 // DoReadHeadersComplete completes the sequence. The next state is |
1422 // intentionally not set as it should be STATE_NONE; | 1394 // intentionally not set as it should be STATE_NONE; |
1423 DCHECK_EQ(STATE_NONE, next_state_); | 1395 DCHECK_EQ(STATE_NONE, next_state_); |
1424 return result; | 1396 return result; |
1425 } | 1397 } |
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1964 } | 1936 } |
1965 | 1937 |
1966 bool HttpNetworkTransaction::ShouldApplyProxyAuth() const { | 1938 bool HttpNetworkTransaction::ShouldApplyProxyAuth() const { |
1967 return !using_ssl_ && proxy_info_.is_http(); | 1939 return !using_ssl_ && proxy_info_.is_http(); |
1968 } | 1940 } |
1969 | 1941 |
1970 bool HttpNetworkTransaction::ShouldApplyServerAuth() const { | 1942 bool HttpNetworkTransaction::ShouldApplyServerAuth() const { |
1971 return !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA); | 1943 return !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA); |
1972 } | 1944 } |
1973 | 1945 |
1974 int HttpNetworkTransaction::MaybeGenerateAuthToken(HttpAuth::Target target) { | |
1975 bool needs_auth = HaveAuth(target) || SelectPreemptiveAuth(target); | |
1976 if (!needs_auth) | |
1977 return OK; | |
1978 const std::wstring* username = NULL; | |
1979 const std::wstring* password = NULL; | |
1980 const HttpAuth::Identity& identity = auth_identity_[target]; | |
1981 if (identity.source != HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS) { | |
1982 username = &identity.username; | |
1983 password = &identity.password; | |
1984 } | |
1985 DCHECK(auth_token_[target].empty()); | |
1986 return auth_handler_[target]->GenerateAuthToken( | |
1987 username, password, request_, &io_callback_, &auth_token_[target]); | |
1988 } | |
1989 | |
1990 void HttpNetworkTransaction::AddAuthorizationHeader( | |
1991 HttpAuth::Target target, HttpRequestHeaders* authorization_headers) { | |
1992 DCHECK(HaveAuth(target)); | |
1993 DCHECK(!auth_token_[target].empty()); | |
1994 authorization_headers->SetHeader( | |
1995 HttpAuth::GetAuthorizationHeaderName(target), | |
1996 auth_token_[target]); | |
1997 auth_token_[target].clear(); | |
1998 } | |
1999 | |
2000 GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const { | |
2001 GURL origin = PossiblyInvalidAuthOrigin(target); | |
2002 DCHECK(origin.is_valid()); | |
2003 return origin; | |
2004 } | |
2005 | |
2006 GURL HttpNetworkTransaction::PossiblyInvalidAuthOrigin( | |
2007 HttpAuth::Target target) const { | |
2008 switch (target) { | |
2009 case HttpAuth::AUTH_PROXY: | |
2010 if (!proxy_info_.proxy_server().is_valid() || | |
2011 proxy_info_.proxy_server().is_direct()) { | |
2012 return GURL(); // There is no proxy server. | |
2013 } | |
2014 return GURL("http://" + proxy_info_.proxy_server().host_and_port()); | |
2015 case HttpAuth::AUTH_SERVER: | |
2016 return request_->url.GetOrigin(); | |
2017 default: | |
2018 return GURL(); | |
2019 } | |
2020 } | |
2021 | |
2022 std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target) | |
2023 const { | |
2024 // Proxy authentication realms apply to all paths. So we will use | |
2025 // empty string in place of an absolute path. | |
2026 return target == HttpAuth::AUTH_PROXY ? | |
2027 std::string() : request_->url.path(); | |
2028 } | |
2029 | |
2030 // static | |
2031 std::string HttpNetworkTransaction::AuthTargetString( | |
2032 HttpAuth::Target target) { | |
2033 return target == HttpAuth::AUTH_PROXY ? "proxy" : "server"; | |
2034 } | |
2035 | |
2036 void HttpNetworkTransaction::InvalidateRejectedAuthFromCache( | |
2037 HttpAuth::Target target, | |
2038 const GURL& auth_origin) { | |
2039 DCHECK(HaveAuth(target)); | |
2040 | |
2041 // TODO(eroman): this short-circuit can be relaxed. If the realm of | |
2042 // the preemptively used auth entry matches the realm of the subsequent | |
2043 // challenge, then we can invalidate the preemptively used entry. | |
2044 // Otherwise as-is we may send the failed credentials one extra time. | |
2045 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP) | |
2046 return; | |
2047 | |
2048 // Clear the cache entry for the identity we just failed on. | |
2049 // Note: we require the username/password to match before invalidating | |
2050 // since the entry in the cache may be newer than what we used last time. | |
2051 session_->auth_cache()->Remove(auth_origin, | |
2052 auth_handler_[target]->realm(), | |
2053 auth_handler_[target]->scheme(), | |
2054 auth_identity_[target].username, | |
2055 auth_identity_[target].password); | |
2056 } | |
2057 | |
2058 bool HttpNetworkTransaction::SelectPreemptiveAuth(HttpAuth::Target target) { | |
2059 DCHECK(!HaveAuth(target)); | |
2060 | |
2061 // Don't do preemptive authorization if the URL contains a username/password, | |
2062 // since we must first be challenged in order to use the URL's identity. | |
2063 if (request_->url.has_username()) | |
2064 return false; | |
2065 | |
2066 // SelectPreemptiveAuth() is on the critical path for each request, so it | |
2067 // is expected to be fast. LookupByPath() is fast in the common case, since | |
2068 // the number of http auth cache entries is expected to be very small. | |
2069 // (For most users in fact, it will be 0.) | |
2070 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath( | |
2071 AuthOrigin(target), AuthPath(target)); | |
2072 if (!entry) | |
2073 return false; | |
2074 | |
2075 // Try to create a handler using the previous auth challenge. | |
2076 scoped_ptr<HttpAuthHandler> handler_preemptive; | |
2077 int rv_create = session_->http_auth_handler_factory()-> | |
2078 CreatePreemptiveAuthHandlerFromString( | |
2079 entry->auth_challenge(), target, AuthOrigin(target), | |
2080 entry->IncrementNonceCount(), net_log_, &handler_preemptive); | |
2081 if (rv_create != OK) | |
2082 return false; | |
2083 | |
2084 // Set the state | |
2085 auth_identity_[target].source = HttpAuth::IDENT_SRC_PATH_LOOKUP; | |
2086 auth_identity_[target].invalid = false; | |
2087 auth_identity_[target].username = entry->username(); | |
2088 auth_identity_[target].password = entry->password(); | |
2089 auth_handler_[target].swap(handler_preemptive); | |
2090 return true; | |
2091 } | |
2092 | |
2093 bool HttpNetworkTransaction::SelectNextAuthIdentityToTry( | |
2094 HttpAuth::Target target, | |
2095 const GURL& auth_origin) { | |
2096 DCHECK(auth_handler_[target].get()); | |
2097 DCHECK(auth_identity_[target].invalid); | |
2098 | |
2099 // Try to use the username/password encoded into the URL first. | |
2100 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() && | |
2101 !embedded_identity_used_) { | |
2102 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL; | |
2103 auth_identity_[target].invalid = false; | |
2104 // Extract the username:password from the URL. | |
2105 GetIdentityFromURL(request_->url, | |
2106 &auth_identity_[target].username, | |
2107 &auth_identity_[target].password); | |
2108 embedded_identity_used_ = true; | |
2109 // TODO(eroman): If the password is blank, should we also try combining | |
2110 // with a password from the cache? | |
2111 return true; | |
2112 } | |
2113 | |
2114 // Check the auth cache for a realm entry. | |
2115 HttpAuthCache::Entry* entry = | |
2116 session_->auth_cache()->Lookup(auth_origin, auth_handler_[target]->realm(), | |
2117 auth_handler_[target]->scheme()); | |
2118 | |
2119 if (entry) { | |
2120 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP; | |
2121 auth_identity_[target].invalid = false; | |
2122 auth_identity_[target].username = entry->username(); | |
2123 auth_identity_[target].password = entry->password(); | |
2124 return true; | |
2125 } | |
2126 | |
2127 // Use default credentials (single sign on) if this is the first attempt | |
2128 // at identity. Do not allow multiple times as it will infinite loop. | |
2129 // We use default credentials after checking the auth cache so that if | |
2130 // single sign-on doesn't work, we won't try default credentials for future | |
2131 // transactions. | |
2132 if (!default_credentials_used_ && | |
2133 auth_handler_[target]->AllowsDefaultCredentials()) { | |
2134 auth_identity_[target].source = HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS; | |
2135 auth_identity_[target].invalid = false; | |
2136 default_credentials_used_ = true; | |
2137 return true; | |
2138 } | |
2139 | |
2140 return false; | |
2141 } | |
2142 | |
2143 std::string HttpNetworkTransaction::AuthChallengeLogMessage() const { | |
2144 std::string msg; | |
2145 std::string header_val; | |
2146 void* iter = NULL; | |
2147 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders(); | |
2148 while (headers->EnumerateHeader(&iter, "proxy-authenticate", &header_val)) { | |
2149 msg.append("\n Has header Proxy-Authenticate: "); | |
2150 msg.append(header_val); | |
2151 } | |
2152 | |
2153 iter = NULL; | |
2154 while (headers->EnumerateHeader(&iter, "www-authenticate", &header_val)) { | |
2155 msg.append("\n Has header WWW-Authenticate: "); | |
2156 msg.append(header_val); | |
2157 } | |
2158 | |
2159 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate | |
2160 // authentication with a "Proxy-Support: Session-Based-Authentication" | |
2161 // response header. | |
2162 iter = NULL; | |
2163 while (headers->EnumerateHeader(&iter, "proxy-support", &header_val)) { | |
2164 msg.append("\n Has header Proxy-Support: "); | |
2165 msg.append(header_val); | |
2166 } | |
2167 | |
2168 return msg; | |
2169 } | |
2170 | |
2171 int HttpNetworkTransaction::HandleAuthChallenge(bool establishing_tunnel) { | 1946 int HttpNetworkTransaction::HandleAuthChallenge(bool establishing_tunnel) { |
2172 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders(); | 1947 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders(); |
2173 DCHECK(headers); | 1948 DCHECK(headers); |
2174 | 1949 |
2175 int status = headers->response_code(); | 1950 int status = headers->response_code(); |
2176 if (status != 401 && status != 407) | 1951 if (status != 401 && status != 407) |
2177 return OK; | 1952 return OK; |
2178 HttpAuth::Target target = status == 407 ? | 1953 HttpAuth::Target target = status == 407 ? |
2179 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER; | 1954 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER; |
2180 GURL auth_origin = PossiblyInvalidAuthOrigin(target); | |
2181 | |
2182 LOG(INFO) << "The " << AuthTargetString(target) << " " | |
2183 << auth_origin << " requested auth" | |
2184 << AuthChallengeLogMessage(); | |
2185 | |
2186 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) | 1955 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) |
2187 return ERR_UNEXPECTED_PROXY_AUTH; | 1956 return ERR_UNEXPECTED_PROXY_AUTH; |
2188 DCHECK(auth_origin.is_valid()); | |
2189 | 1957 |
2190 // The auth we tried just failed, hence it can't be valid. Remove it from | 1958 int rv = auth_controllers_[target]->HandleAuthChallenge(headers, |
2191 // the cache so it won't be used again. | 1959 request_->load_flags, |
2192 // TODO(wtc): IsFinalRound is not the right condition. In a multi-round | 1960 establishing_tunnel); |
2193 // auth sequence, the server may fail the auth in round 1 if our first | 1961 if (auth_controllers_[target]->HaveAuthHandler()) |
2194 // authorization header is broken. We should inspect response_.headers to | 1962 pending_auth_target_ = target; |
2195 // determine if the server already failed the auth or wants us to continue. | 1963 |
2196 // See http://crbug.com/21015. | 1964 scoped_refptr<AuthChallengeInfo> auth_info = |
2197 if (HaveAuth(target) && auth_handler_[target]->IsFinalRound()) { | 1965 auth_controllers_[target]->auth_info(); |
2198 InvalidateRejectedAuthFromCache(target, auth_origin); | 1966 if (auth_info.get()) |
2199 auth_handler_[target].reset(); | 1967 response_.auth_challenge = auth_info; |
2200 auth_identity_[target] = HttpAuth::Identity(); | 1968 |
| 1969 if (rv == ERR_AUTH_NEEDS_CANONICAL_NAME) { |
| 1970 next_state_ = STATE_RESOLVE_CANONICAL_NAME; |
| 1971 rv = OK; |
2201 } | 1972 } |
2202 | 1973 |
2203 auth_identity_[target].invalid = true; | 1974 return rv; |
2204 | |
2205 if (target != HttpAuth::AUTH_SERVER || | |
2206 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) { | |
2207 // Find the best authentication challenge that we support. | |
2208 HttpAuth::ChooseBestChallenge(session_->http_auth_handler_factory(), | |
2209 headers, target, auth_origin, net_log_, | |
2210 &auth_handler_[target]); | |
2211 } | |
2212 | |
2213 if (!auth_handler_[target].get()) { | |
2214 if (establishing_tunnel) { | |
2215 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target) | |
2216 << " " << auth_origin << " when establishing a tunnel" | |
2217 << AuthChallengeLogMessage(); | |
2218 | |
2219 // We are establishing a tunnel, we can't show the error page because an | |
2220 // active network attacker could control its contents. Instead, we just | |
2221 // fail to establish the tunnel. | |
2222 DCHECK(target == HttpAuth::AUTH_PROXY); | |
2223 return ERR_PROXY_AUTH_REQUESTED; | |
2224 } | |
2225 // We found no supported challenge -- let the transaction continue | |
2226 // so we end up displaying the error page. | |
2227 return OK; | |
2228 } | |
2229 | |
2230 if (auth_handler_[target]->NeedsIdentity()) { | |
2231 // Pick a new auth identity to try, by looking to the URL and auth cache. | |
2232 // If an identity to try is found, it is saved to auth_identity_[target]. | |
2233 SelectNextAuthIdentityToTry(target, auth_origin); | |
2234 } else { | |
2235 // Proceed with the existing identity or a null identity. | |
2236 // | |
2237 // TODO(wtc): Add a safeguard against infinite transaction restarts, if | |
2238 // the server keeps returning "NTLM". | |
2239 auth_identity_[target].invalid = false; | |
2240 } | |
2241 | |
2242 // Make a note that we are waiting for auth. This variable is inspected | |
2243 // when the client calls RestartWithAuth() to pick up where we left off. | |
2244 pending_auth_target_ = target; | |
2245 | |
2246 if (auth_identity_[target].invalid) { | |
2247 // We have exhausted all identity possibilities, all we can do now is | |
2248 // pass the challenge information back to the client. | |
2249 PopulateAuthChallenge(target, auth_origin); | |
2250 } | |
2251 | |
2252 // SPN determination (for Negotiate) requires a DNS lookup to find the | |
2253 // canonical name. This needs to be done asynchronously to prevent blocking | |
2254 // the IO thread. | |
2255 if (auth_handler_[target]->NeedsCanonicalName()) | |
2256 next_state_ = STATE_RESOLVE_CANONICAL_NAME; | |
2257 | |
2258 return OK; | |
2259 } | 1975 } |
2260 | 1976 |
2261 void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target, | 1977 GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const { |
2262 const GURL& auth_origin) { | 1978 switch (target) { |
2263 // Populates response_.auth_challenge with the authentication challenge info. | 1979 case HttpAuth::AUTH_PROXY: |
2264 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo(). | 1980 if (!proxy_info_.proxy_server().is_valid() || |
2265 | 1981 proxy_info_.proxy_server().is_direct()) { |
2266 AuthChallengeInfo* auth_info = new AuthChallengeInfo; | 1982 return GURL(); // There is no proxy server. |
2267 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY; | 1983 } |
2268 auth_info->host_and_port = ASCIIToWide(GetHostAndPort(auth_origin)); | 1984 return GURL("http://" + proxy_info_.proxy_server().host_and_port()); |
2269 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme()); | 1985 case HttpAuth::AUTH_SERVER: |
2270 // TODO(eroman): decode realm according to RFC 2047. | 1986 return request_->url; |
2271 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm()); | 1987 default: |
2272 response_.auth_challenge = auth_info; | 1988 return GURL(); |
| 1989 } |
2273 } | 1990 } |
2274 | 1991 |
2275 void HttpNetworkTransaction::MarkBrokenAlternateProtocolAndFallback() { | 1992 void HttpNetworkTransaction::MarkBrokenAlternateProtocolAndFallback() { |
2276 // We have to: | 1993 // We have to: |
2277 // * Reset the endpoint to be the unmodified URL specified destination. | 1994 // * Reset the endpoint to be the unmodified URL specified destination. |
2278 // * Mark the endpoint as broken so we don't try again. | 1995 // * Mark the endpoint as broken so we don't try again. |
2279 // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we | 1996 // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we |
2280 // ignore future Alternate-Protocol headers from the HostPortPair. | 1997 // ignore future Alternate-Protocol headers from the HostPortPair. |
2281 // * Reset the connection and go back to STATE_INIT_CONNECTION. | 1998 // * Reset the connection and go back to STATE_INIT_CONNECTION. |
2282 | 1999 |
2283 endpoint_ = HostPortPair(request_->url.HostNoBrackets(), | 2000 endpoint_ = HostPortPair(request_->url.HostNoBrackets(), |
2284 request_->url.EffectiveIntPort()); | 2001 request_->url.EffectiveIntPort()); |
2285 | 2002 |
2286 session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor( | 2003 session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor( |
2287 endpoint_); | 2004 endpoint_); |
2288 | 2005 |
2289 alternate_protocol_mode_ = kDoNotUseAlternateProtocol; | 2006 alternate_protocol_mode_ = kDoNotUseAlternateProtocol; |
2290 if (connection_->socket()) | 2007 if (connection_->socket()) |
2291 connection_->socket()->Disconnect(); | 2008 connection_->socket()->Disconnect(); |
2292 connection_->Reset(); | 2009 connection_->Reset(); |
2293 next_state_ = STATE_INIT_CONNECTION; | 2010 next_state_ = STATE_INIT_CONNECTION; |
2294 } | 2011 } |
2295 | 2012 |
2296 } // namespace net | 2013 } // namespace net |
OLD | NEW |