| OLD | NEW |
| 1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2009 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/scoped_ptr.h" | 7 #include "base/scoped_ptr.h" |
| 8 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
| 9 #include "base/field_trial.h" | 9 #include "base/field_trial.h" |
| 10 #include "base/histogram.h" | 10 #include "base/histogram.h" |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP); | 246 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP); |
| 247 | 247 |
| 248 // Add the auth entry to the cache before restarting. We don't know whether | 248 // Add the auth entry to the cache before restarting. We don't know whether |
| 249 // the identity is valid yet, but if it is valid we want other transactions | 249 // the identity is valid yet, but if it is valid we want other transactions |
| 250 // to know about it. If an entry for (origin, handler->realm()) already | 250 // to know about it. If an entry for (origin, handler->realm()) already |
| 251 // exists, we update it. | 251 // exists, we update it. |
| 252 // | 252 // |
| 253 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE, | 253 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE, |
| 254 // auth_identity_[target] contains no identity because identity is not | 254 // auth_identity_[target] contains no identity because identity is not |
| 255 // required yet. | 255 // required yet. |
| 256 // |
| 257 // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in |
| 258 // round 1 and round 2, which is redundant but correct. It would be nice |
| 259 // to add an auth entry to the cache only once, preferrably in round 1. |
| 260 // See http://crbug.com/21015. |
| 256 bool has_auth_identity = | 261 bool has_auth_identity = |
| 257 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE; | 262 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE; |
| 258 if (has_auth_identity) { | 263 if (has_auth_identity) { |
| 259 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target], | 264 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target], |
| 260 auth_identity_[target].username, auth_identity_[target].password, | 265 auth_identity_[target].username, auth_identity_[target].password, |
| 261 AuthPath(target)); | 266 AuthPath(target)); |
| 262 } | 267 } |
| 263 | 268 |
| 264 bool keep_alive = false; | 269 bool keep_alive = false; |
| 265 if (response_.headers->IsKeepAlive()) { | 270 if (response_.headers->IsKeepAlive()) { |
| 266 // If there is a response body of known length, we need to drain it first. | 271 // If there is a response body of known length, we need to drain it first. |
| 267 if (response_body_length_ > 0 || chunked_decoder_.get()) { | 272 if (response_body_length_ > 0 || chunked_decoder_.get()) { |
| 268 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; | 273 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; |
| 269 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket | 274 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket |
| 270 read_buf_len_ = kDrainBodyBufferSize; | 275 read_buf_len_ = kDrainBodyBufferSize; |
| 271 return; | 276 return; |
| 272 } | 277 } |
| 273 if (response_body_length_ == 0) // No response body to drain. | 278 if (response_body_length_ == 0) // No response body to drain. |
| 274 keep_alive = true; | 279 keep_alive = true; |
| 275 // response_body_length_ is -1 and we're not using chunked encoding. We | 280 // response_body_length_ is -1 and we're not using chunked encoding. We |
| 276 // don't know the length of the response body, so we can't reuse this | 281 // don't know the length of the response body, so we can't reuse this |
| 277 // connection even though the server says it's keep-alive. | 282 // connection even though the server says it's keep-alive. |
| 278 } | 283 } |
| 279 | 284 |
| 280 // If the auth scheme is connection-based but the proxy/server mistakenly | 285 // If the auth scheme is connection-based but the proxy/server mistakenly |
| 281 // marks the connection as non-keep-alive, the auth is going to fail, so log | 286 // marks the connection as non-keep-alive, the auth is going to fail, so log |
| 282 // an error message. | 287 // an error message. |
| 288 // |
| 289 // TODO(wtc): has_auth_identity is not the right condition. We should |
| 290 // be testing for "not round 1" here. See http://crbug.com/21015. |
| 283 if (!keep_alive && auth_handler_[target]->is_connection_based() && | 291 if (!keep_alive && auth_handler_[target]->is_connection_based() && |
| 284 has_auth_identity) { | 292 has_auth_identity) { |
| 285 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme() | 293 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme() |
| 286 << " auth to the " << AuthTargetString(target) << " " | 294 << " auth to the " << AuthTargetString(target) << " " |
| 287 << AuthOrigin(target) << " over a non-keep-alive connection"; | 295 << AuthOrigin(target) << " over a non-keep-alive connection"; |
| 288 | 296 |
| 289 HttpVersion http_version = response_.headers->GetHttpVersion(); | 297 HttpVersion http_version = response_.headers->GetHttpVersion(); |
| 290 LOG(ERROR) << " HTTP version is " << http_version.major_value() << "." | 298 LOG(ERROR) << " HTTP version is " << http_version.major_value() << "." |
| 291 << http_version.minor_value(); | 299 << http_version.minor_value(); |
| 292 | 300 |
| (...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 ShouldApplyProxyAuth() && | 743 ShouldApplyProxyAuth() && |
| 736 (HaveAuth(HttpAuth::AUTH_PROXY) || | 744 (HaveAuth(HttpAuth::AUTH_PROXY) || |
| 737 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY)); | 745 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY)); |
| 738 bool have_server_auth = | 746 bool have_server_auth = |
| 739 ShouldApplyServerAuth() && | 747 ShouldApplyServerAuth() && |
| 740 (HaveAuth(HttpAuth::AUTH_SERVER) || | 748 (HaveAuth(HttpAuth::AUTH_SERVER) || |
| 741 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER)); | 749 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER)); |
| 742 | 750 |
| 743 std::string authorization_headers; | 751 std::string authorization_headers; |
| 744 | 752 |
| 753 // TODO(wtc): If BuildAuthorizationHeader fails (returns an authorization |
| 754 // header with no credentials), we should return an error to prevent |
| 755 // entering an infinite auth restart loop. See http://crbug.com/21050. |
| 745 if (have_proxy_auth) | 756 if (have_proxy_auth) |
| 746 authorization_headers.append( | 757 authorization_headers.append( |
| 747 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY)); | 758 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY)); |
| 748 if (have_server_auth) | 759 if (have_server_auth) |
| 749 authorization_headers.append( | 760 authorization_headers.append( |
| 750 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER)); | 761 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER)); |
| 751 | 762 |
| 752 if (establishing_tunnel_) { | 763 if (establishing_tunnel_) { |
| 753 BuildTunnelRequest(request_, authorization_headers, | 764 BuildTunnelRequest(request_, authorization_headers, |
| 754 &request_headers_->headers_); | 765 &request_headers_->headers_); |
| (...skipping 1119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1874 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER; | 1885 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER; |
| 1875 | 1886 |
| 1876 LOG(INFO) << "The " << AuthTargetString(target) << " " | 1887 LOG(INFO) << "The " << AuthTargetString(target) << " " |
| 1877 << AuthOrigin(target) << " requested auth" | 1888 << AuthOrigin(target) << " requested auth" |
| 1878 << AuthChallengeLogMessage(); | 1889 << AuthChallengeLogMessage(); |
| 1879 | 1890 |
| 1880 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) | 1891 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) |
| 1881 return ERR_UNEXPECTED_PROXY_AUTH; | 1892 return ERR_UNEXPECTED_PROXY_AUTH; |
| 1882 | 1893 |
| 1883 // The auth we tried just failed, hence it can't be valid. Remove it from | 1894 // The auth we tried just failed, hence it can't be valid. Remove it from |
| 1884 // the cache so it won't be used again, unless it's a null identity. | 1895 // the cache so it won't be used again. |
| 1885 if (HaveAuth(target) && | 1896 // TODO(wtc): IsFinalRound is not the right condition. In a multi-round |
| 1886 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) | 1897 // auth sequence, the server may fail the auth in round 1 if our first |
| 1898 // authorization header is broken. We should inspect response_.headers to |
| 1899 // determine if the server already failed the auth or wants us to continue. |
| 1900 // See http://crbug.com/21015. |
| 1901 if (HaveAuth(target) && auth_handler_[target]->IsFinalRound()) { |
| 1887 InvalidateRejectedAuthFromCache(target); | 1902 InvalidateRejectedAuthFromCache(target); |
| 1903 auth_handler_[target] = NULL; |
| 1904 auth_identity_[target] = HttpAuth::Identity(); |
| 1905 } |
| 1888 | 1906 |
| 1889 auth_identity_[target].invalid = true; | 1907 auth_identity_[target].invalid = true; |
| 1890 | 1908 |
| 1891 if (target != HttpAuth::AUTH_SERVER || | 1909 if (target != HttpAuth::AUTH_SERVER || |
| 1892 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) { | 1910 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) { |
| 1893 // Find the best authentication challenge that we support. | 1911 // Find the best authentication challenge that we support. |
| 1894 HttpAuth::ChooseBestChallenge(response_.headers.get(), | 1912 HttpAuth::ChooseBestChallenge(response_.headers.get(), |
| 1895 target, | 1913 target, |
| 1896 &auth_handler_[target]); | 1914 &auth_handler_[target]); |
| 1897 } | 1915 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1912 // We found no supported challenge -- let the transaction continue | 1930 // We found no supported challenge -- let the transaction continue |
| 1913 // so we end up displaying the error page. | 1931 // so we end up displaying the error page. |
| 1914 return OK; | 1932 return OK; |
| 1915 } | 1933 } |
| 1916 | 1934 |
| 1917 if (auth_handler_[target]->NeedsIdentity()) { | 1935 if (auth_handler_[target]->NeedsIdentity()) { |
| 1918 // Pick a new auth identity to try, by looking to the URL and auth cache. | 1936 // Pick a new auth identity to try, by looking to the URL and auth cache. |
| 1919 // If an identity to try is found, it is saved to auth_identity_[target]. | 1937 // If an identity to try is found, it is saved to auth_identity_[target]. |
| 1920 SelectNextAuthIdentityToTry(target); | 1938 SelectNextAuthIdentityToTry(target); |
| 1921 } else { | 1939 } else { |
| 1922 // Proceed with a null identity. | 1940 // Proceed with the existing identity or a null identity. |
| 1923 // | 1941 // |
| 1924 // TODO(wtc): Add a safeguard against infinite transaction restarts, if | 1942 // TODO(wtc): Add a safeguard against infinite transaction restarts, if |
| 1925 // the server keeps returning "NTLM". | 1943 // the server keeps returning "NTLM". |
| 1926 auth_identity_[target].source = HttpAuth::IDENT_SRC_NONE; | |
| 1927 auth_identity_[target].invalid = false; | 1944 auth_identity_[target].invalid = false; |
| 1928 auth_identity_[target].username.clear(); | |
| 1929 auth_identity_[target].password.clear(); | |
| 1930 } | 1945 } |
| 1931 | 1946 |
| 1932 // Make a note that we are waiting for auth. This variable is inspected | 1947 // Make a note that we are waiting for auth. This variable is inspected |
| 1933 // when the client calls RestartWithAuth() to pick up where we left off. | 1948 // when the client calls RestartWithAuth() to pick up where we left off. |
| 1934 pending_auth_target_ = target; | 1949 pending_auth_target_ = target; |
| 1935 | 1950 |
| 1936 if (auth_identity_[target].invalid) { | 1951 if (auth_identity_[target].invalid) { |
| 1937 // We have exhausted all identity possibilities, all we can do now is | 1952 // We have exhausted all identity possibilities, all we can do now is |
| 1938 // pass the challenge information back to the client. | 1953 // pass the challenge information back to the client. |
| 1939 PopulateAuthChallenge(target); | 1954 PopulateAuthChallenge(target); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1956 host_and_port = proxy_info_.proxy_server().host_and_port(); | 1971 host_and_port = proxy_info_.proxy_server().host_and_port(); |
| 1957 } else { | 1972 } else { |
| 1958 DCHECK(target == HttpAuth::AUTH_SERVER); | 1973 DCHECK(target == HttpAuth::AUTH_SERVER); |
| 1959 host_and_port = GetHostAndPort(request_->url); | 1974 host_and_port = GetHostAndPort(request_->url); |
| 1960 } | 1975 } |
| 1961 auth_info->host_and_port = ASCIIToWide(host_and_port); | 1976 auth_info->host_and_port = ASCIIToWide(host_and_port); |
| 1962 response_.auth_challenge = auth_info; | 1977 response_.auth_challenge = auth_info; |
| 1963 } | 1978 } |
| 1964 | 1979 |
| 1965 } // namespace net | 1980 } // namespace net |
| OLD | NEW |