| 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 |