Chromium Code Reviews| 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, | |
|
bengr
2014/08/12 20:57:10
If we believe that this will become the dominant i
sclittle
2014/08/12 21:24:43
I'm not certain what the priorities should be. The
| |
| 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 data_reduction_proxy_info->mark_proxies_as_bad = true; | |
|
bengr
2014/08/12 20:57:11
Please add a comment to explain why this gets set
sclittle
2014/08/12 21:24:43
Done.
| |
| 192 data_reduction_proxy_info->bypass_duration = GetDefaultBypassDuration(); | 213 data_reduction_proxy_info->bypass_duration = GetDefaultBypassDuration(); |
| 193 // Fall back if a 500, 502 or 503 is returned. | 214 // Fall back if a 500, 502 or 503 is returned. |
| 194 if (headers->response_code() == net::HTTP_INTERNAL_SERVER_ERROR) | 215 if (headers->response_code() == net::HTTP_INTERNAL_SERVER_ERROR) |
| 195 return BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR; | 216 return BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR; |
| 196 if (headers->response_code() == net::HTTP_BAD_GATEWAY) | 217 if (headers->response_code() == net::HTTP_BAD_GATEWAY) |
| 197 return BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY; | 218 return BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY; |
| 198 if (headers->response_code() == net::HTTP_SERVICE_UNAVAILABLE) | 219 if (headers->response_code() == net::HTTP_SERVICE_UNAVAILABLE) |
| 199 return BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE; | 220 return BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE; |
| 200 // TODO(kundaji): Bypass if Proxy-Authenticate header value cannot be | 221 // TODO(kundaji): Bypass if Proxy-Authenticate header value cannot be |
| 201 // interpreted by data reduction proxy. | 222 // interpreted by data reduction proxy. |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 274 value.begin() + chrome_proxy_fingerprint_prefix.size(), | 295 value.begin() + chrome_proxy_fingerprint_prefix.size(), |
| 275 chrome_proxy_fingerprint_prefix.c_str())) { | 296 chrome_proxy_fingerprint_prefix.c_str())) { |
| 276 continue; | 297 continue; |
| 277 } | 298 } |
| 278 } | 299 } |
| 279 values->push_back(value); | 300 values->push_back(value); |
| 280 } | 301 } |
| 281 } | 302 } |
| 282 | 303 |
| 283 } // namespace data_reduction_proxy | 304 } // namespace data_reduction_proxy |
| OLD | NEW |