OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "components/data_reduction_proxy/common/data_reduction_proxy_headers.h" | 5 #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/rand_util.h" | 10 #include "base/rand_util.h" |
11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
12 #include "base/strings/string_piece.h" | 12 #include "base/strings/string_piece.h" |
13 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
15 #include "net/http/http_response_headers.h" | 15 #include "net/http/http_response_headers.h" |
16 #include "net/http/http_status_code.h" | 16 #include "net/http/http_status_code.h" |
17 | 17 |
18 using base::StringPiece; | 18 using base::StringPiece; |
19 using base::TimeDelta; | 19 using base::TimeDelta; |
20 | 20 |
21 namespace { | 21 namespace { |
22 | 22 |
23 const char kChromeProxyHeader[] = "chrome-proxy"; | 23 const char kChromeProxyHeader[] = "chrome-proxy"; |
24 const char kActionValueDelimiter = '='; | 24 const char kActionValueDelimiter = '='; |
25 | 25 |
| 26 const char kChromeProxyActionBlockOnce[] = "block-once"; |
26 const char kChromeProxyActionBlock[] = "block"; | 27 const char kChromeProxyActionBlock[] = "block"; |
27 const char kChromeProxyActionBypass[] = "bypass"; | 28 const char kChromeProxyActionBypass[] = "bypass"; |
28 | 29 |
29 // Actions for tamper detection fingerprints. | 30 // Actions for tamper detection fingerprints. |
30 const char kChromeProxyActionFingerprintChromeProxy[] = "fcp"; | 31 const char kChromeProxyActionFingerprintChromeProxy[] = "fcp"; |
31 const char kChromeProxyActionFingerprintVia[] = "fvia"; | 32 const char kChromeProxyActionFingerprintVia[] = "fvia"; |
32 const char kChromeProxyActionFingerprintOtherHeaders[] = "foh"; | 33 const char kChromeProxyActionFingerprintOtherHeaders[] = "foh"; |
33 const char kChromeProxyActionFingerprintContentLength[] = "fcl"; | 34 const char kChromeProxyActionFingerprintContentLength[] = "fcl"; |
34 | 35 |
35 const int kShortBypassMaxSeconds = 59; | 36 const int kShortBypassMaxSeconds = 59; |
36 const int kMediumBypassMaxSeconds = 300; | 37 const int kMediumBypassMaxSeconds = 300; |
37 | 38 |
38 // Returns a random bypass duration between 1 and 5 minutes. | 39 // Returns a random bypass duration between 1 and 5 minutes. |
39 base::TimeDelta GetDefaultBypassDuration() { | 40 base::TimeDelta GetDefaultBypassDuration() { |
40 const int64 delta_ms = | 41 const int64 delta_ms = |
41 base::RandInt(base::TimeDelta::FromMinutes(1).InMilliseconds(), | 42 base::RandInt(base::TimeDelta::FromMinutes(1).InMilliseconds(), |
42 base::TimeDelta::FromMinutes(5).InMilliseconds()); | 43 base::TimeDelta::FromMinutes(5).InMilliseconds()); |
43 return TimeDelta::FromMilliseconds(delta_ms); | 44 return TimeDelta::FromMilliseconds(delta_ms); |
44 } | 45 } |
| 46 |
45 } // namespace | 47 } // namespace |
46 | 48 |
47 namespace data_reduction_proxy { | 49 namespace data_reduction_proxy { |
48 | 50 |
49 bool GetDataReductionProxyActionValue( | 51 bool GetDataReductionProxyActionValue( |
50 const net::HttpResponseHeaders* headers, | 52 const net::HttpResponseHeaders* headers, |
51 const std::string& action_prefix, | 53 const std::string& action_prefix, |
52 std::string* action_value) { | 54 std::string* action_value) { |
53 DCHECK(headers); | 55 DCHECK(headers); |
54 DCHECK(!action_prefix.empty()); | 56 DCHECK(!action_prefix.empty()); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 return true; | 106 return true; |
105 } | 107 } |
106 } | 108 } |
107 } | 109 } |
108 return false; | 110 return false; |
109 } | 111 } |
110 | 112 |
111 bool ParseHeadersAndSetProxyInfo(const net::HttpResponseHeaders* headers, | 113 bool ParseHeadersAndSetProxyInfo(const net::HttpResponseHeaders* headers, |
112 DataReductionProxyInfo* proxy_info) { | 114 DataReductionProxyInfo* proxy_info) { |
113 DCHECK(proxy_info); | 115 DCHECK(proxy_info); |
114 proxy_info->bypass_all = false; | 116 |
115 // Support header of the form Chrome-Proxy: bypass|block=<duration>, where | 117 // Support header of the form Chrome-Proxy: bypass|block=<duration>, where |
116 // <duration> is the number of seconds to wait before retrying | 118 // <duration> is the number of seconds to wait before retrying |
117 // the proxy. If the duration is 0, then the default proxy retry delay | 119 // the proxy. If the duration is 0, then the default proxy retry delay |
118 // (specified in |ProxyList::UpdateRetryInfoOnFallback|) will be used. | 120 // (specified in |ProxyList::UpdateRetryInfoOnFallback|) will be used. |
119 // 'bypass' instructs Chrome to bypass the currently connected data reduction | 121 // 'bypass' instructs Chrome to bypass the currently connected data reduction |
120 // proxy, whereas 'block' instructs Chrome to bypass all available data | 122 // proxy, whereas 'block' instructs Chrome to bypass all available data |
121 // reduction proxies. | 123 // reduction proxies. |
122 | 124 |
123 // 'block' takes precedence over 'bypass', so look for it first. | 125 // 'block' takes precedence over 'bypass' and 'block-once', so look for it |
| 126 // first. |
124 // TODO(bengr): Reduce checks for 'block' and 'bypass' to a single loop. | 127 // TODO(bengr): Reduce checks for 'block' and 'bypass' to a single loop. |
125 if (ParseHeadersAndSetBypassDuration( | 128 if (ParseHeadersAndSetBypassDuration( |
126 headers, kChromeProxyActionBlock, &proxy_info->bypass_duration)) { | 129 headers, kChromeProxyActionBlock, &proxy_info->bypass_duration)) { |
127 proxy_info->bypass_all = true; | 130 proxy_info->bypass_all = true; |
| 131 proxy_info->mark_proxies_as_bad = true; |
128 return true; | 132 return true; |
129 } | 133 } |
130 | 134 |
131 // Next, look for 'bypass'. | 135 // Next, look for 'bypass'. |
132 if (ParseHeadersAndSetBypassDuration( | 136 if (ParseHeadersAndSetBypassDuration( |
133 headers, kChromeProxyActionBypass, &proxy_info->bypass_duration)) { | 137 headers, kChromeProxyActionBypass, &proxy_info->bypass_duration)) { |
| 138 proxy_info->bypass_all = false; |
| 139 proxy_info->mark_proxies_as_bad = true; |
134 return true; | 140 return true; |
135 } | 141 } |
| 142 |
| 143 // Lastly, look for 'block-once'. 'block-once' instructs Chrome to retry the |
| 144 // current request (if it's idempotent), bypassing all available data |
| 145 // reduction proxies. Unlike 'block', 'block-once' does not cause data |
| 146 // reduction proxies to be bypassed for an extended period of time; |
| 147 // 'block-once' only affects the retry of the current request. |
| 148 if (headers->HasHeaderValue(kChromeProxyHeader, |
| 149 kChromeProxyActionBlockOnce)) { |
| 150 proxy_info->bypass_all = true; |
| 151 proxy_info->mark_proxies_as_bad = false; |
| 152 proxy_info->bypass_duration = TimeDelta(); |
| 153 return true; |
| 154 } |
| 155 |
136 return false; | 156 return false; |
137 } | 157 } |
138 | 158 |
139 bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers, | 159 bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers, |
140 bool* has_intermediary) { | 160 bool* has_intermediary) { |
141 const size_t kVersionSize = 4; | 161 const size_t kVersionSize = 4; |
142 const char kDataReductionProxyViaValue[] = "Chrome-Compression-Proxy"; | 162 const char kDataReductionProxyViaValue[] = "Chrome-Compression-Proxy"; |
143 size_t value_len = strlen(kDataReductionProxyViaValue); | 163 size_t value_len = strlen(kDataReductionProxyViaValue); |
144 void* iter = NULL; | 164 void* iter = NULL; |
145 std::string value; | 165 std::string value; |
(...skipping 26 matching lines...) Expand all Loading... |
172 return false; | 192 return false; |
173 } | 193 } |
174 | 194 |
175 DataReductionProxyBypassType GetDataReductionProxyBypassType( | 195 DataReductionProxyBypassType GetDataReductionProxyBypassType( |
176 const net::HttpResponseHeaders* headers, | 196 const net::HttpResponseHeaders* headers, |
177 DataReductionProxyInfo* data_reduction_proxy_info) { | 197 DataReductionProxyInfo* data_reduction_proxy_info) { |
178 DCHECK(data_reduction_proxy_info); | 198 DCHECK(data_reduction_proxy_info); |
179 if (ParseHeadersAndSetProxyInfo(headers, data_reduction_proxy_info)) { | 199 if (ParseHeadersAndSetProxyInfo(headers, data_reduction_proxy_info)) { |
180 // A chrome-proxy response header is only present in a 502. For proper | 200 // A chrome-proxy response header is only present in a 502. For proper |
181 // reporting, this check must come before the 5xx checks below. | 201 // reporting, this check must come before the 5xx checks below. |
| 202 if (!data_reduction_proxy_info->mark_proxies_as_bad) |
| 203 return BYPASS_EVENT_TYPE_CURRENT; |
| 204 |
182 const TimeDelta& duration = data_reduction_proxy_info->bypass_duration; | 205 const TimeDelta& duration = data_reduction_proxy_info->bypass_duration; |
183 // bypass=0 means bypass for a random duration between 1 to 5 minutes | |
184 if (duration == TimeDelta()) | |
185 return BYPASS_EVENT_TYPE_MEDIUM; | |
186 if (duration <= TimeDelta::FromSeconds(kShortBypassMaxSeconds)) | 206 if (duration <= TimeDelta::FromSeconds(kShortBypassMaxSeconds)) |
187 return BYPASS_EVENT_TYPE_SHORT; | 207 return BYPASS_EVENT_TYPE_SHORT; |
188 if (duration <= TimeDelta::FromSeconds(kMediumBypassMaxSeconds)) | 208 if (duration <= TimeDelta::FromSeconds(kMediumBypassMaxSeconds)) |
189 return BYPASS_EVENT_TYPE_MEDIUM; | 209 return BYPASS_EVENT_TYPE_MEDIUM; |
190 return BYPASS_EVENT_TYPE_LONG; | 210 return BYPASS_EVENT_TYPE_LONG; |
191 } | 211 } |
| 212 |
| 213 // If a bypass is triggered by any of the following cases, then the data |
| 214 // reduction proxy should be bypassed for a random duration between 1 and 5 |
| 215 // minutes. |
| 216 data_reduction_proxy_info->mark_proxies_as_bad = true; |
192 data_reduction_proxy_info->bypass_duration = GetDefaultBypassDuration(); | 217 data_reduction_proxy_info->bypass_duration = GetDefaultBypassDuration(); |
| 218 |
193 // Fall back if a 500, 502 or 503 is returned. | 219 // Fall back if a 500, 502 or 503 is returned. |
194 if (headers->response_code() == net::HTTP_INTERNAL_SERVER_ERROR) | 220 if (headers->response_code() == net::HTTP_INTERNAL_SERVER_ERROR) |
195 return BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR; | 221 return BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR; |
196 if (headers->response_code() == net::HTTP_BAD_GATEWAY) | 222 if (headers->response_code() == net::HTTP_BAD_GATEWAY) |
197 return BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY; | 223 return BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY; |
198 if (headers->response_code() == net::HTTP_SERVICE_UNAVAILABLE) | 224 if (headers->response_code() == net::HTTP_SERVICE_UNAVAILABLE) |
199 return BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE; | 225 return BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE; |
200 // TODO(kundaji): Bypass if Proxy-Authenticate header value cannot be | 226 // TODO(kundaji): Bypass if Proxy-Authenticate header value cannot be |
201 // interpreted by data reduction proxy. | 227 // interpreted by data reduction proxy. |
202 if (headers->response_code() == net::HTTP_PROXY_AUTHENTICATION_REQUIRED && | 228 if (headers->response_code() == net::HTTP_PROXY_AUTHENTICATION_REQUIRED && |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 value.begin() + chrome_proxy_fingerprint_prefix.size(), | 300 value.begin() + chrome_proxy_fingerprint_prefix.size(), |
275 chrome_proxy_fingerprint_prefix.c_str())) { | 301 chrome_proxy_fingerprint_prefix.c_str())) { |
276 continue; | 302 continue; |
277 } | 303 } |
278 } | 304 } |
279 values->push_back(value); | 305 values->push_back(value); |
280 } | 306 } |
281 } | 307 } |
282 | 308 |
283 } // namespace data_reduction_proxy | 309 } // namespace data_reduction_proxy |
OLD | NEW |