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

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

Issue 1039001: HttpRequestHeaders refactor. (Closed)
Patch Set: Fix bugs, add tests. Created 10 years, 9 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
« 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) 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
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
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
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
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