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

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

Issue 242135: Merge r25564 and r26588 from the trunk.... (Closed) Base URL: svn://chrome-svn/chrome/branches/195/src/
Patch Set: Undo an extraneous comment change Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/http/http_network_transaction.h ('k') | net/http/http_network_transaction_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/string_util.h" 10 #include "base/string_util.h"
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 session_(session), 137 session_(session),
138 request_(NULL), 138 request_(NULL),
139 pac_request_(NULL), 139 pac_request_(NULL),
140 socket_factory_(csf), 140 socket_factory_(csf),
141 connection_(session->connection_pool()), 141 connection_(session->connection_pool()),
142 reused_socket_(false), 142 reused_socket_(false),
143 using_ssl_(false), 143 using_ssl_(false),
144 proxy_mode_(kDirectConnection), 144 proxy_mode_(kDirectConnection),
145 establishing_tunnel_(false), 145 establishing_tunnel_(false),
146 reading_body_from_socket_(false), 146 reading_body_from_socket_(false),
147 embedded_identity_used_(false),
147 request_headers_(new RequestHeaders()), 148 request_headers_(new RequestHeaders()),
148 request_headers_bytes_sent_(0), 149 request_headers_bytes_sent_(0),
149 header_buf_(new ResponseHeaders()), 150 header_buf_(new ResponseHeaders()),
150 header_buf_capacity_(0), 151 header_buf_capacity_(0),
151 header_buf_len_(0), 152 header_buf_len_(0),
152 header_buf_body_offset_(-1), 153 header_buf_body_offset_(-1),
153 header_buf_http_offset_(-1), 154 header_buf_http_offset_(-1),
154 response_body_length_(-1), // -1 means unspecified. 155 response_body_length_(-1), // -1 means unspecified.
155 response_body_read_(0), 156 response_body_read_(0),
156 read_buf_len_(0), 157 read_buf_len_(0),
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP); 248 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
248 249
249 // Add the auth entry to the cache before restarting. We don't know whether 250 // Add the auth entry to the cache before restarting. We don't know whether
250 // the identity is valid yet, but if it is valid we want other transactions 251 // the identity is valid yet, but if it is valid we want other transactions
251 // to know about it. If an entry for (origin, handler->realm()) already 252 // to know about it. If an entry for (origin, handler->realm()) already
252 // exists, we update it. 253 // exists, we update it.
253 // 254 //
254 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE, 255 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE,
255 // auth_identity_[target] contains no identity because identity is not 256 // auth_identity_[target] contains no identity because identity is not
256 // required yet. 257 // required yet.
258 //
259 // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in
260 // round 1 and round 2, which is redundant but correct. It would be nice
261 // to add an auth entry to the cache only once, preferrably in round 1.
262 // See http://crbug.com/21015.
257 bool has_auth_identity = 263 bool has_auth_identity =
258 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE; 264 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE;
259 if (has_auth_identity) { 265 if (has_auth_identity) {
260 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target], 266 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target],
261 auth_identity_[target].username, auth_identity_[target].password, 267 auth_identity_[target].username, auth_identity_[target].password,
262 AuthPath(target)); 268 AuthPath(target));
263 } 269 }
264 270
265 bool keep_alive = false; 271 bool keep_alive = false;
266 if (response_.headers->IsKeepAlive()) { 272 if (response_.headers->IsKeepAlive()) {
267 // If there is a response body of known length, we need to drain it first. 273 // If there is a response body of known length, we need to drain it first.
268 if (response_body_length_ > 0 || chunked_decoder_.get()) { 274 if (response_body_length_ > 0 || chunked_decoder_.get()) {
269 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; 275 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
270 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket 276 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket
271 read_buf_len_ = kDrainBodyBufferSize; 277 read_buf_len_ = kDrainBodyBufferSize;
272 return; 278 return;
273 } 279 }
274 if (response_body_length_ == 0) // No response body to drain. 280 if (response_body_length_ == 0) // No response body to drain.
275 keep_alive = true; 281 keep_alive = true;
276 // response_body_length_ is -1 and we're not using chunked encoding. We 282 // response_body_length_ is -1 and we're not using chunked encoding. We
277 // don't know the length of the response body, so we can't reuse this 283 // don't know the length of the response body, so we can't reuse this
278 // connection even though the server says it's keep-alive. 284 // connection even though the server says it's keep-alive.
279 } 285 }
280 286
281 // If the auth scheme is connection-based but the proxy/server mistakenly
282 // marks the connection as non-keep-alive, the auth is going to fail, so log
283 // an error message.
284 if (!keep_alive && auth_handler_[target]->is_connection_based() &&
285 has_auth_identity) {
286 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme()
287 << " auth to the " << AuthTargetString(target) << " "
288 << AuthOrigin(target) << " over a non-keep-alive connection";
289
290 HttpVersion http_version = response_.headers->GetHttpVersion();
291 LOG(ERROR) << " HTTP version is " << http_version.major_value() << "."
292 << http_version.minor_value();
293
294 std::string header_val;
295 void* iter = NULL;
296 while (response_.headers->EnumerateHeader(&iter, "connection",
297 &header_val)) {
298 LOG(ERROR) << " Has header Connection: " << header_val;
299 }
300
301 iter = NULL;
302 while (response_.headers->EnumerateHeader(&iter, "proxy-connection",
303 &header_val)) {
304 LOG(ERROR) << " Has header Proxy-Connection: " << header_val;
305 }
306
307 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
308 // authentication with a "Proxy-Support: Session-Based-Authentication"
309 // response header.
310 iter = NULL;
311 while (response_.headers->EnumerateHeader(&iter, "proxy-support",
312 &header_val)) {
313 LOG(ERROR) << " Has header Proxy-Support: " << header_val;
314 }
315 }
316
317 // We don't need to drain the response body, so we act as if we had drained 287 // We don't need to drain the response body, so we act as if we had drained
318 // the response body. 288 // the response body.
319 DidDrainBodyForAuthRestart(keep_alive); 289 DidDrainBodyForAuthRestart(keep_alive);
320 } 290 }
321 291
322 void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) { 292 void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
323 if (keep_alive) { 293 if (keep_alive) {
324 next_state_ = STATE_WRITE_HEADERS; 294 next_state_ = STATE_WRITE_HEADERS;
325 reused_socket_ = true; 295 reused_socket_ = true;
326 } else { 296 } else {
(...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after
726 ShouldApplyProxyAuth() && 696 ShouldApplyProxyAuth() &&
727 (HaveAuth(HttpAuth::AUTH_PROXY) || 697 (HaveAuth(HttpAuth::AUTH_PROXY) ||
728 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY)); 698 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY));
729 bool have_server_auth = 699 bool have_server_auth =
730 ShouldApplyServerAuth() && 700 ShouldApplyServerAuth() &&
731 (HaveAuth(HttpAuth::AUTH_SERVER) || 701 (HaveAuth(HttpAuth::AUTH_SERVER) ||
732 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER)); 702 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
733 703
734 std::string authorization_headers; 704 std::string authorization_headers;
735 705
706 // TODO(wtc): If BuildAuthorizationHeader fails (returns an authorization
707 // header with no credentials), we should return an error to prevent
708 // entering an infinite auth restart loop. See http://crbug.com/21050.
736 if (have_proxy_auth) 709 if (have_proxy_auth)
737 authorization_headers.append( 710 authorization_headers.append(
738 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY)); 711 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY));
739 if (have_server_auth) 712 if (have_server_auth)
740 authorization_headers.append( 713 authorization_headers.append(
741 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER)); 714 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER));
742 715
743 if (establishing_tunnel_) { 716 if (establishing_tunnel_) {
744 BuildTunnelRequest(request_, authorization_headers, 717 BuildTunnelRequest(request_, authorization_headers,
745 &request_headers_->headers_); 718 &request_headers_->headers_);
(...skipping 864 matching lines...) Expand 10 before | Expand all | Expand 10 after
1610 } 1583 }
1611 return false; 1584 return false;
1612 } 1585 }
1613 1586
1614 bool HttpNetworkTransaction::SelectNextAuthIdentityToTry( 1587 bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
1615 HttpAuth::Target target) { 1588 HttpAuth::Target target) {
1616 DCHECK(auth_handler_[target]); 1589 DCHECK(auth_handler_[target]);
1617 DCHECK(auth_identity_[target].invalid); 1590 DCHECK(auth_identity_[target].invalid);
1618 1591
1619 // Try to use the username/password encoded into the URL first. 1592 // Try to use the username/password encoded into the URL first.
1620 // (By checking source == IDENT_SRC_NONE, we make sure that this
1621 // is only done once for the transaction.)
1622 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() && 1593 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
1623 auth_identity_[target].source == HttpAuth::IDENT_SRC_NONE) { 1594 !embedded_identity_used_) {
1624 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL; 1595 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1625 auth_identity_[target].invalid = false; 1596 auth_identity_[target].invalid = false;
1626 // TODO(wtc) It may be necessary to unescape the username and password 1597 // TODO(wtc) It may be necessary to unescape the username and password
1627 // after extracting them from the URL. We should be careful about 1598 // after extracting them from the URL. We should be careful about
1628 // embedded nulls in that case. 1599 // embedded nulls in that case.
1629 auth_identity_[target].username = ASCIIToWide(request_->url.username()); 1600 auth_identity_[target].username = ASCIIToWide(request_->url.username());
1630 auth_identity_[target].password = ASCIIToWide(request_->url.password()); 1601 auth_identity_[target].password = ASCIIToWide(request_->url.password());
1602 embedded_identity_used_ = true;
1631 // TODO(eroman): If the password is blank, should we also try combining 1603 // TODO(eroman): If the password is blank, should we also try combining
1632 // with a password from the cache? 1604 // with a password from the cache?
1633 return true; 1605 return true;
1634 } 1606 }
1635 1607
1636 // Check the auth cache for a realm entry. 1608 // Check the auth cache for a realm entry.
1637 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm( 1609 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm(
1638 AuthOrigin(target), auth_handler_[target]->realm()); 1610 AuthOrigin(target), auth_handler_[target]->realm());
1639 1611
1640 if (entry) { 1612 if (entry) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1704 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER; 1676 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
1705 1677
1706 LOG(INFO) << "The " << AuthTargetString(target) << " " 1678 LOG(INFO) << "The " << AuthTargetString(target) << " "
1707 << AuthOrigin(target) << " requested auth" 1679 << AuthOrigin(target) << " requested auth"
1708 << AuthChallengeLogMessage(); 1680 << AuthChallengeLogMessage();
1709 1681
1710 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) 1682 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1711 return ERR_UNEXPECTED_PROXY_AUTH; 1683 return ERR_UNEXPECTED_PROXY_AUTH;
1712 1684
1713 // The auth we tried just failed, hence it can't be valid. Remove it from 1685 // The auth we tried just failed, hence it can't be valid. Remove it from
1714 // the cache so it won't be used again, unless it's a null identity. 1686 // the cache so it won't be used again.
1715 if (HaveAuth(target) && 1687 // TODO(wtc): IsFinalRound is not the right condition. In a multi-round
1716 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) 1688 // auth sequence, the server may fail the auth in round 1 if our first
1689 // authorization header is broken. We should inspect response_.headers to
1690 // determine if the server already failed the auth or wants us to continue.
1691 // See http://crbug.com/21015.
1692 if (HaveAuth(target) && auth_handler_[target]->IsFinalRound()) {
1717 InvalidateRejectedAuthFromCache(target); 1693 InvalidateRejectedAuthFromCache(target);
1694 auth_handler_[target] = NULL;
1695 auth_identity_[target] = HttpAuth::Identity();
1696 }
1718 1697
1719 auth_identity_[target].invalid = true; 1698 auth_identity_[target].invalid = true;
1720 1699
1721 if (target != HttpAuth::AUTH_SERVER || 1700 if (target != HttpAuth::AUTH_SERVER ||
1722 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) { 1701 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) {
1723 // Find the best authentication challenge that we support. 1702 // Find the best authentication challenge that we support.
1724 HttpAuth::ChooseBestChallenge(response_.headers.get(), 1703 HttpAuth::ChooseBestChallenge(response_.headers.get(),
1725 target, 1704 target,
1705 AuthOrigin(target),
1726 &auth_handler_[target]); 1706 &auth_handler_[target]);
1727 } 1707 }
1728 1708
1729 if (!auth_handler_[target]) { 1709 if (!auth_handler_[target]) {
1730 if (establishing_tunnel_) { 1710 if (establishing_tunnel_) {
1731 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target) 1711 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target)
1732 << " " << AuthOrigin(target) 1712 << " " << AuthOrigin(target)
1733 << " when establishing a tunnel" 1713 << " when establishing a tunnel"
1734 << AuthChallengeLogMessage(); 1714 << AuthChallengeLogMessage();
1735 1715
1736 // We are establishing a tunnel, we can't show the error page because an 1716 // We are establishing a tunnel, we can't show the error page because an
1737 // active network attacker could control its contents. Instead, we just 1717 // active network attacker could control its contents. Instead, we just
1738 // fail to establish the tunnel. 1718 // fail to establish the tunnel.
1739 DCHECK(target == HttpAuth::AUTH_PROXY); 1719 DCHECK(target == HttpAuth::AUTH_PROXY);
1740 return ERR_PROXY_AUTH_REQUESTED; 1720 return ERR_PROXY_AUTH_REQUESTED;
1741 } 1721 }
1742 // We found no supported challenge -- let the transaction continue 1722 // We found no supported challenge -- let the transaction continue
1743 // so we end up displaying the error page. 1723 // so we end up displaying the error page.
1744 return OK; 1724 return OK;
1745 } 1725 }
1746 1726
1747 if (auth_handler_[target]->NeedsIdentity()) { 1727 if (auth_handler_[target]->NeedsIdentity()) {
1748 // Pick a new auth identity to try, by looking to the URL and auth cache. 1728 // Pick a new auth identity to try, by looking to the URL and auth cache.
1749 // If an identity to try is found, it is saved to auth_identity_[target]. 1729 // If an identity to try is found, it is saved to auth_identity_[target].
1750 SelectNextAuthIdentityToTry(target); 1730 SelectNextAuthIdentityToTry(target);
1751 } else { 1731 } else {
1752 // Proceed with a null identity. 1732 // Proceed with the existing identity or a null identity.
1753 // 1733 //
1754 // TODO(wtc): Add a safeguard against infinite transaction restarts, if 1734 // TODO(wtc): Add a safeguard against infinite transaction restarts, if
1755 // the server keeps returning "NTLM". 1735 // the server keeps returning "NTLM".
1756 auth_identity_[target].source = HttpAuth::IDENT_SRC_NONE;
1757 auth_identity_[target].invalid = false; 1736 auth_identity_[target].invalid = false;
1758 auth_identity_[target].username.clear();
1759 auth_identity_[target].password.clear();
1760 } 1737 }
1761 1738
1762 // Make a note that we are waiting for auth. This variable is inspected 1739 // Make a note that we are waiting for auth. This variable is inspected
1763 // when the client calls RestartWithAuth() to pick up where we left off. 1740 // when the client calls RestartWithAuth() to pick up where we left off.
1764 pending_auth_target_ = target; 1741 pending_auth_target_ = target;
1765 1742
1766 if (auth_identity_[target].invalid) { 1743 if (auth_identity_[target].invalid) {
1767 // We have exhausted all identity possibilities, all we can do now is 1744 // We have exhausted all identity possibilities, all we can do now is
1768 // pass the challenge information back to the client. 1745 // pass the challenge information back to the client.
1769 PopulateAuthChallenge(target); 1746 PopulateAuthChallenge(target);
1770 } 1747 }
1771 return OK; 1748 return OK;
1772 } 1749 }
1773 1750
1774 void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target) { 1751 void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target) {
1775 // Populates response_.auth_challenge with the authentication challenge info. 1752 // Populates response_.auth_challenge with the authentication challenge info.
1776 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo(). 1753 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
1777 1754
1778 AuthChallengeInfo* auth_info = new AuthChallengeInfo; 1755 AuthChallengeInfo* auth_info = new AuthChallengeInfo;
1779 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY; 1756 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
1757 auth_info->host_and_port = ASCIIToWide(GetHostAndPort(AuthOrigin(target)));
1780 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme()); 1758 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
1781 // TODO(eroman): decode realm according to RFC 2047. 1759 // TODO(eroman): decode realm according to RFC 2047.
1782 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm()); 1760 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
1783
1784 std::string host_and_port;
1785 if (target == HttpAuth::AUTH_PROXY) {
1786 host_and_port = proxy_info_.proxy_server().host_and_port();
1787 } else {
1788 DCHECK(target == HttpAuth::AUTH_SERVER);
1789 host_and_port = GetHostAndPort(request_->url);
1790 }
1791 auth_info->host_and_port = ASCIIToWide(host_and_port);
1792 response_.auth_challenge = auth_info; 1761 response_.auth_challenge = auth_info;
1793 } 1762 }
1794 1763
1795 } // namespace net 1764 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_network_transaction.h ('k') | net/http/http_network_transaction_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698