| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 // response_body_length_ is -1 and we're not using chunked encoding. We | 159 // response_body_length_ is -1 and we're not using chunked encoding. We |
| 160 // don't know the length of the response body, so we can't reuse this | 160 // don't know the length of the response body, so we can't reuse this |
| 161 // connection even though the server says it's keep-alive. | 161 // connection even though the server says it's keep-alive. |
| 162 } | 162 } |
| 163 | 163 |
| 164 // If the auth scheme is connection-based but the proxy/server mistakenly | 164 // If the auth scheme is connection-based but the proxy/server mistakenly |
| 165 // marks the connection as not keep-alive, the auth is going to fail, so log | 165 // marks the connection as not keep-alive, the auth is going to fail, so log |
| 166 // an error message. | 166 // an error message. |
| 167 if (!keep_alive && auth_handler_[target]->is_connection_based() && | 167 if (!keep_alive && auth_handler_[target]->is_connection_based() && |
| 168 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) { | 168 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) { |
| 169 std::string auth_target(target == HttpAuth::AUTH_PROXY ? | |
| 170 "proxy" : "server"); | |
| 171 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme() | 169 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme() |
| 172 << " auth to the " << auth_target << " " | 170 << " auth to the " << AuthTargetString(target) << " " |
| 173 << AuthOrigin(target).spec() | 171 << AuthOrigin(target) << " over a non-keep-alive connection"; |
| 174 << " over a non-keep-alive connection"; | |
| 175 | 172 |
| 176 HttpVersion http_version = response_.headers->GetHttpVersion(); | 173 HttpVersion http_version = response_.headers->GetHttpVersion(); |
| 177 LOG(ERROR) << " HTTP version is " << http_version.major_value() << "." | 174 LOG(ERROR) << " HTTP version is " << http_version.major_value() << "." |
| 178 << http_version.minor_value(); | 175 << http_version.minor_value(); |
| 179 | 176 |
| 180 std::string connection_val; | 177 std::string header_val; |
| 181 void* iter = NULL; | 178 void* iter = NULL; |
| 182 while (response_.headers->EnumerateHeader(&iter, "connection", | 179 while (response_.headers->EnumerateHeader(&iter, "connection", |
| 183 &connection_val)) { | 180 &header_val)) { |
| 184 LOG(ERROR) << " Has header Connection: " << connection_val; | 181 LOG(ERROR) << " Has header Connection: " << header_val; |
| 185 } | 182 } |
| 186 | 183 |
| 187 iter = NULL; | 184 iter = NULL; |
| 188 while (response_.headers->EnumerateHeader(&iter, "proxy-connection", | 185 while (response_.headers->EnumerateHeader(&iter, "proxy-connection", |
| 189 &connection_val)) { | 186 &header_val)) { |
| 190 LOG(ERROR) << " Has header Proxy-Connection: " << connection_val; | 187 LOG(ERROR) << " Has header Proxy-Connection: " << header_val; |
| 188 } |
| 189 |
| 190 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate |
| 191 // authentication with a "Proxy-Support: Session-Based-Authentication" |
| 192 // response header. |
| 193 iter = NULL; |
| 194 while (response_.headers->EnumerateHeader(&iter, "proxy-support", |
| 195 &header_val)) { |
| 196 LOG(ERROR) << " Has header Proxy-Support: " << header_val; |
| 191 } | 197 } |
| 192 } | 198 } |
| 193 | 199 |
| 194 // We don't need to drain the response body, so we act as if we had drained | 200 // We don't need to drain the response body, so we act as if we had drained |
| 195 // the response body. | 201 // the response body. |
| 196 DidDrainBodyForAuthRestart(keep_alive); | 202 DidDrainBodyForAuthRestart(keep_alive); |
| 197 } | 203 } |
| 198 | 204 |
| 199 void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) { | 205 void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) { |
| 200 if (keep_alive) { | 206 if (keep_alive) { |
| (...skipping 1174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1375 } | 1381 } |
| 1376 | 1382 |
| 1377 std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target) | 1383 std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target) |
| 1378 const { | 1384 const { |
| 1379 // Proxy authentication realms apply to all paths. So we will use | 1385 // Proxy authentication realms apply to all paths. So we will use |
| 1380 // empty string in place of an absolute path. | 1386 // empty string in place of an absolute path. |
| 1381 return target == HttpAuth::AUTH_PROXY ? | 1387 return target == HttpAuth::AUTH_PROXY ? |
| 1382 std::string() : request_->url.path(); | 1388 std::string() : request_->url.path(); |
| 1383 } | 1389 } |
| 1384 | 1390 |
| 1391 // static |
| 1392 std::string HttpNetworkTransaction::AuthTargetString( |
| 1393 HttpAuth::Target target) { |
| 1394 return target == HttpAuth::AUTH_PROXY ? "proxy" : "server"; |
| 1395 } |
| 1396 |
| 1385 void HttpNetworkTransaction::InvalidateRejectedAuthFromCache( | 1397 void HttpNetworkTransaction::InvalidateRejectedAuthFromCache( |
| 1386 HttpAuth::Target target) { | 1398 HttpAuth::Target target) { |
| 1387 DCHECK(HaveAuth(target)); | 1399 DCHECK(HaveAuth(target)); |
| 1388 | 1400 |
| 1389 // TODO(eroman): this short-circuit can be relaxed. If the realm of | 1401 // TODO(eroman): this short-circuit can be relaxed. If the realm of |
| 1390 // the preemptively used auth entry matches the realm of the subsequent | 1402 // the preemptively used auth entry matches the realm of the subsequent |
| 1391 // challenge, then we can invalidate the preemptively used entry. | 1403 // challenge, then we can invalidate the preemptively used entry. |
| 1392 // Otherwise as-is we may send the failed credentials one extra time. | 1404 // Otherwise as-is we may send the failed credentials one extra time. |
| 1393 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP) | 1405 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP) |
| 1394 return; | 1406 return; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1478 | 1490 |
| 1479 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP; | 1491 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP; |
| 1480 auth_identity_[target].invalid = false; | 1492 auth_identity_[target].invalid = false; |
| 1481 auth_identity_[target].username = entry->username(); | 1493 auth_identity_[target].username = entry->username(); |
| 1482 auth_identity_[target].password = entry->password(); | 1494 auth_identity_[target].password = entry->password(); |
| 1483 return true; | 1495 return true; |
| 1484 } | 1496 } |
| 1485 return false; | 1497 return false; |
| 1486 } | 1498 } |
| 1487 | 1499 |
| 1500 std::string HttpNetworkTransaction::AuthChallengeLogMessage() const { |
| 1501 std::string msg; |
| 1502 std::string header_val; |
| 1503 void* iter = NULL; |
| 1504 while (response_.headers->EnumerateHeader(&iter, "proxy-authenticate", |
| 1505 &header_val)) { |
| 1506 msg.append("\n Has header Proxy-Authenticate: "); |
| 1507 msg.append(header_val); |
| 1508 } |
| 1509 |
| 1510 iter = NULL; |
| 1511 while (response_.headers->EnumerateHeader(&iter, "www-authenticate", |
| 1512 &header_val)) { |
| 1513 msg.append("\n Has header WWW-Authenticate: "); |
| 1514 msg.append(header_val); |
| 1515 } |
| 1516 |
| 1517 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate |
| 1518 // authentication with a "Proxy-Support: Session-Based-Authentication" |
| 1519 // response header. |
| 1520 iter = NULL; |
| 1521 while (response_.headers->EnumerateHeader(&iter, "proxy-support", |
| 1522 &header_val)) { |
| 1523 msg.append("\n Has header Proxy-Support: "); |
| 1524 msg.append(header_val); |
| 1525 } |
| 1526 |
| 1527 return msg; |
| 1528 } |
| 1529 |
| 1488 int HttpNetworkTransaction::HandleAuthChallenge() { | 1530 int HttpNetworkTransaction::HandleAuthChallenge() { |
| 1489 DCHECK(response_.headers); | 1531 DCHECK(response_.headers); |
| 1490 | 1532 |
| 1491 int status = response_.headers->response_code(); | 1533 int status = response_.headers->response_code(); |
| 1492 if (status != 401 && status != 407) | 1534 if (status != 401 && status != 407) |
| 1493 return OK; | 1535 return OK; |
| 1494 HttpAuth::Target target = status == 407 ? | 1536 HttpAuth::Target target = status == 407 ? |
| 1495 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER; | 1537 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER; |
| 1496 | 1538 |
| 1539 LOG(INFO) << "The " << AuthTargetString(target) << " " |
| 1540 << AuthOrigin(target) << " requested auth" |
| 1541 << AuthChallengeLogMessage(); |
| 1542 |
| 1497 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) | 1543 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) |
| 1498 return ERR_UNEXPECTED_PROXY_AUTH; | 1544 return ERR_UNEXPECTED_PROXY_AUTH; |
| 1499 | 1545 |
| 1500 // The auth we tried just failed, hence it can't be valid. Remove it from | 1546 // The auth we tried just failed, hence it can't be valid. Remove it from |
| 1501 // the cache so it won't be used again, unless it's a null identity. | 1547 // the cache so it won't be used again, unless it's a null identity. |
| 1502 if (HaveAuth(target) && | 1548 if (HaveAuth(target) && |
| 1503 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) | 1549 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) |
| 1504 InvalidateRejectedAuthFromCache(target); | 1550 InvalidateRejectedAuthFromCache(target); |
| 1505 | 1551 |
| 1506 auth_identity_[target].invalid = true; | 1552 auth_identity_[target].invalid = true; |
| 1507 | 1553 |
| 1508 // Find the best authentication challenge that we support. | 1554 // Find the best authentication challenge that we support. |
| 1509 HttpAuth::ChooseBestChallenge(response_.headers.get(), | 1555 HttpAuth::ChooseBestChallenge(response_.headers.get(), |
| 1510 target, | 1556 target, |
| 1511 &auth_handler_[target]); | 1557 &auth_handler_[target]); |
| 1512 | 1558 |
| 1513 if (!auth_handler_[target]) { | 1559 if (!auth_handler_[target]) { |
| 1514 if (establishing_tunnel_) { | 1560 if (establishing_tunnel_) { |
| 1515 // Log an error message to help debug http://crbug.com/8771. | 1561 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target) |
| 1516 std::string auth_target(target == HttpAuth::AUTH_PROXY ? | 1562 << " " << AuthOrigin(target) |
| 1517 "proxy" : "server"); | 1563 << " when establishing a tunnel" |
| 1518 LOG(ERROR) << "Can't perform auth to the " << auth_target << " " | 1564 << AuthChallengeLogMessage(); |
| 1519 << AuthOrigin(target).spec() | |
| 1520 << " when establishing a tunnel"; | |
| 1521 | |
| 1522 std::string challenge; | |
| 1523 void* iter = NULL; | |
| 1524 while (response_.headers->EnumerateHeader(&iter, "Proxy-Authenticate", | |
| 1525 &challenge)) { | |
| 1526 LOG(ERROR) << " Has header Proxy-Authenticate: " << challenge; | |
| 1527 } | |
| 1528 | |
| 1529 iter = NULL; | |
| 1530 while (response_.headers->EnumerateHeader(&iter, "WWW-Authenticate", | |
| 1531 &challenge)) { | |
| 1532 LOG(ERROR) << " Has header WWW-Authenticate: " << challenge; | |
| 1533 } | |
| 1534 | 1565 |
| 1535 // We are establishing a tunnel, we can't show the error page because an | 1566 // We are establishing a tunnel, we can't show the error page because an |
| 1536 // active network attacker could control its contents. Instead, we just | 1567 // active network attacker could control its contents. Instead, we just |
| 1537 // fail to establish the tunnel. | 1568 // fail to establish the tunnel. |
| 1538 DCHECK(target == HttpAuth::AUTH_PROXY); | 1569 DCHECK(target == HttpAuth::AUTH_PROXY); |
| 1539 return ERR_PROXY_AUTH_REQUESTED; | 1570 return ERR_PROXY_AUTH_REQUESTED; |
| 1540 } | 1571 } |
| 1541 // We found no supported challenge -- let the transaction continue | 1572 // We found no supported challenge -- let the transaction continue |
| 1542 // so we end up displaying the error page. | 1573 // so we end up displaying the error page. |
| 1543 return OK; | 1574 return OK; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1582 if (target == HttpAuth::AUTH_PROXY) { | 1613 if (target == HttpAuth::AUTH_PROXY) { |
| 1583 auth_info->host = ASCIIToWide(proxy_info_.proxy_server().host_and_port()); | 1614 auth_info->host = ASCIIToWide(proxy_info_.proxy_server().host_and_port()); |
| 1584 } else { | 1615 } else { |
| 1585 DCHECK(target == HttpAuth::AUTH_SERVER); | 1616 DCHECK(target == HttpAuth::AUTH_SERVER); |
| 1586 auth_info->host = ASCIIToWide(request_->url.host()); | 1617 auth_info->host = ASCIIToWide(request_->url.host()); |
| 1587 } | 1618 } |
| 1588 response_.auth_challenge = auth_info; | 1619 response_.auth_challenge = auth_info; |
| 1589 } | 1620 } |
| 1590 | 1621 |
| 1591 } // namespace net | 1622 } // namespace net |
| OLD | NEW |