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), |
299 read_buf_len_(0), | 301 read_buf_len_(0), |
300 next_state_(STATE_NONE) { | 302 next_state_(STATE_NONE) { |
301 session->ssl_config_service()->GetSSLConfig(&ssl_config_); | 303 session->ssl_config_service()->GetSSLConfig(&ssl_config_); |
302 if (g_next_protos) | 304 if (g_next_protos) |
303 ssl_config_.next_protos = *g_next_protos; | 305 ssl_config_.next_protos = *g_next_protos; |
304 if (!g_tls_intolerant_servers) | 306 if (!g_tls_intolerant_servers) |
305 g_tls_intolerant_servers = new std::set<std::string>; | 307 g_tls_intolerant_servers = new std::set<std::string>; |
306 } | 308 } |
307 | 309 |
308 // static | 310 // static |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
388 | 390 |
389 int HttpNetworkTransaction::RestartWithAuth( | 391 int HttpNetworkTransaction::RestartWithAuth( |
390 const std::wstring& username, | 392 const std::wstring& username, |
391 const std::wstring& password, | 393 const std::wstring& password, |
392 CompletionCallback* callback) { | 394 CompletionCallback* callback) { |
393 HttpAuth::Target target = pending_auth_target_; | 395 HttpAuth::Target target = pending_auth_target_; |
394 if (target == HttpAuth::AUTH_NONE) { | 396 if (target == HttpAuth::AUTH_NONE) { |
395 NOTREACHED(); | 397 NOTREACHED(); |
396 return ERR_UNEXPECTED; | 398 return ERR_UNEXPECTED; |
397 } | 399 } |
| 400 |
398 pending_auth_target_ = HttpAuth::AUTH_NONE; | 401 pending_auth_target_ = HttpAuth::AUTH_NONE; |
399 | 402 |
400 auth_controllers_[target]->ResetAuth(username, password); | 403 DCHECK(auth_identity_[target].invalid || |
| 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 } |
401 | 413 |
402 PrepareForAuthRestart(target); | 414 PrepareForAuthRestart(target); |
403 | 415 |
404 DCHECK(user_callback_ == NULL); | 416 DCHECK(user_callback_ == NULL); |
405 int rv = DoLoop(OK); | 417 int rv = DoLoop(OK); |
406 if (rv == ERR_IO_PENDING) | 418 if (rv == ERR_IO_PENDING) |
407 user_callback_ = callback; | 419 user_callback_ = callback; |
408 | 420 |
409 return rv; | 421 return rv; |
410 } | 422 } |
411 | 423 |
412 void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) { | 424 void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) { |
413 DCHECK(HaveAuth(target)); | 425 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 |
414 bool keep_alive = false; | 458 bool keep_alive = false; |
415 // Even if the server says the connection is keep-alive, we have to be | 459 // Even if the server says the connection is keep-alive, we have to be |
416 // able to find the end of each response in order to reuse the connection. | 460 // able to find the end of each response in order to reuse the connection. |
417 if (GetResponseHeaders()->IsKeepAlive() && | 461 if (GetResponseHeaders()->IsKeepAlive() && |
418 http_stream_->CanFindEndOfResponse()) { | 462 http_stream_->CanFindEndOfResponse()) { |
419 // If the response body hasn't been completely read, we need to drain | 463 // If the response body hasn't been completely read, we need to drain |
420 // it first. | 464 // it first. |
421 if (!http_stream_->IsResponseBodyComplete()) { | 465 if (!http_stream_->IsResponseBodyComplete()) { |
422 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; | 466 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; |
423 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket. | 467 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket. |
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
805 } | 849 } |
806 | 850 |
807 next_state_ = STATE_INIT_CONNECTION; | 851 next_state_ = STATE_INIT_CONNECTION; |
808 return OK; | 852 return OK; |
809 } | 853 } |
810 | 854 |
811 int HttpNetworkTransaction::DoInitConnection() { | 855 int HttpNetworkTransaction::DoInitConnection() { |
812 DCHECK(!connection_->is_initialized()); | 856 DCHECK(!connection_->is_initialized()); |
813 DCHECK(proxy_info_.proxy_server().is_valid()); | 857 DCHECK(proxy_info_.proxy_server().is_valid()); |
814 | 858 |
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 | |
825 next_state_ = STATE_INIT_CONNECTION_COMPLETE; | 859 next_state_ = STATE_INIT_CONNECTION_COMPLETE; |
826 | 860 |
827 using_ssl_ = request_->url.SchemeIs("https") || | 861 using_ssl_ = request_->url.SchemeIs("https") || |
828 (alternate_protocol_mode_ == kUsingAlternateProtocol && | 862 (alternate_protocol_mode_ == kUsingAlternateProtocol && |
829 alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1); | 863 alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1); |
830 | 864 |
831 using_spdy_ = false; | 865 using_spdy_ = false; |
832 | 866 |
833 // Build the string used to uniquely identify connections of this type. | 867 // Build the string used to uniquely identify connections of this type. |
834 // Determine the host and port to connect to. | 868 // Determine the host and port to connect to. |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
962 | 996 |
963 void HttpNetworkTransaction::ClearTunnelState() { | 997 void HttpNetworkTransaction::ClearTunnelState() { |
964 http_stream_.reset(); | 998 http_stream_.reset(); |
965 request_headers_.clear(); | 999 request_headers_.clear(); |
966 response_ = HttpResponseInfo(); | 1000 response_ = HttpResponseInfo(); |
967 headers_valid_ = false; | 1001 headers_valid_ = false; |
968 } | 1002 } |
969 | 1003 |
970 int HttpNetworkTransaction::DoTunnelGenerateAuthToken() { | 1004 int HttpNetworkTransaction::DoTunnelGenerateAuthToken() { |
971 next_state_ = STATE_TUNNEL_GENERATE_AUTH_TOKEN_COMPLETE; | 1005 next_state_ = STATE_TUNNEL_GENERATE_AUTH_TOKEN_COMPLETE; |
972 return auth_controllers_[HttpAuth::AUTH_PROXY]->MaybeGenerateAuthToken( | 1006 return MaybeGenerateAuthToken(HttpAuth::AUTH_PROXY); |
973 request_, &io_callback_); | |
974 } | 1007 } |
975 | 1008 |
976 int HttpNetworkTransaction::DoTunnelGenerateAuthTokenComplete(int rv) { | 1009 int HttpNetworkTransaction::DoTunnelGenerateAuthTokenComplete(int rv) { |
977 DCHECK_NE(ERR_IO_PENDING, rv); | 1010 DCHECK_NE(ERR_IO_PENDING, rv); |
978 if (rv == OK) | 1011 if (rv == OK) |
979 next_state_ = STATE_TUNNEL_SEND_REQUEST; | 1012 next_state_ = STATE_TUNNEL_SEND_REQUEST; |
980 return rv; | 1013 return rv; |
981 } | 1014 } |
982 | 1015 |
983 int HttpNetworkTransaction::DoTunnelSendRequest() { | 1016 int HttpNetworkTransaction::DoTunnelSendRequest() { |
984 next_state_ = STATE_TUNNEL_SEND_REQUEST_COMPLETE; | 1017 next_state_ = STATE_TUNNEL_SEND_REQUEST_COMPLETE; |
985 | 1018 |
986 // This is constructed lazily (instead of within our Start method), so that | 1019 // This is constructed lazily (instead of within our Start method), so that |
987 // we have proxy info available. | 1020 // we have proxy info available. |
988 if (request_headers_.empty()) { | 1021 if (request_headers_.empty()) { |
989 HttpRequestHeaders authorization_headers; | 1022 HttpRequestHeaders authorization_headers; |
990 if (HaveAuth(HttpAuth::AUTH_PROXY)) | 1023 if (HaveAuth(HttpAuth::AUTH_PROXY)) |
991 auth_controllers_[HttpAuth::AUTH_PROXY]->AddAuthorizationHeader( | 1024 AddAuthorizationHeader(HttpAuth::AUTH_PROXY, &authorization_headers); |
992 &authorization_headers); | |
993 std::string request_line; | 1025 std::string request_line; |
994 HttpRequestHeaders request_headers; | 1026 HttpRequestHeaders request_headers; |
995 BuildTunnelRequest(request_, authorization_headers, endpoint_, | 1027 BuildTunnelRequest(request_, authorization_headers, endpoint_, |
996 &request_line, &request_headers); | 1028 &request_line, &request_headers); |
997 if (net_log_.HasListener()) { | 1029 if (net_log_.HasListener()) { |
998 net_log_.AddEvent( | 1030 net_log_.AddEvent( |
999 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | 1031 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, |
1000 new NetLogHttpRequestParameter( | 1032 new NetLogHttpRequestParameter( |
1001 request_line, request_headers)); | 1033 request_line, request_headers)); |
1002 } | 1034 } |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1174 } else { | 1206 } else { |
1175 result = HandleSSLHandshakeError(result); | 1207 result = HandleSSLHandshakeError(result); |
1176 } | 1208 } |
1177 return result; | 1209 return result; |
1178 } | 1210 } |
1179 | 1211 |
1180 int HttpNetworkTransaction::DoGenerateProxyAuthToken() { | 1212 int HttpNetworkTransaction::DoGenerateProxyAuthToken() { |
1181 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE; | 1213 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE; |
1182 if (!ShouldApplyProxyAuth()) | 1214 if (!ShouldApplyProxyAuth()) |
1183 return OK; | 1215 return OK; |
1184 return auth_controllers_[HttpAuth::AUTH_PROXY]->MaybeGenerateAuthToken( | 1216 return MaybeGenerateAuthToken(HttpAuth::AUTH_PROXY); |
1185 request_, &io_callback_); | |
1186 } | 1217 } |
1187 | 1218 |
1188 int HttpNetworkTransaction::DoGenerateProxyAuthTokenComplete(int rv) { | 1219 int HttpNetworkTransaction::DoGenerateProxyAuthTokenComplete(int rv) { |
1189 DCHECK_NE(ERR_IO_PENDING, rv); | 1220 DCHECK_NE(ERR_IO_PENDING, rv); |
1190 if (rv == OK) | 1221 if (rv == OK) |
1191 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN; | 1222 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN; |
1192 return rv; | 1223 return rv; |
1193 } | 1224 } |
1194 | 1225 |
1195 int HttpNetworkTransaction::DoGenerateServerAuthToken() { | 1226 int HttpNetworkTransaction::DoGenerateServerAuthToken() { |
1196 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE; | 1227 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE; |
1197 if (!ShouldApplyServerAuth()) | 1228 if (!ShouldApplyServerAuth()) |
1198 return OK; | 1229 return OK; |
1199 return auth_controllers_[HttpAuth::AUTH_SERVER]->MaybeGenerateAuthToken( | 1230 return MaybeGenerateAuthToken(HttpAuth::AUTH_SERVER); |
1200 request_, &io_callback_); | |
1201 } | 1231 } |
1202 | 1232 |
1203 int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) { | 1233 int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) { |
1204 DCHECK_NE(ERR_IO_PENDING, rv); | 1234 DCHECK_NE(ERR_IO_PENDING, rv); |
1205 if (rv == OK) | 1235 if (rv == OK) |
1206 next_state_ = STATE_SEND_REQUEST; | 1236 next_state_ = STATE_SEND_REQUEST; |
1207 return rv; | 1237 return rv; |
1208 } | 1238 } |
1209 | 1239 |
1210 int HttpNetworkTransaction::DoSendRequest() { | 1240 int HttpNetworkTransaction::DoSendRequest() { |
(...skipping 11 matching lines...) Expand all Loading... |
1222 // we have proxy info available. | 1252 // we have proxy info available. |
1223 if (request_headers_.empty()) { | 1253 if (request_headers_.empty()) { |
1224 // Figure out if we can/should add Proxy-Authentication & Authentication | 1254 // Figure out if we can/should add Proxy-Authentication & Authentication |
1225 // headers. | 1255 // headers. |
1226 HttpRequestHeaders authorization_headers; | 1256 HttpRequestHeaders authorization_headers; |
1227 bool have_proxy_auth = (ShouldApplyProxyAuth() && | 1257 bool have_proxy_auth = (ShouldApplyProxyAuth() && |
1228 HaveAuth(HttpAuth::AUTH_PROXY)); | 1258 HaveAuth(HttpAuth::AUTH_PROXY)); |
1229 bool have_server_auth = (ShouldApplyServerAuth() && | 1259 bool have_server_auth = (ShouldApplyServerAuth() && |
1230 HaveAuth(HttpAuth::AUTH_SERVER)); | 1260 HaveAuth(HttpAuth::AUTH_SERVER)); |
1231 if (have_proxy_auth) | 1261 if (have_proxy_auth) |
1232 auth_controllers_[HttpAuth::AUTH_PROXY]->AddAuthorizationHeader( | 1262 AddAuthorizationHeader(HttpAuth::AUTH_PROXY, &authorization_headers); |
1233 &authorization_headers); | |
1234 if (have_server_auth) | 1263 if (have_server_auth) |
1235 auth_controllers_[HttpAuth::AUTH_SERVER]->AddAuthorizationHeader( | 1264 AddAuthorizationHeader(HttpAuth::AUTH_SERVER, &authorization_headers); |
1236 &authorization_headers); | |
1237 std::string request_line; | 1265 std::string request_line; |
1238 HttpRequestHeaders request_headers; | 1266 HttpRequestHeaders request_headers; |
1239 BuildRequestHeaders(request_, authorization_headers, request_body, | 1267 BuildRequestHeaders(request_, authorization_headers, request_body, |
1240 !using_ssl_ && proxy_info_.is_http(), &request_line, | 1268 !using_ssl_ && proxy_info_.is_http(), &request_line, |
1241 &request_headers); | 1269 &request_headers); |
1242 | 1270 |
1243 if (session_->network_delegate()) | 1271 if (session_->network_delegate()) |
1244 session_->network_delegate()->OnSendHttpRequest(&request_headers); | 1272 session_->network_delegate()->OnSendHttpRequest(&request_headers); |
1245 | 1273 |
1246 if (net_log_.HasListener()) { | 1274 if (net_log_.HasListener()) { |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1374 SSLClientSocket* ssl_socket = | 1402 SSLClientSocket* ssl_socket = |
1375 reinterpret_cast<SSLClientSocket*>(connection_->socket()); | 1403 reinterpret_cast<SSLClientSocket*>(connection_->socket()); |
1376 ssl_socket->GetSSLInfo(&response_.ssl_info); | 1404 ssl_socket->GetSSLInfo(&response_.ssl_info); |
1377 } | 1405 } |
1378 | 1406 |
1379 headers_valid_ = true; | 1407 headers_valid_ = true; |
1380 return OK; | 1408 return OK; |
1381 } | 1409 } |
1382 | 1410 |
1383 int HttpNetworkTransaction::DoResolveCanonicalName() { | 1411 int HttpNetworkTransaction::DoResolveCanonicalName() { |
1384 DCHECK(auth_controllers_[pending_auth_target_].get()); | 1412 DCHECK(auth_handler_[pending_auth_target_].get()); |
1385 next_state_ = STATE_RESOLVE_CANONICAL_NAME_COMPLETE; | 1413 next_state_ = STATE_RESOLVE_CANONICAL_NAME_COMPLETE; |
1386 return auth_controllers_[pending_auth_target_]->ResolveCanonicalName( | 1414 return auth_handler_[pending_auth_target_]-> |
1387 &io_callback_); | 1415 ResolveCanonicalName(session_->host_resolver(), &io_callback_); |
1388 } | 1416 } |
1389 | 1417 |
1390 int HttpNetworkTransaction::DoResolveCanonicalNameComplete(int result) { | 1418 int HttpNetworkTransaction::DoResolveCanonicalNameComplete(int result) { |
1391 // The STATE_RESOLVE_CANONICAL_NAME state ends the Start sequence when the | 1419 // The STATE_RESOLVE_CANONICAL_NAME state ends the Start sequence when the |
1392 // canonical name of the server needs to be determined. Normally | 1420 // canonical name of the server needs to be determined. Normally |
1393 // DoReadHeadersComplete completes the sequence. The next state is | 1421 // DoReadHeadersComplete completes the sequence. The next state is |
1394 // intentionally not set as it should be STATE_NONE; | 1422 // intentionally not set as it should be STATE_NONE; |
1395 DCHECK_EQ(STATE_NONE, next_state_); | 1423 DCHECK_EQ(STATE_NONE, next_state_); |
1396 return result; | 1424 return result; |
1397 } | 1425 } |
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1936 } | 1964 } |
1937 | 1965 |
1938 bool HttpNetworkTransaction::ShouldApplyProxyAuth() const { | 1966 bool HttpNetworkTransaction::ShouldApplyProxyAuth() const { |
1939 return !using_ssl_ && proxy_info_.is_http(); | 1967 return !using_ssl_ && proxy_info_.is_http(); |
1940 } | 1968 } |
1941 | 1969 |
1942 bool HttpNetworkTransaction::ShouldApplyServerAuth() const { | 1970 bool HttpNetworkTransaction::ShouldApplyServerAuth() const { |
1943 return !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA); | 1971 return !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA); |
1944 } | 1972 } |
1945 | 1973 |
| 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 |
1946 int HttpNetworkTransaction::HandleAuthChallenge(bool establishing_tunnel) { | 2171 int HttpNetworkTransaction::HandleAuthChallenge(bool establishing_tunnel) { |
1947 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders(); | 2172 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders(); |
1948 DCHECK(headers); | 2173 DCHECK(headers); |
1949 | 2174 |
1950 int status = headers->response_code(); | 2175 int status = headers->response_code(); |
1951 if (status != 401 && status != 407) | 2176 if (status != 401 && status != 407) |
1952 return OK; | 2177 return OK; |
1953 HttpAuth::Target target = status == 407 ? | 2178 HttpAuth::Target target = status == 407 ? |
1954 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER; | 2179 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 |
1955 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) | 2186 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) |
1956 return ERR_UNEXPECTED_PROXY_AUTH; | 2187 return ERR_UNEXPECTED_PROXY_AUTH; |
| 2188 DCHECK(auth_origin.is_valid()); |
1957 | 2189 |
1958 int rv = auth_controllers_[target]->HandleAuthChallenge(headers, | 2190 // The auth we tried just failed, hence it can't be valid. Remove it from |
1959 request_->load_flags, | 2191 // the cache so it won't be used again. |
1960 establishing_tunnel); | 2192 // TODO(wtc): IsFinalRound is not the right condition. In a multi-round |
1961 if (auth_controllers_[target]->HaveAuthHandler()) | 2193 // auth sequence, the server may fail the auth in round 1 if our first |
1962 pending_auth_target_ = target; | 2194 // authorization header is broken. We should inspect response_.headers to |
1963 | 2195 // determine if the server already failed the auth or wants us to continue. |
1964 scoped_refptr<AuthChallengeInfo> auth_info = | 2196 // See http://crbug.com/21015. |
1965 auth_controllers_[target]->auth_info(); | 2197 if (HaveAuth(target) && auth_handler_[target]->IsFinalRound()) { |
1966 if (auth_info.get()) | 2198 InvalidateRejectedAuthFromCache(target, auth_origin); |
1967 response_.auth_challenge = auth_info; | 2199 auth_handler_[target].reset(); |
1968 | 2200 auth_identity_[target] = HttpAuth::Identity(); |
1969 if (rv == ERR_AUTH_NEEDS_CANONICAL_NAME) { | |
1970 next_state_ = STATE_RESOLVE_CANONICAL_NAME; | |
1971 rv = OK; | |
1972 } | 2201 } |
1973 | 2202 |
1974 return rv; | 2203 auth_identity_[target].invalid = true; |
| 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; |
1975 } | 2259 } |
1976 | 2260 |
1977 GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const { | 2261 void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target, |
1978 switch (target) { | 2262 const GURL& auth_origin) { |
1979 case HttpAuth::AUTH_PROXY: | 2263 // Populates response_.auth_challenge with the authentication challenge info. |
1980 if (!proxy_info_.proxy_server().is_valid() || | 2264 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo(). |
1981 proxy_info_.proxy_server().is_direct()) { | 2265 |
1982 return GURL(); // There is no proxy server. | 2266 AuthChallengeInfo* auth_info = new AuthChallengeInfo; |
1983 } | 2267 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY; |
1984 return GURL("http://" + proxy_info_.proxy_server().host_and_port()); | 2268 auth_info->host_and_port = ASCIIToWide(GetHostAndPort(auth_origin)); |
1985 case HttpAuth::AUTH_SERVER: | 2269 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme()); |
1986 return request_->url; | 2270 // TODO(eroman): decode realm according to RFC 2047. |
1987 default: | 2271 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm()); |
1988 return GURL(); | 2272 response_.auth_challenge = auth_info; |
1989 } | |
1990 } | 2273 } |
1991 | 2274 |
1992 void HttpNetworkTransaction::MarkBrokenAlternateProtocolAndFallback() { | 2275 void HttpNetworkTransaction::MarkBrokenAlternateProtocolAndFallback() { |
1993 // We have to: | 2276 // We have to: |
1994 // * Reset the endpoint to be the unmodified URL specified destination. | 2277 // * Reset the endpoint to be the unmodified URL specified destination. |
1995 // * Mark the endpoint as broken so we don't try again. | 2278 // * Mark the endpoint as broken so we don't try again. |
1996 // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we | 2279 // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we |
1997 // ignore future Alternate-Protocol headers from the HostPortPair. | 2280 // ignore future Alternate-Protocol headers from the HostPortPair. |
1998 // * Reset the connection and go back to STATE_INIT_CONNECTION. | 2281 // * Reset the connection and go back to STATE_INIT_CONNECTION. |
1999 | 2282 |
2000 endpoint_ = HostPortPair(request_->url.HostNoBrackets(), | 2283 endpoint_ = HostPortPair(request_->url.HostNoBrackets(), |
2001 request_->url.EffectiveIntPort()); | 2284 request_->url.EffectiveIntPort()); |
2002 | 2285 |
2003 session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor( | 2286 session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor( |
2004 endpoint_); | 2287 endpoint_); |
2005 | 2288 |
2006 alternate_protocol_mode_ = kDoNotUseAlternateProtocol; | 2289 alternate_protocol_mode_ = kDoNotUseAlternateProtocol; |
2007 if (connection_->socket()) | 2290 if (connection_->socket()) |
2008 connection_->socket()->Disconnect(); | 2291 connection_->socket()->Disconnect(); |
2009 connection_->Reset(); | 2292 connection_->Reset(); |
2010 next_state_ = STATE_INIT_CONNECTION; | 2293 next_state_ = STATE_INIT_CONNECTION; |
2011 } | 2294 } |
2012 | 2295 |
2013 } // namespace net | 2296 } // namespace net |
OLD | NEW |