OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 <memory> | 7 #include <memory> |
8 #include <set> | 8 #include <set> |
9 #include <utility> | 9 #include <utility> |
10 #include <vector> | 10 #include <vector> |
(...skipping 14 matching lines...) Expand all Loading... | |
25 #include "base/values.h" | 25 #include "base/values.h" |
26 #include "build/build_config.h" | 26 #include "build/build_config.h" |
27 #include "net/base/auth.h" | 27 #include "net/base/auth.h" |
28 #include "net/base/host_port_pair.h" | 28 #include "net/base/host_port_pair.h" |
29 #include "net/base/io_buffer.h" | 29 #include "net/base/io_buffer.h" |
30 #include "net/base/load_flags.h" | 30 #include "net/base/load_flags.h" |
31 #include "net/base/load_timing_info.h" | 31 #include "net/base/load_timing_info.h" |
32 #include "net/base/net_errors.h" | 32 #include "net/base/net_errors.h" |
33 #include "net/base/upload_data_stream.h" | 33 #include "net/base/upload_data_stream.h" |
34 #include "net/base/url_util.h" | 34 #include "net/base/url_util.h" |
35 #include "net/filter/source_stream.h" | |
35 #include "net/http/http_auth.h" | 36 #include "net/http/http_auth.h" |
36 #include "net/http/http_auth_handler.h" | 37 #include "net/http/http_auth_handler.h" |
37 #include "net/http/http_auth_handler_factory.h" | 38 #include "net/http/http_auth_handler_factory.h" |
38 #include "net/http/http_basic_stream.h" | 39 #include "net/http/http_basic_stream.h" |
39 #include "net/http/http_chunked_decoder.h" | 40 #include "net/http/http_chunked_decoder.h" |
40 #include "net/http/http_network_session.h" | 41 #include "net/http/http_network_session.h" |
41 #include "net/http/http_proxy_client_socket.h" | 42 #include "net/http/http_proxy_client_socket.h" |
42 #include "net/http/http_proxy_client_socket_pool.h" | 43 #include "net/http/http_proxy_client_socket_pool.h" |
43 #include "net/http/http_request_headers.h" | 44 #include "net/http/http_request_headers.h" |
44 #include "net/http/http_request_info.h" | 45 #include "net/http/http_request_info.h" |
(...skipping 29 matching lines...) Expand all Loading... | |
74 std::unique_ptr<base::Value> NetLogSSLCipherFallbackCallback( | 75 std::unique_ptr<base::Value> NetLogSSLCipherFallbackCallback( |
75 const GURL* url, | 76 const GURL* url, |
76 int net_error, | 77 int net_error, |
77 NetLogCaptureMode /* capture_mode */) { | 78 NetLogCaptureMode /* capture_mode */) { |
78 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 79 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
79 dict->SetString("host_and_port", GetHostAndPort(*url)); | 80 dict->SetString("host_and_port", GetHostAndPort(*url)); |
80 dict->SetInteger("net_error", net_error); | 81 dict->SetInteger("net_error", net_error); |
81 return std::move(dict); | 82 return std::move(dict); |
82 } | 83 } |
83 | 84 |
85 enum QualityParsingState { | |
86 BEFORE_QUALIFIER, // waiting for ";" | |
87 QUALIFIER, // waiting for "q" | |
88 EQUALS, // waiting for "=" | |
89 ZERO_OR_ONE, // waiting for "0" or "1" | |
90 PERIOD, // waiting for "." | |
91 DECIMALS, | |
92 DONE | |
93 }; | |
94 | |
95 // Tests is specified encoding is allowed by the given "Accept-Encoding" header. | |
96 // It is expected that header value is somewhat well-formatted (according to the | |
97 // RFC2616), and no "content-coding" is a prefix of another "content-coding". | |
98 bool IsAcceptableEncoding(const std::string& accept_encoding, | |
99 const std::string& encoding) { | |
100 size_t cursor = accept_encoding.find(encoding); | |
101 char c; | |
102 | |
103 // Encoding is not mentioned. | |
104 if (cursor == std::string::npos) | |
105 return false; | |
Randy Smith (Not in Mondays)
2017/03/16 17:50:44
Put a note in here about explicitly not worrying a
eustas
2017/03/20 13:05:18
This code is gone.
| |
106 | |
107 // Check that match position is not in the middle of another entry. | |
108 if (cursor != 0) { | |
109 c = accept_encoding[cursor - 1]; | |
110 if ((c != ' ') && (c != ',')) | |
Randy Smith (Not in Mondays)
2017/03/16 17:50:44
Do we need to check other whitespace? (Tab specif
eustas
2017/03/20 13:05:18
In new code whitespace is trimmed around all token
| |
111 return false; | |
112 } | |
113 cursor += encoding.size(); | |
114 | |
115 QualityParsingState state = BEFORE_QUALIFIER; | |
116 int ones = 0; | |
117 int sum = 0; | |
118 int digits = 0; | |
119 | |
120 for (; cursor < accept_encoding.size(); ++cursor) { | |
121 c = accept_encoding[cursor]; | |
122 switch (state) { | |
123 case BEFORE_QUALIFIER: | |
124 if (c == ' ') | |
125 break; | |
126 if (c == ',') | |
127 return true; | |
128 if (c == ';') { | |
129 state = QUALIFIER; | |
130 break; | |
131 } | |
132 return false; | |
133 | |
134 case QUALIFIER: | |
135 if (c == ' ') | |
136 break; | |
137 if (c == 'q' || c == 'Q') { | |
138 state = EQUALS; | |
139 break; | |
140 } | |
141 return false; | |
142 | |
143 case EQUALS: | |
144 if (c == '=') { | |
145 state = ZERO_OR_ONE; | |
146 break; | |
147 } | |
148 return false; | |
149 | |
150 case ZERO_OR_ONE: | |
151 if (c == '0' || c == '1') { | |
152 ones = c - '0'; | |
153 state = PERIOD; | |
154 break; | |
155 } | |
156 return false; | |
157 | |
158 case PERIOD: | |
159 if (c == '.') { | |
160 state = DECIMALS; | |
161 break; | |
162 } | |
163 return false; | |
Randy Smith (Not in Mondays)
2017/03/16 17:50:44
Is the thought that q=1 will never happen? I'd so
eustas
2017/03/20 13:05:18
Ooops. Fixed it,... and then rewritten it to a mor
| |
164 | |
165 case DECIMALS: | |
166 if (c == ',' || c == ' ') { | |
167 state = DONE; | |
168 break; | |
169 } | |
170 if (c >= '0' && c <= '9') { | |
171 sum += c - '0'; | |
172 digits++; | |
173 break; | |
174 } | |
175 return false; | |
176 | |
177 case DONE: | |
178 // assert(0) | |
179 break; | |
180 } | |
181 if (state == DONE) | |
182 break; | |
183 } | |
184 | |
185 // Before "q". | |
186 if (state == BEFORE_QUALIFIER) | |
187 return true; | |
188 | |
189 // Before value. | |
190 if (state == QUALIFIER || state == EQUALS || state == ZERO_OR_ONE) | |
191 return false; | |
192 | |
193 // assert(state == PERIOD || state == DECIMALS || state == DONE | |
Randy Smith (Not in Mondays)
2017/03/16 17:50:44
Why not make this a DCHECK and remove the comments
eustas
2017/03/20 13:05:18
Acknowledged.
| |
194 // Some value is read. | |
195 | |
196 if (digits > 3) | |
197 return false; | |
198 | |
199 if (ones == 0) | |
200 return (sum != 0); | |
201 | |
202 // Reject values like "1.x", where x != 0 | |
203 return (sum == 0); | |
204 } | |
205 | |
84 } // namespace | 206 } // namespace |
85 | 207 |
86 //----------------------------------------------------------------------------- | 208 //----------------------------------------------------------------------------- |
87 | 209 |
88 HttpNetworkTransaction::HttpNetworkTransaction(RequestPriority priority, | 210 HttpNetworkTransaction::HttpNetworkTransaction(RequestPriority priority, |
89 HttpNetworkSession* session) | 211 HttpNetworkSession* session) |
90 : pending_auth_target_(HttpAuth::AUTH_NONE), | 212 : pending_auth_target_(HttpAuth::AUTH_NONE), |
91 io_callback_(base::Bind(&HttpNetworkTransaction::OnIOComplete, | 213 io_callback_(base::Bind(&HttpNetworkTransaction::OnIOComplete, |
92 base::Unretained(this))), | 214 base::Unretained(this))), |
93 session_(session), | 215 session_(session), |
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
538 const HttpResponseInfo& proxy_response, | 660 const HttpResponseInfo& proxy_response, |
539 const SSLConfig& used_ssl_config, | 661 const SSLConfig& used_ssl_config, |
540 const ProxyInfo& used_proxy_info, | 662 const ProxyInfo& used_proxy_info, |
541 HttpAuthController* auth_controller) { | 663 HttpAuthController* auth_controller) { |
542 DCHECK(stream_request_.get()); | 664 DCHECK(stream_request_.get()); |
543 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); | 665 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); |
544 | 666 |
545 establishing_tunnel_ = true; | 667 establishing_tunnel_ = true; |
546 response_.headers = proxy_response.headers; | 668 response_.headers = proxy_response.headers; |
547 response_.auth_challenge = proxy_response.auth_challenge; | 669 response_.auth_challenge = proxy_response.auth_challenge; |
670 | |
671 if (response_.headers.get() && !ContentEncodingsValid()) { | |
672 UMA_HISTOGRAM_ENUMERATION("Net.ContentDecodingFailed2.FilterType", | |
673 SourceStream::TYPE_UNKNOWN, | |
674 SourceStream::TYPE_MAX); | |
675 return ERR_CONTENT_DECODING_FAILED; | |
676 } | |
677 | |
548 headers_valid_ = true; | 678 headers_valid_ = true; |
549 server_ssl_config_ = used_ssl_config; | 679 server_ssl_config_ = used_ssl_config; |
550 proxy_info_ = used_proxy_info; | 680 proxy_info_ = used_proxy_info; |
551 | 681 |
552 auth_controllers_[HttpAuth::AUTH_PROXY] = auth_controller; | 682 auth_controllers_[HttpAuth::AUTH_PROXY] = auth_controller; |
553 pending_auth_target_ = HttpAuth::AUTH_PROXY; | 683 pending_auth_target_ = HttpAuth::AUTH_PROXY; |
554 | 684 |
555 DoCallback(OK); | 685 DoCallback(OK); |
556 } | 686 } |
557 | 687 |
(...skipping 681 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1239 // bizarre for SPDY. Assuming this logic is useful at all. | 1369 // bizarre for SPDY. Assuming this logic is useful at all. |
1240 // TODO(davidben): Bubble the error code up so we do not cache? | 1370 // TODO(davidben): Bubble the error code up so we do not cache? |
1241 if (result == ERR_CONNECTION_CLOSED && response_.headers.get()) | 1371 if (result == ERR_CONNECTION_CLOSED && response_.headers.get()) |
1242 result = OK; | 1372 result = OK; |
1243 | 1373 |
1244 if (result < 0) | 1374 if (result < 0) |
1245 return HandleIOError(result); | 1375 return HandleIOError(result); |
1246 | 1376 |
1247 DCHECK(response_.headers.get()); | 1377 DCHECK(response_.headers.get()); |
1248 | 1378 |
1379 if (response_.headers.get() && !ContentEncodingsValid()) { | |
1380 UMA_HISTOGRAM_ENUMERATION("Net.ContentDecodingFailed2.FilterType", | |
1381 SourceStream::TYPE_UNKNOWN, | |
1382 SourceStream::TYPE_MAX); | |
1383 return ERR_CONTENT_DECODING_FAILED; | |
1384 } | |
1385 | |
1249 // On a 408 response from the server ("Request Timeout") on a stale socket, | 1386 // On a 408 response from the server ("Request Timeout") on a stale socket, |
1250 // retry the request. | 1387 // retry the request. |
1251 // Headers can be NULL because of http://crbug.com/384554. | 1388 // Headers can be NULL because of http://crbug.com/384554. |
1252 if (response_.headers.get() && response_.headers->response_code() == 408 && | 1389 if (response_.headers.get() && response_.headers->response_code() == 408 && |
1253 stream_->IsConnectionReused()) { | 1390 stream_->IsConnectionReused()) { |
1254 net_log_.AddEventWithNetErrorCode( | 1391 net_log_.AddEventWithNetErrorCode( |
1255 NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR, | 1392 NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR, |
1256 response_.headers->response_code()); | 1393 response_.headers->response_code()); |
1257 // This will close the socket - it would be weird to try and reuse it, even | 1394 // This will close the socket - it would be weird to try and reuse it, even |
1258 // if the server doesn't actually close it. | 1395 // if the server doesn't actually close it. |
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1704 void HttpNetworkTransaction::CopyConnectionAttemptsFromStreamRequest() { | 1841 void HttpNetworkTransaction::CopyConnectionAttemptsFromStreamRequest() { |
1705 DCHECK(stream_request_); | 1842 DCHECK(stream_request_); |
1706 | 1843 |
1707 // Since the transaction can restart with auth credentials, it may create a | 1844 // Since the transaction can restart with auth credentials, it may create a |
1708 // stream more than once. Accumulate all of the connection attempts across | 1845 // stream more than once. Accumulate all of the connection attempts across |
1709 // those streams by appending them to the vector: | 1846 // those streams by appending them to the vector: |
1710 for (const auto& attempt : stream_request_->connection_attempts()) | 1847 for (const auto& attempt : stream_request_->connection_attempts()) |
1711 connection_attempts_.push_back(attempt); | 1848 connection_attempts_.push_back(attempt); |
1712 } | 1849 } |
1713 | 1850 |
1851 bool HttpNetworkTransaction::ContentEncodingsValid() const { | |
1852 HttpResponseHeaders* headers = GetResponseHeaders(); | |
1853 DCHECK(headers); | |
1854 | |
1855 // It is OK, if both "Accept-Encoding" and "Content-Encoding" headers are | |
1856 // missing. It is a widely used setup in unit-tests. | |
Randy Smith (Not in Mondays)
2017/03/16 17:50:44
Suggestion: Move this comment down to above the "r
eustas
2017/03/20 13:05:18
Replaced with set-matching code, so now it is more
| |
1857 std::string accept_encoding; | |
1858 request_headers_.GetHeader(HttpRequestHeaders::kAcceptEncoding, | |
1859 &accept_encoding); | |
1860 | |
1861 std::string encoding; | |
1862 size_t iter = 0; | |
1863 while (headers->EnumerateHeader(&iter, "Content-Encoding", &encoding)) { | |
1864 if (accept_encoding.empty()) | |
1865 return false; | |
1866 | |
1867 encoding = base::ToLowerASCII(encoding); | |
1868 // RFC2616 Section 3.5 recommendation: applications SHOULD consider "x-gzip" | |
1869 // and "x-compress" to be equivalent to "gzip" and "compress" respectively. | |
1870 if (encoding.compare("x-gzip") == 0) | |
1871 encoding = "gzip"; | |
1872 if (encoding.compare("x-compress") == 0) | |
1873 encoding = "compress"; | |
Randy Smith (Not in Mondays)
2017/03/16 17:50:44
Do we need to worry about these cases in the Accep
eustas
2017/03/20 13:05:18
Made it symmetric in new parser.
| |
1874 | |
1875 // Reject malformed encodings. | |
1876 if (encoding.find_first_of("=;, ") != std::string::npos) | |
1877 return false; | |
1878 | |
1879 if (!IsAcceptableEncoding(accept_encoding, encoding)) | |
1880 return false; | |
1881 } | |
1882 return true; | |
1883 } | |
1884 | |
1714 } // namespace net | 1885 } // namespace net |
OLD | NEW |