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/format_macros.h" | |
8 #include "base/scoped_ptr.h" | |
9 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
10 #include "base/field_trial.h" | 8 #include "base/field_trial.h" |
| 9 #include "base/format_macros.h" |
11 #include "base/histogram.h" | 10 #include "base/histogram.h" |
| 11 #include "base/scoped_ptr.h" |
12 #include "base/stats_counters.h" | 12 #include "base/stats_counters.h" |
13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
14 #include "base/trace_event.h" | 14 #include "base/trace_event.h" |
15 #include "build/build_config.h" | 15 #include "build/build_config.h" |
16 #include "net/base/connection_type_histograms.h" | 16 #include "net/base/connection_type_histograms.h" |
17 #include "net/base/io_buffer.h" | 17 #include "net/base/io_buffer.h" |
18 #include "net/base/load_flags.h" | 18 #include "net/base/load_flags.h" |
19 #include "net/base/net_errors.h" | 19 #include "net/base/net_errors.h" |
20 #include "net/base/net_util.h" | 20 #include "net/base/net_util.h" |
21 #include "net/base/ssl_cert_request_info.h" | 21 #include "net/base/ssl_cert_request_info.h" |
22 #include "net/base/upload_data_stream.h" | 22 #include "net/base/upload_data_stream.h" |
23 #include "net/http/http_auth.h" | 23 #include "net/http/http_auth.h" |
24 #include "net/http/http_auth_handler.h" | 24 #include "net/http/http_auth_handler.h" |
25 #include "net/http/http_basic_stream.h" | 25 #include "net/http/http_basic_stream.h" |
26 #include "net/http/http_chunked_decoder.h" | 26 #include "net/http/http_chunked_decoder.h" |
27 #include "net/http/http_network_session.h" | 27 #include "net/http/http_network_session.h" |
| 28 #include "net/http/http_request_headers.h" |
28 #include "net/http/http_request_info.h" | 29 #include "net/http/http_request_info.h" |
29 #include "net/http/http_response_headers.h" | 30 #include "net/http/http_response_headers.h" |
30 #include "net/http/http_response_info.h" | 31 #include "net/http/http_response_info.h" |
31 #include "net/http/http_util.h" | 32 #include "net/http/http_util.h" |
32 #include "net/socket/client_socket_factory.h" | 33 #include "net/socket/client_socket_factory.h" |
33 #include "net/socket/socks5_client_socket.h" | 34 #include "net/socket/socks5_client_socket.h" |
34 #include "net/socket/socks_client_socket.h" | 35 #include "net/socket/socks_client_socket.h" |
35 #include "net/socket/ssl_client_socket.h" | 36 #include "net/socket/ssl_client_socket.h" |
36 #include "net/socket/tcp_client_socket_pool.h" | 37 #include "net/socket/tcp_client_socket_pool.h" |
37 #include "net/spdy/spdy_session.h" | 38 #include "net/spdy/spdy_session.h" |
38 #include "net/spdy/spdy_session_pool.h" | 39 #include "net/spdy/spdy_session_pool.h" |
39 #include "net/spdy/spdy_stream.h" | 40 #include "net/spdy/spdy_stream.h" |
40 | 41 |
41 using base::Time; | 42 using base::Time; |
42 | 43 |
43 namespace net { | 44 namespace net { |
44 | 45 |
45 namespace { | 46 namespace { |
46 | 47 |
47 const std::string* g_next_protos = NULL; | 48 const std::string* g_next_protos = NULL; |
48 | 49 |
49 void BuildRequestHeaders(const HttpRequestInfo* request_info, | 50 void BuildRequestHeaders(const HttpRequestInfo* request_info, |
50 const std::string& authorization_headers, | 51 const HttpRequestHeaders& authorization_headers, |
51 const UploadDataStream* upload_data_stream, | 52 const UploadDataStream* upload_data_stream, |
52 bool using_proxy, | 53 bool using_proxy, |
53 std::string* request_headers) { | 54 HttpRequestHeaders* request_headers) { |
| 55 const std::string path = using_proxy ? |
| 56 HttpUtil::SpecForRequest(request_info->url) : |
| 57 HttpUtil::PathForRequest(request_info->url); |
| 58 request_headers->SetRequestLine( |
| 59 request_info->method, path, "1.1"); |
| 60 |
| 61 request_headers->SetHeader(HttpRequestHeaders::kHost, |
| 62 GetHostAndOptionalPort(request_info->url)); |
| 63 |
| 64 // For compat with HTTP/1.0 servers and proxies: |
| 65 if (using_proxy) { |
| 66 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection, |
| 67 "keep-alive"); |
| 68 } else { |
| 69 request_headers->SetHeader(HttpRequestHeaders::kConnection, "keep-alive"); |
| 70 } |
| 71 |
| 72 if (!request_info->user_agent.empty()) { |
| 73 request_headers->SetHeader(HttpRequestHeaders::kUserAgent, |
| 74 request_info->user_agent); |
| 75 } |
| 76 |
| 77 // Our consumer should have made sure that this is a safe referrer. See for |
| 78 // instance WebCore::FrameLoader::HideReferrer. |
| 79 if (request_info->referrer.is_valid()) { |
| 80 request_headers->SetHeader(HttpRequestHeaders::kReferer, |
| 81 request_info->referrer.spec()); |
| 82 } |
| 83 |
| 84 // Add a content length header? |
| 85 if (upload_data_stream) { |
| 86 request_headers->SetHeader( |
| 87 HttpRequestHeaders::kContentLength, |
| 88 Uint64ToString(upload_data_stream->size())); |
| 89 } else if (request_info->method == "POST" || request_info->method == "PUT" || |
| 90 request_info->method == "HEAD") { |
| 91 // An empty POST/PUT request still needs a content length. As for HEAD, |
| 92 // IE and Safari also add a content length header. Presumably it is to |
| 93 // support sending a HEAD request to an URL that only expects to be sent a |
| 94 // POST or some other method that normally would have a message body. |
| 95 request_headers->SetHeader(HttpRequestHeaders::kContentLength, "0"); |
| 96 } |
| 97 |
| 98 // Honor load flags that impact proxy caches. |
| 99 if (request_info->load_flags & LOAD_BYPASS_CACHE) { |
| 100 request_headers->SetHeader(HttpRequestHeaders::kPragma, "no-cache"); |
| 101 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "no-cache"); |
| 102 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) { |
| 103 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0"); |
| 104 } |
| 105 |
| 106 request_headers->MergeFrom(authorization_headers); |
| 107 |
54 // Headers that will be stripped from request_info->extra_headers to prevent, | 108 // Headers that will be stripped from request_info->extra_headers to prevent, |
55 // e.g., plugins from overriding headers that are controlled using other | 109 // e.g., plugins from overriding headers that are controlled using other |
56 // means. Otherwise a plugin could set a referrer although sending the | 110 // means. Otherwise a plugin could set a referrer although sending the |
57 // referrer is inhibited. | 111 // referrer is inhibited. |
58 // TODO(jochen): check whether also other headers should be stripped. | 112 // TODO(jochen): check whether also other headers should be stripped. |
59 static const char* const kExtraHeadersToBeStripped[] = { | 113 static const char* const kExtraHeadersToBeStripped[] = { |
60 "Referer" | 114 "Referer" |
61 }; | 115 }; |
62 | 116 |
63 const std::string path = using_proxy ? | 117 // TODO(willchan): Change HttpRequestInfo::extra_headers to be a |
64 HttpUtil::SpecForRequest(request_info->url) : | 118 // HttpRequestHeaders. |
65 HttpUtil::PathForRequest(request_info->url); | |
66 *request_headers = | |
67 StringPrintf("%s %s HTTP/1.1\r\nHost: %s\r\n", | |
68 request_info->method.c_str(), path.c_str(), | |
69 GetHostAndOptionalPort(request_info->url).c_str()); | |
70 | 119 |
71 // For compat with HTTP/1.0 servers and proxies: | 120 std::vector<std::string> extra_headers_vector; |
72 if (using_proxy) | 121 Tokenize(request_info->extra_headers, "\r\n", &extra_headers_vector); |
73 *request_headers += "Proxy-"; | 122 HttpRequestHeaders extra_headers; |
74 *request_headers += "Connection: keep-alive\r\n"; | 123 if (!extra_headers_vector.empty()) { |
| 124 for (std::vector<std::string>::const_iterator it = |
| 125 extra_headers_vector.begin(); it != extra_headers_vector.end(); ++it) |
| 126 extra_headers.AddHeaderFromString(*it); |
75 | 127 |
76 if (!request_info->user_agent.empty()) { | 128 for (size_t i = 0; i < arraysize(kExtraHeadersToBeStripped); ++i) |
77 StringAppendF(request_headers, "User-Agent: %s\r\n", | 129 extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]); |
78 request_info->user_agent.c_str()); | 130 |
| 131 request_headers->MergeFrom(extra_headers); |
79 } | 132 } |
80 | |
81 // Our consumer should have made sure that this is a safe referrer. See for | |
82 // instance WebCore::FrameLoader::HideReferrer. | |
83 if (request_info->referrer.is_valid()) | |
84 StringAppendF(request_headers, "Referer: %s\r\n", | |
85 request_info->referrer.spec().c_str()); | |
86 | |
87 // Add a content length header? | |
88 if (upload_data_stream) { | |
89 StringAppendF(request_headers, "Content-Length: %" PRIu64 "\r\n", | |
90 upload_data_stream->size()); | |
91 } else if (request_info->method == "POST" || request_info->method == "PUT" || | |
92 request_info->method == "HEAD") { | |
93 // An empty POST/PUT request still needs a content length. As for HEAD, | |
94 // IE and Safari also add a content length header. Presumably it is to | |
95 // support sending a HEAD request to an URL that only expects to be sent a | |
96 // POST or some other method that normally would have a message body. | |
97 *request_headers += "Content-Length: 0\r\n"; | |
98 } | |
99 | |
100 // Honor load flags that impact proxy caches. | |
101 if (request_info->load_flags & LOAD_BYPASS_CACHE) { | |
102 *request_headers += "Pragma: no-cache\r\nCache-Control: no-cache\r\n"; | |
103 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) { | |
104 *request_headers += "Cache-Control: max-age=0\r\n"; | |
105 } | |
106 | |
107 if (!authorization_headers.empty()) { | |
108 *request_headers += authorization_headers; | |
109 } | |
110 | |
111 // TODO(darin): Need to prune out duplicate headers. | |
112 | |
113 *request_headers += HttpUtil::StripHeaders(request_info->extra_headers, | |
114 kExtraHeadersToBeStripped, arraysize(kExtraHeadersToBeStripped)); | |
115 *request_headers += "\r\n"; | |
116 } | 133 } |
117 | 134 |
118 // The HTTP CONNECT method for establishing a tunnel connection is documented | 135 // The HTTP CONNECT method for establishing a tunnel connection is documented |
119 // in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and | 136 // in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and |
120 // 5.3. | 137 // 5.3. |
121 void BuildTunnelRequest(const HttpRequestInfo* request_info, | 138 void BuildTunnelRequest(const HttpRequestInfo* request_info, |
122 const std::string& authorization_headers, | 139 const HttpRequestHeaders& authorization_headers, |
123 std::string* request_headers) { | 140 HttpRequestHeaders* request_headers) { |
124 // RFC 2616 Section 9 says the Host request-header field MUST accompany all | 141 // RFC 2616 Section 9 says the Host request-header field MUST accompany all |
125 // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with | 142 // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with |
126 // HTTP/1.0 proxies such as Squid (required for NTLM authentication). | 143 // HTTP/1.0 proxies such as Squid (required for NTLM authentication). |
127 *request_headers = StringPrintf( | 144 request_headers->SetRequestLine( |
128 "CONNECT %s HTTP/1.1\r\nHost: %s\r\nProxy-Connection: keep-alive\r\n", | 145 "CONNECT", GetHostAndPort(request_info->url), "1.1"); |
129 GetHostAndPort(request_info->url).c_str(), | 146 request_headers->SetHeader(HttpRequestHeaders::kHost, |
130 GetHostAndOptionalPort(request_info->url).c_str()); | 147 GetHostAndOptionalPort(request_info->url)); |
| 148 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection, |
| 149 "keep-alive"); |
131 | 150 |
132 if (!request_info->user_agent.empty()) | 151 if (!request_info->user_agent.empty()) { |
133 StringAppendF(request_headers, "User-Agent: %s\r\n", | 152 request_headers->SetHeader(HttpRequestHeaders::kUserAgent, |
134 request_info->user_agent.c_str()); | 153 request_info->user_agent); |
135 | |
136 if (!authorization_headers.empty()) { | |
137 *request_headers += authorization_headers; | |
138 } | 154 } |
139 | 155 |
140 *request_headers += "\r\n"; | 156 request_headers->MergeFrom(authorization_headers); |
141 } | 157 } |
142 | 158 |
143 void ProcessAlternateProtocol(const HttpResponseHeaders& headers, | 159 void ProcessAlternateProtocol(const HttpResponseHeaders& headers, |
144 const HostPortPair& http_host_port_pair, | 160 const HostPortPair& http_host_port_pair, |
145 HttpAlternateProtocols* alternate_protocols) { | 161 HttpAlternateProtocols* alternate_protocols) { |
146 if (!g_next_protos || g_next_protos->empty()) { | 162 if (!g_next_protos || g_next_protos->empty()) { |
147 // This implies that NPN is not suppoted. We don't currently support any | 163 // This implies that NPN is not suppoted. We don't currently support any |
148 // alternate protocols that don't use NPN. | 164 // alternate protocols that don't use NPN. |
149 return; | 165 return; |
150 } | 166 } |
(...skipping 790 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
941 // headers. | 957 // headers. |
942 bool have_proxy_auth = | 958 bool have_proxy_auth = |
943 ShouldApplyProxyAuth() && | 959 ShouldApplyProxyAuth() && |
944 (HaveAuth(HttpAuth::AUTH_PROXY) || | 960 (HaveAuth(HttpAuth::AUTH_PROXY) || |
945 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY)); | 961 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY)); |
946 bool have_server_auth = | 962 bool have_server_auth = |
947 ShouldApplyServerAuth() && | 963 ShouldApplyServerAuth() && |
948 (HaveAuth(HttpAuth::AUTH_SERVER) || | 964 (HaveAuth(HttpAuth::AUTH_SERVER) || |
949 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER)); | 965 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER)); |
950 | 966 |
951 std::string authorization_headers; | 967 HttpRequestHeaders request_headers; |
| 968 HttpRequestHeaders authorization_headers; |
952 | 969 |
953 // TODO(wtc): If BuildAuthorizationHeader fails (returns an authorization | 970 // TODO(wtc): If BuildAuthorizationHeader fails (returns an authorization |
954 // header with no credentials), we should return an error to prevent | 971 // header with no credentials), we should return an error to prevent |
955 // entering an infinite auth restart loop. See http://crbug.com/21050. | 972 // entering an infinite auth restart loop. See http://crbug.com/21050. |
956 if (have_proxy_auth) | 973 if (have_proxy_auth) |
957 authorization_headers.append( | 974 AddAuthorizationHeader(HttpAuth::AUTH_PROXY, &authorization_headers); |
958 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY)); | |
959 if (have_server_auth) | 975 if (have_server_auth) |
960 authorization_headers.append( | 976 AddAuthorizationHeader(HttpAuth::AUTH_SERVER, &authorization_headers); |
961 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER)); | |
962 | 977 |
963 if (establishing_tunnel_) { | 978 if (establishing_tunnel_) { |
964 BuildTunnelRequest(request_, authorization_headers, &request_headers_); | 979 BuildTunnelRequest(request_, authorization_headers, &request_headers); |
965 } else { | 980 } else { |
966 BuildRequestHeaders(request_, authorization_headers, request_body, | 981 BuildRequestHeaders(request_, authorization_headers, request_body, |
967 proxy_mode_ == kHTTPProxy, &request_headers_); | 982 proxy_mode_ == kHTTPProxy, &request_headers); |
968 } | 983 } |
| 984 |
| 985 request_headers_ = request_headers.ToString(); |
969 } | 986 } |
970 | 987 |
971 headers_valid_ = false; | 988 headers_valid_ = false; |
972 http_stream_.reset(new HttpBasicStream(connection_.get(), load_log_)); | 989 http_stream_.reset(new HttpBasicStream(connection_.get(), load_log_)); |
973 | 990 |
974 return http_stream_->SendRequest(request_, request_headers_, | 991 return http_stream_->SendRequest(request_, request_headers_, |
975 request_body, &response_, &io_callback_); | 992 request_body, &response_, &io_callback_); |
976 } | 993 } |
977 | 994 |
978 int HttpNetworkTransaction::DoSendRequestComplete(int result) { | 995 int HttpNetworkTransaction::DoSendRequestComplete(int result) { |
(...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1642 | 1659 |
1643 bool HttpNetworkTransaction::ShouldApplyProxyAuth() const { | 1660 bool HttpNetworkTransaction::ShouldApplyProxyAuth() const { |
1644 return (proxy_mode_ == kHTTPProxy) || establishing_tunnel_; | 1661 return (proxy_mode_ == kHTTPProxy) || establishing_tunnel_; |
1645 } | 1662 } |
1646 | 1663 |
1647 bool HttpNetworkTransaction::ShouldApplyServerAuth() const { | 1664 bool HttpNetworkTransaction::ShouldApplyServerAuth() const { |
1648 return !establishing_tunnel_ && | 1665 return !establishing_tunnel_ && |
1649 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA); | 1666 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA); |
1650 } | 1667 } |
1651 | 1668 |
1652 std::string HttpNetworkTransaction::BuildAuthorizationHeader( | 1669 void HttpNetworkTransaction::AddAuthorizationHeader( |
1653 HttpAuth::Target target) const { | 1670 HttpAuth::Target target, HttpRequestHeaders* authorization_headers) const { |
1654 DCHECK(HaveAuth(target)); | 1671 DCHECK(HaveAuth(target)); |
1655 | 1672 |
1656 // Add a Authorization/Proxy-Authorization header line. | 1673 // Add a Authorization/Proxy-Authorization header line. |
1657 std::string auth_token; | 1674 std::string auth_token; |
1658 int rv = auth_handler_[target]->GenerateAuthToken( | 1675 int rv = auth_handler_[target]->GenerateAuthToken( |
1659 auth_identity_[target].username, | 1676 auth_identity_[target].username, |
1660 auth_identity_[target].password, | 1677 auth_identity_[target].password, |
1661 request_, | 1678 request_, |
1662 &proxy_info_, | 1679 &proxy_info_, |
1663 &auth_token); | 1680 &auth_token); |
1664 if (rv == OK) | 1681 if (rv == OK) { |
1665 return HttpAuth::GetAuthorizationHeaderName(target) + | 1682 authorization_headers->SetHeader( |
1666 ": " + auth_token + "\r\n"; | 1683 HttpAuth::GetAuthorizationHeaderName(target), auth_token); |
| 1684 } |
1667 | 1685 |
1668 // TODO(cbentzel): Evict username and password from cache on non-OK return? | 1686 // TODO(cbentzel): Evict username and password from cache on non-OK return? |
1669 // TODO(cbentzel): Never use this scheme again if | 1687 // TODO(cbentzel): Never use this scheme again if |
1670 // ERR_UNSUPPORTED_AUTH_SCHEME is returned. | 1688 // ERR_UNSUPPORTED_AUTH_SCHEME is returned. |
1671 return std::string(); | |
1672 } | 1689 } |
1673 | 1690 |
1674 GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const { | 1691 GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const { |
1675 return target == HttpAuth::AUTH_PROXY ? | 1692 return target == HttpAuth::AUTH_PROXY ? |
1676 GURL("http://" + proxy_info_.proxy_server().host_and_port()) : | 1693 GURL("http://" + proxy_info_.proxy_server().host_and_port()) : |
1677 request_->url.GetOrigin(); | 1694 request_->url.GetOrigin(); |
1678 } | 1695 } |
1679 | 1696 |
1680 std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target) | 1697 std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target) |
1681 const { | 1698 const { |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1927 http_host_port_pair); | 1944 http_host_port_pair); |
1928 | 1945 |
1929 alternate_protocol_mode_ = kDoNotUseAlternateProtocol; | 1946 alternate_protocol_mode_ = kDoNotUseAlternateProtocol; |
1930 if (connection_->socket()) | 1947 if (connection_->socket()) |
1931 connection_->socket()->Disconnect(); | 1948 connection_->socket()->Disconnect(); |
1932 connection_->Reset(); | 1949 connection_->Reset(); |
1933 next_state_ = STATE_INIT_CONNECTION; | 1950 next_state_ = STATE_INIT_CONNECTION; |
1934 } | 1951 } |
1935 | 1952 |
1936 } // namespace net | 1953 } // namespace net |
OLD | NEW |