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" |
7 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
8 #include "base/field_trial.h" | 10 #include "base/field_trial.h" |
9 #include "base/format_macros.h" | |
10 #include "base/histogram.h" | 11 #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" | |
29 #include "net/http/http_request_info.h" | 28 #include "net/http/http_request_info.h" |
30 #include "net/http/http_response_headers.h" | 29 #include "net/http/http_response_headers.h" |
31 #include "net/http/http_response_info.h" | 30 #include "net/http/http_response_info.h" |
32 #include "net/http/http_util.h" | 31 #include "net/http/http_util.h" |
33 #include "net/socket/client_socket_factory.h" | 32 #include "net/socket/client_socket_factory.h" |
34 #include "net/socket/socks_client_socket_pool.h" | 33 #include "net/socket/socks_client_socket_pool.h" |
35 #include "net/socket/ssl_client_socket.h" | 34 #include "net/socket/ssl_client_socket.h" |
36 #include "net/socket/tcp_client_socket_pool.h" | 35 #include "net/socket/tcp_client_socket_pool.h" |
37 #include "net/spdy/spdy_session.h" | 36 #include "net/spdy/spdy_session.h" |
38 #include "net/spdy/spdy_session_pool.h" | 37 #include "net/spdy/spdy_session_pool.h" |
39 #include "net/spdy/spdy_stream.h" | 38 #include "net/spdy/spdy_stream.h" |
40 | 39 |
41 using base::Time; | 40 using base::Time; |
42 | 41 |
43 namespace net { | 42 namespace net { |
44 | 43 |
45 namespace { | 44 namespace { |
46 | 45 |
47 const std::string* g_next_protos = NULL; | 46 const std::string* g_next_protos = NULL; |
48 | 47 |
49 void BuildRequestHeaders(const HttpRequestInfo* request_info, | 48 void BuildRequestHeaders(const HttpRequestInfo* request_info, |
50 const HttpRequestHeaders& authorization_headers, | 49 const std::string& authorization_headers, |
51 const UploadDataStream* upload_data_stream, | 50 const UploadDataStream* upload_data_stream, |
52 bool using_proxy, | 51 bool using_proxy, |
53 HttpRequestHeaders* request_headers) { | 52 std::string* request_headers) { |
54 const std::string path = using_proxy ? | |
55 HttpUtil::SpecForRequest(request_info->url) : | |
56 HttpUtil::PathForRequest(request_info->url); | |
57 request_headers->SetRequestLine( | |
58 request_info->method, path, "1.1"); | |
59 | |
60 request_headers->SetHeader(HttpRequestHeaders::kHost, | |
61 GetHostAndOptionalPort(request_info->url)); | |
62 | |
63 // For compat with HTTP/1.0 servers and proxies: | |
64 if (using_proxy) { | |
65 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection, | |
66 "keep-alive"); | |
67 } else { | |
68 request_headers->SetHeader(HttpRequestHeaders::kConnection, "keep-alive"); | |
69 } | |
70 | |
71 if (!request_info->user_agent.empty()) { | |
72 request_headers->SetHeader(HttpRequestHeaders::kUserAgent, | |
73 request_info->user_agent); | |
74 } | |
75 | |
76 // Our consumer should have made sure that this is a safe referrer. See for | |
77 // instance WebCore::FrameLoader::HideReferrer. | |
78 if (request_info->referrer.is_valid()) { | |
79 request_headers->SetHeader(HttpRequestHeaders::kReferer, | |
80 request_info->referrer.spec()); | |
81 } | |
82 | |
83 // Add a content length header? | |
84 if (upload_data_stream) { | |
85 request_headers->SetHeader( | |
86 HttpRequestHeaders::kContentLength, | |
87 Uint64ToString(upload_data_stream->size())); | |
88 } else if (request_info->method == "POST" || request_info->method == "PUT" || | |
89 request_info->method == "HEAD") { | |
90 // An empty POST/PUT request still needs a content length. As for HEAD, | |
91 // IE and Safari also add a content length header. Presumably it is to | |
92 // support sending a HEAD request to an URL that only expects to be sent a | |
93 // POST or some other method that normally would have a message body. | |
94 request_headers->SetHeader(HttpRequestHeaders::kContentLength, "0"); | |
95 } | |
96 | |
97 // Honor load flags that impact proxy caches. | |
98 if (request_info->load_flags & LOAD_BYPASS_CACHE) { | |
99 request_headers->SetHeader(HttpRequestHeaders::kPragma, "no-cache"); | |
100 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "no-cache"); | |
101 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) { | |
102 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0"); | |
103 } | |
104 | |
105 request_headers->MergeFrom(authorization_headers); | |
106 | |
107 // Headers that will be stripped from request_info->extra_headers to prevent, | 53 // Headers that will be stripped from request_info->extra_headers to prevent, |
108 // e.g., plugins from overriding headers that are controlled using other | 54 // e.g., plugins from overriding headers that are controlled using other |
109 // means. Otherwise a plugin could set a referrer although sending the | 55 // means. Otherwise a plugin could set a referrer although sending the |
110 // referrer is inhibited. | 56 // referrer is inhibited. |
111 // TODO(jochen): check whether also other headers should be stripped. | 57 // TODO(jochen): check whether also other headers should be stripped. |
112 static const char* const kExtraHeadersToBeStripped[] = { | 58 static const char* const kExtraHeadersToBeStripped[] = { |
113 "Referer" | 59 "Referer" |
114 }; | 60 }; |
115 | 61 |
116 // TODO(willchan): Change HttpRequestInfo::extra_headers to be a | 62 const std::string path = using_proxy ? |
117 // HttpRequestHeaders. | 63 HttpUtil::SpecForRequest(request_info->url) : |
| 64 HttpUtil::PathForRequest(request_info->url); |
| 65 *request_headers = |
| 66 StringPrintf("%s %s HTTP/1.1\r\nHost: %s\r\n", |
| 67 request_info->method.c_str(), path.c_str(), |
| 68 GetHostAndOptionalPort(request_info->url).c_str()); |
118 | 69 |
119 std::vector<std::string> extra_headers_vector; | 70 // For compat with HTTP/1.0 servers and proxies: |
120 Tokenize(request_info->extra_headers, "\r\n", &extra_headers_vector); | 71 if (using_proxy) |
121 HttpRequestHeaders extra_headers; | 72 *request_headers += "Proxy-"; |
122 if (!extra_headers_vector.empty()) { | 73 *request_headers += "Connection: keep-alive\r\n"; |
123 for (std::vector<std::string>::const_iterator it = | |
124 extra_headers_vector.begin(); it != extra_headers_vector.end(); ++it) | |
125 extra_headers.AddHeaderFromString(*it); | |
126 | 74 |
127 for (size_t i = 0; i < arraysize(kExtraHeadersToBeStripped); ++i) | 75 if (!request_info->user_agent.empty()) { |
128 extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]); | 76 StringAppendF(request_headers, "User-Agent: %s\r\n", |
| 77 request_info->user_agent.c_str()); |
| 78 } |
129 | 79 |
130 request_headers->MergeFrom(extra_headers); | 80 // Our consumer should have made sure that this is a safe referrer. See for |
| 81 // instance WebCore::FrameLoader::HideReferrer. |
| 82 if (request_info->referrer.is_valid()) |
| 83 StringAppendF(request_headers, "Referer: %s\r\n", |
| 84 request_info->referrer.spec().c_str()); |
| 85 |
| 86 // Add a content length header? |
| 87 if (upload_data_stream) { |
| 88 StringAppendF(request_headers, "Content-Length: %" PRIu64 "\r\n", |
| 89 upload_data_stream->size()); |
| 90 } else if (request_info->method == "POST" || request_info->method == "PUT" || |
| 91 request_info->method == "HEAD") { |
| 92 // An empty POST/PUT request still needs a content length. As for HEAD, |
| 93 // IE and Safari also add a content length header. Presumably it is to |
| 94 // support sending a HEAD request to an URL that only expects to be sent a |
| 95 // POST or some other method that normally would have a message body. |
| 96 *request_headers += "Content-Length: 0\r\n"; |
131 } | 97 } |
| 98 |
| 99 // Honor load flags that impact proxy caches. |
| 100 if (request_info->load_flags & LOAD_BYPASS_CACHE) { |
| 101 *request_headers += "Pragma: no-cache\r\nCache-Control: no-cache\r\n"; |
| 102 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) { |
| 103 *request_headers += "Cache-Control: max-age=0\r\n"; |
| 104 } |
| 105 |
| 106 if (!authorization_headers.empty()) { |
| 107 *request_headers += authorization_headers; |
| 108 } |
| 109 |
| 110 // TODO(darin): Need to prune out duplicate headers. |
| 111 |
| 112 *request_headers += HttpUtil::StripHeaders(request_info->extra_headers, |
| 113 kExtraHeadersToBeStripped, arraysize(kExtraHeadersToBeStripped)); |
| 114 *request_headers += "\r\n"; |
132 } | 115 } |
133 | 116 |
134 // The HTTP CONNECT method for establishing a tunnel connection is documented | 117 // The HTTP CONNECT method for establishing a tunnel connection is documented |
135 // in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and | 118 // in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and |
136 // 5.3. | 119 // 5.3. |
137 void BuildTunnelRequest(const HttpRequestInfo* request_info, | 120 void BuildTunnelRequest(const HttpRequestInfo* request_info, |
138 const HttpRequestHeaders& authorization_headers, | 121 const std::string& authorization_headers, |
139 HttpRequestHeaders* request_headers) { | 122 std::string* request_headers) { |
140 // RFC 2616 Section 9 says the Host request-header field MUST accompany all | 123 // RFC 2616 Section 9 says the Host request-header field MUST accompany all |
141 // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with | 124 // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with |
142 // HTTP/1.0 proxies such as Squid (required for NTLM authentication). | 125 // HTTP/1.0 proxies such as Squid (required for NTLM authentication). |
143 request_headers->SetRequestLine( | 126 *request_headers = StringPrintf( |
144 "CONNECT", GetHostAndPort(request_info->url), "1.1"); | 127 "CONNECT %s HTTP/1.1\r\nHost: %s\r\nProxy-Connection: keep-alive\r\n", |
145 request_headers->SetHeader(HttpRequestHeaders::kHost, | 128 GetHostAndPort(request_info->url).c_str(), |
146 GetHostAndOptionalPort(request_info->url)); | 129 GetHostAndOptionalPort(request_info->url).c_str()); |
147 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection, | |
148 "keep-alive"); | |
149 | 130 |
150 if (!request_info->user_agent.empty()) { | 131 if (!request_info->user_agent.empty()) |
151 request_headers->SetHeader(HttpRequestHeaders::kUserAgent, | 132 StringAppendF(request_headers, "User-Agent: %s\r\n", |
152 request_info->user_agent); | 133 request_info->user_agent.c_str()); |
| 134 |
| 135 if (!authorization_headers.empty()) { |
| 136 *request_headers += authorization_headers; |
153 } | 137 } |
154 | 138 |
155 request_headers->MergeFrom(authorization_headers); | 139 *request_headers += "\r\n"; |
156 } | 140 } |
157 | 141 |
158 void ProcessAlternateProtocol(const HttpResponseHeaders& headers, | 142 void ProcessAlternateProtocol(const HttpResponseHeaders& headers, |
159 const HostPortPair& http_host_port_pair, | 143 const HostPortPair& http_host_port_pair, |
160 HttpAlternateProtocols* alternate_protocols) { | 144 HttpAlternateProtocols* alternate_protocols) { |
161 if (!g_next_protos || g_next_protos->empty()) { | 145 if (!g_next_protos || g_next_protos->empty()) { |
162 // This implies that NPN is not suppoted. We don't currently support any | 146 // This implies that NPN is not suppoted. We don't currently support any |
163 // alternate protocols that don't use NPN. | 147 // alternate protocols that don't use NPN. |
164 return; | 148 return; |
165 } | 149 } |
(...skipping 747 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
913 // headers. | 897 // headers. |
914 bool have_proxy_auth = | 898 bool have_proxy_auth = |
915 ShouldApplyProxyAuth() && | 899 ShouldApplyProxyAuth() && |
916 (HaveAuth(HttpAuth::AUTH_PROXY) || | 900 (HaveAuth(HttpAuth::AUTH_PROXY) || |
917 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY)); | 901 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY)); |
918 bool have_server_auth = | 902 bool have_server_auth = |
919 ShouldApplyServerAuth() && | 903 ShouldApplyServerAuth() && |
920 (HaveAuth(HttpAuth::AUTH_SERVER) || | 904 (HaveAuth(HttpAuth::AUTH_SERVER) || |
921 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER)); | 905 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER)); |
922 | 906 |
923 HttpRequestHeaders request_headers; | 907 std::string authorization_headers; |
924 HttpRequestHeaders authorization_headers; | |
925 | 908 |
926 // TODO(wtc): If BuildAuthorizationHeader fails (returns an authorization | 909 // TODO(wtc): If BuildAuthorizationHeader fails (returns an authorization |
927 // header with no credentials), we should return an error to prevent | 910 // header with no credentials), we should return an error to prevent |
928 // entering an infinite auth restart loop. See http://crbug.com/21050. | 911 // entering an infinite auth restart loop. See http://crbug.com/21050. |
929 if (have_proxy_auth) | 912 if (have_proxy_auth) |
930 AddAuthorizationHeader(HttpAuth::AUTH_PROXY, &authorization_headers); | 913 authorization_headers.append( |
| 914 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY)); |
931 if (have_server_auth) | 915 if (have_server_auth) |
932 AddAuthorizationHeader(HttpAuth::AUTH_SERVER, &authorization_headers); | 916 authorization_headers.append( |
| 917 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER)); |
933 | 918 |
934 if (establishing_tunnel_) { | 919 if (establishing_tunnel_) { |
935 BuildTunnelRequest(request_, authorization_headers, &request_headers); | 920 BuildTunnelRequest(request_, authorization_headers, &request_headers_); |
936 } else { | 921 } else { |
937 BuildRequestHeaders(request_, authorization_headers, request_body, | 922 BuildRequestHeaders(request_, authorization_headers, request_body, |
938 proxy_mode_ == kHTTPProxy, &request_headers); | 923 proxy_mode_ == kHTTPProxy, &request_headers_); |
939 } | 924 } |
940 | |
941 request_headers_ = request_headers.ToString(); | |
942 } | 925 } |
943 | 926 |
944 headers_valid_ = false; | 927 headers_valid_ = false; |
945 http_stream_.reset(new HttpBasicStream(connection_.get(), net_log_)); | 928 http_stream_.reset(new HttpBasicStream(connection_.get(), net_log_)); |
946 | 929 |
947 return http_stream_->SendRequest(request_, request_headers_, | 930 return http_stream_->SendRequest(request_, request_headers_, |
948 request_body, &response_, &io_callback_); | 931 request_body, &response_, &io_callback_); |
949 } | 932 } |
950 | 933 |
951 int HttpNetworkTransaction::DoSendRequestComplete(int result) { | 934 int HttpNetworkTransaction::DoSendRequestComplete(int result) { |
(...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1605 | 1588 |
1606 bool HttpNetworkTransaction::ShouldApplyProxyAuth() const { | 1589 bool HttpNetworkTransaction::ShouldApplyProxyAuth() const { |
1607 return (proxy_mode_ == kHTTPProxy) || establishing_tunnel_; | 1590 return (proxy_mode_ == kHTTPProxy) || establishing_tunnel_; |
1608 } | 1591 } |
1609 | 1592 |
1610 bool HttpNetworkTransaction::ShouldApplyServerAuth() const { | 1593 bool HttpNetworkTransaction::ShouldApplyServerAuth() const { |
1611 return !establishing_tunnel_ && | 1594 return !establishing_tunnel_ && |
1612 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA); | 1595 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA); |
1613 } | 1596 } |
1614 | 1597 |
1615 void HttpNetworkTransaction::AddAuthorizationHeader( | 1598 std::string HttpNetworkTransaction::BuildAuthorizationHeader( |
1616 HttpAuth::Target target, HttpRequestHeaders* authorization_headers) const { | 1599 HttpAuth::Target target) const { |
1617 DCHECK(HaveAuth(target)); | 1600 DCHECK(HaveAuth(target)); |
1618 | 1601 |
1619 // Add a Authorization/Proxy-Authorization header line. | 1602 // Add a Authorization/Proxy-Authorization header line. |
1620 std::string auth_token; | 1603 std::string auth_token; |
1621 int rv = auth_handler_[target]->GenerateAuthToken( | 1604 int rv = auth_handler_[target]->GenerateAuthToken( |
1622 auth_identity_[target].username, | 1605 auth_identity_[target].username, |
1623 auth_identity_[target].password, | 1606 auth_identity_[target].password, |
1624 request_, | 1607 request_, |
1625 &proxy_info_, | 1608 &proxy_info_, |
1626 &auth_token); | 1609 &auth_token); |
1627 if (rv == OK) { | 1610 if (rv == OK) |
1628 authorization_headers->SetHeader( | 1611 return HttpAuth::GetAuthorizationHeaderName(target) + |
1629 HttpAuth::GetAuthorizationHeaderName(target), auth_token); | 1612 ": " + auth_token + "\r\n"; |
1630 } | |
1631 | 1613 |
1632 // TODO(cbentzel): Evict username and password from cache on non-OK return? | 1614 // TODO(cbentzel): Evict username and password from cache on non-OK return? |
1633 // TODO(cbentzel): Never use this scheme again if | 1615 // TODO(cbentzel): Never use this scheme again if |
1634 // ERR_UNSUPPORTED_AUTH_SCHEME is returned. | 1616 // ERR_UNSUPPORTED_AUTH_SCHEME is returned. |
| 1617 return std::string(); |
1635 } | 1618 } |
1636 | 1619 |
1637 GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const { | 1620 GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const { |
1638 return target == HttpAuth::AUTH_PROXY ? | 1621 return target == HttpAuth::AUTH_PROXY ? |
1639 GURL("http://" + proxy_info_.proxy_server().host_and_port()) : | 1622 GURL("http://" + proxy_info_.proxy_server().host_and_port()) : |
1640 request_->url.GetOrigin(); | 1623 request_->url.GetOrigin(); |
1641 } | 1624 } |
1642 | 1625 |
1643 std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target) | 1626 std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target) |
1644 const { | 1627 const { |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1890 http_host_port_pair); | 1873 http_host_port_pair); |
1891 | 1874 |
1892 alternate_protocol_mode_ = kDoNotUseAlternateProtocol; | 1875 alternate_protocol_mode_ = kDoNotUseAlternateProtocol; |
1893 if (connection_->socket()) | 1876 if (connection_->socket()) |
1894 connection_->socket()->Disconnect(); | 1877 connection_->socket()->Disconnect(); |
1895 connection_->Reset(); | 1878 connection_->Reset(); |
1896 next_state_ = STATE_INIT_CONNECTION; | 1879 next_state_ = STATE_INIT_CONNECTION; |
1897 } | 1880 } |
1898 | 1881 |
1899 } // namespace net | 1882 } // namespace net |
OLD | NEW |