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/core/common/data_reduction_proxy_heade rs.h" | 5 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_heade rs.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <string> | 10 #include <string> |
| 11 #include <utility> | 11 #include <utility> |
| 12 #include <vector> | 12 #include <vector> |
| 13 | 13 |
| 14 #include "base/rand_util.h" | 14 #include "base/rand_util.h" |
| 15 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
| 16 #include "base/strings/string_split.h" | 16 #include "base/strings/string_split.h" |
| 17 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
| 18 #include "base/time/time.h" | 18 #include "base/time/time.h" |
| 19 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event _creator.h" | 19 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event _creator.h" |
| 20 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_param s.h" | 20 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_param s.h" |
| 21 #include "net/http/http_response_headers.h" | 21 #include "net/http/http_response_headers.h" |
| 22 #include "net/http/http_status_code.h" | 22 #include "net/http/http_status_code.h" |
| 23 #include "net/url_request/url_request.h" | |
| 23 | 24 |
| 24 using base::StringPiece; | 25 using base::StringPiece; |
| 25 using base::TimeDelta; | 26 using base::TimeDelta; |
| 26 | 27 |
| 27 namespace { | 28 namespace { |
| 28 | 29 |
| 29 const char kChromeProxyHeader[] = "chrome-proxy"; | 30 const char kChromeProxyHeader[] = "chrome-proxy"; |
| 30 const char kChromeProxyECTHeader[] = "chrome-proxy-ect"; | 31 const char kChromeProxyECTHeader[] = "chrome-proxy-ect"; |
| 31 const char kChromeProxyAcceptTransformHeader[] = | 32 const char kChromeProxyAcceptTransformHeader[] = |
| 32 "chrome-proxy-accept-transform"; | 33 "chrome-proxy-accept-transform"; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 99 const std::string& transform_type) { | 100 const std::string& transform_type) { |
| 100 std::string header_value; | 101 std::string header_value; |
| 101 if (!headers.GetNormalizedHeader( | 102 if (!headers.GetNormalizedHeader( |
| 102 data_reduction_proxy::chrome_proxy_content_transform_header(), | 103 data_reduction_proxy::chrome_proxy_content_transform_header(), |
| 103 &header_value)) { | 104 &header_value)) { |
| 104 return false; | 105 return false; |
| 105 } | 106 } |
| 106 return IsPreviewTypeInHeaderValue(header_value, transform_type); | 107 return IsPreviewTypeInHeaderValue(header_value, transform_type); |
| 107 } | 108 } |
| 108 | 109 |
| 110 // Returns true if there is a cycle in |url_chain|. | |
| 111 bool HasURLRedirectCycle(const std::vector<GURL>& url_chain) { | |
| 112 if (url_chain.size() <= 1) | |
| 113 return false; | |
| 114 | |
| 115 // If the last entry occurs more than once, then very likely there is a | |
| 116 // redirect cycle. | |
| 117 GURL last_entry = url_chain.back(); | |
| 118 size_t last_entry_number_occurences = 0; | |
| 119 | |
| 120 for (const auto& url : url_chain) { | |
| 121 if (url == last_entry) { | |
| 122 last_entry_number_occurences++; | |
| 123 if (last_entry_number_occurences >= 2) | |
|
RyanSturm
2017/03/28 18:03:19
This looks confusing with the >=2 condition. Since
tbansal1
2017/03/28 19:59:48
Done.
| |
| 124 return true; | |
| 125 } | |
| 126 } | |
| 127 return false; | |
| 128 } | |
| 129 | |
| 109 } // namespace | 130 } // namespace |
| 110 | 131 |
| 111 namespace data_reduction_proxy { | 132 namespace data_reduction_proxy { |
| 112 | 133 |
| 113 const char* chrome_proxy_header() { | 134 const char* chrome_proxy_header() { |
| 114 return kChromeProxyHeader; | 135 return kChromeProxyHeader; |
| 115 } | 136 } |
| 116 | 137 |
| 117 const char* chrome_proxy_ect_header() { | 138 const char* chrome_proxy_ect_header() { |
| 118 return kChromeProxyECTHeader; | 139 return kChromeProxyECTHeader; |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 276 // the data reduction proxy's Via header. | 297 // the data reduction proxy's Via header. |
| 277 *has_intermediary = !(headers->EnumerateHeader(&iter, "via", &value)); | 298 *has_intermediary = !(headers->EnumerateHeader(&iter, "via", &value)); |
| 278 return true; | 299 return true; |
| 279 } | 300 } |
| 280 } | 301 } |
| 281 | 302 |
| 282 return false; | 303 return false; |
| 283 } | 304 } |
| 284 | 305 |
| 285 DataReductionProxyBypassType GetDataReductionProxyBypassType( | 306 DataReductionProxyBypassType GetDataReductionProxyBypassType( |
| 286 const net::HttpResponseHeaders* headers, | 307 const std::vector<GURL>& url_chain, |
| 308 const net::HttpResponseHeaders& headers, | |
| 287 DataReductionProxyInfo* data_reduction_proxy_info) { | 309 DataReductionProxyInfo* data_reduction_proxy_info) { |
| 288 DCHECK(data_reduction_proxy_info); | 310 DCHECK(data_reduction_proxy_info); |
| 289 if (ParseHeadersForBypassInfo(headers, data_reduction_proxy_info)) { | 311 |
| 312 bool has_via_header = HasDataReductionProxyViaHeader(&headers, nullptr); | |
|
RyanSturm
2017/03/28 18:03:19
Any chance you want to change HasDataReductionProx
tbansal1
2017/03/28 19:59:48
I was planning to do it in a separate CL, but I ha
| |
| 313 | |
| 314 if (has_via_header && HasURLRedirectCycle(url_chain)) { | |
| 315 data_reduction_proxy_info->bypass_all = true; | |
| 316 data_reduction_proxy_info->mark_proxies_as_bad = false; | |
| 317 data_reduction_proxy_info->bypass_duration = base::TimeDelta(); | |
| 318 data_reduction_proxy_info->bypass_action = BYPASS_ACTION_TYPE_BLOCK_ONCE; | |
| 319 return BYPASS_EVENT_TYPE_URL_REDIRECT_CYCLE; | |
| 320 } | |
| 321 | |
| 322 if (ParseHeadersForBypassInfo(&headers, data_reduction_proxy_info)) { | |
| 290 // A chrome-proxy response header is only present in a 502. For proper | 323 // A chrome-proxy response header is only present in a 502. For proper |
| 291 // reporting, this check must come before the 5xx checks below. | 324 // reporting, this check must come before the 5xx checks below. |
| 292 if (!data_reduction_proxy_info->mark_proxies_as_bad) | 325 if (!data_reduction_proxy_info->mark_proxies_as_bad) |
| 293 return BYPASS_EVENT_TYPE_CURRENT; | 326 return BYPASS_EVENT_TYPE_CURRENT; |
| 294 | 327 |
| 295 const TimeDelta& duration = data_reduction_proxy_info->bypass_duration; | 328 const TimeDelta& duration = data_reduction_proxy_info->bypass_duration; |
| 296 if (duration <= TimeDelta::FromSeconds(kShortBypassMaxSeconds)) | 329 if (duration <= TimeDelta::FromSeconds(kShortBypassMaxSeconds)) |
| 297 return BYPASS_EVENT_TYPE_SHORT; | 330 return BYPASS_EVENT_TYPE_SHORT; |
| 298 if (duration <= TimeDelta::FromSeconds(kMediumBypassMaxSeconds)) | 331 if (duration <= TimeDelta::FromSeconds(kMediumBypassMaxSeconds)) |
| 299 return BYPASS_EVENT_TYPE_MEDIUM; | 332 return BYPASS_EVENT_TYPE_MEDIUM; |
| 300 return BYPASS_EVENT_TYPE_LONG; | 333 return BYPASS_EVENT_TYPE_LONG; |
| 301 } | 334 } |
| 302 | 335 |
| 303 // If a bypass is triggered by any of the following cases, then the data | 336 // If a bypass is triggered by any of the following cases, then the data |
| 304 // reduction proxy should be bypassed for a random duration between 1 and 5 | 337 // reduction proxy should be bypassed for a random duration between 1 and 5 |
| 305 // minutes. | 338 // minutes. |
| 306 data_reduction_proxy_info->mark_proxies_as_bad = true; | 339 data_reduction_proxy_info->mark_proxies_as_bad = true; |
| 307 data_reduction_proxy_info->bypass_duration = GetDefaultBypassDuration(); | 340 data_reduction_proxy_info->bypass_duration = GetDefaultBypassDuration(); |
| 308 | 341 |
| 309 // Fall back if a 500, 502 or 503 is returned. | 342 // Fall back if a 500, 502 or 503 is returned. |
| 310 if (headers->response_code() == net::HTTP_INTERNAL_SERVER_ERROR) | 343 if (headers.response_code() == net::HTTP_INTERNAL_SERVER_ERROR) |
| 311 return BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR; | 344 return BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR; |
| 312 if (headers->response_code() == net::HTTP_BAD_GATEWAY) | 345 if (headers.response_code() == net::HTTP_BAD_GATEWAY) |
| 313 return BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY; | 346 return BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY; |
| 314 if (headers->response_code() == net::HTTP_SERVICE_UNAVAILABLE) | 347 if (headers.response_code() == net::HTTP_SERVICE_UNAVAILABLE) |
| 315 return BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE; | 348 return BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE; |
| 316 // TODO(kundaji): Bypass if Proxy-Authenticate header value cannot be | 349 // TODO(kundaji): Bypass if Proxy-Authenticate header value cannot be |
| 317 // interpreted by data reduction proxy. | 350 // interpreted by data reduction proxy. |
| 318 if (headers->response_code() == net::HTTP_PROXY_AUTHENTICATION_REQUIRED && | 351 if (headers.response_code() == net::HTTP_PROXY_AUTHENTICATION_REQUIRED && |
| 319 !headers->HasHeader("Proxy-Authenticate")) { | 352 !headers.HasHeader("Proxy-Authenticate")) { |
| 320 return BYPASS_EVENT_TYPE_MALFORMED_407; | 353 return BYPASS_EVENT_TYPE_MALFORMED_407; |
| 321 } | 354 } |
| 322 if (!HasDataReductionProxyViaHeader(headers, NULL) && | 355 if (!has_via_header && (headers.response_code() != net::HTTP_NOT_MODIFIED)) { |
| 323 (headers->response_code() != net::HTTP_NOT_MODIFIED)) { | |
| 324 // A Via header might not be present in a 304. Since the goal of a 304 | 356 // A Via header might not be present in a 304. Since the goal of a 304 |
| 325 // response is to minimize information transfer, a sender in general | 357 // response is to minimize information transfer, a sender in general |
| 326 // should not generate representation metadata other than Cache-Control, | 358 // should not generate representation metadata other than Cache-Control, |
| 327 // Content-Location, Date, ETag, Expires, and Vary. | 359 // Content-Location, Date, ETag, Expires, and Vary. |
| 328 | 360 |
| 329 // The proxy Via header might also not be present in a 4xx response. | 361 // The proxy Via header might also not be present in a 4xx response. |
| 330 // Separate this case from other responses that are missing the header. | 362 // Separate this case from other responses that are missing the header. |
| 331 if (headers->response_code() >= net::HTTP_BAD_REQUEST && | 363 if (headers.response_code() >= net::HTTP_BAD_REQUEST && |
| 332 headers->response_code() < net::HTTP_INTERNAL_SERVER_ERROR) { | 364 headers.response_code() < net::HTTP_INTERNAL_SERVER_ERROR) { |
| 333 // At this point, any 4xx response that is missing the via header | 365 // At this point, any 4xx response that is missing the via header |
| 334 // indicates an issue that is scoped to only the current request, so only | 366 // indicates an issue that is scoped to only the current request, so only |
| 335 // bypass the data reduction proxy for the current request. | 367 // bypass the data reduction proxy for the current request. |
| 336 data_reduction_proxy_info->bypass_all = true; | 368 data_reduction_proxy_info->bypass_all = true; |
| 337 data_reduction_proxy_info->mark_proxies_as_bad = false; | 369 data_reduction_proxy_info->mark_proxies_as_bad = false; |
| 338 data_reduction_proxy_info->bypass_duration = TimeDelta(); | 370 data_reduction_proxy_info->bypass_duration = TimeDelta(); |
| 339 return BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX; | 371 return BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX; |
| 340 } | 372 } |
| 341 | 373 |
| 342 // Missing the via header should not trigger bypass if the client is | 374 // Missing the via header should not trigger bypass if the client is |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 392 std::string value; | 424 std::string value; |
| 393 size_t iter = 0; | 425 size_t iter = 0; |
| 394 while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) { | 426 while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) { |
| 395 if (StartsWithActionPrefix(value, kChromeProxyActionFingerprintChromeProxy)) | 427 if (StartsWithActionPrefix(value, kChromeProxyActionFingerprintChromeProxy)) |
| 396 continue; | 428 continue; |
| 397 values->push_back(std::move(value)); | 429 values->push_back(std::move(value)); |
| 398 } | 430 } |
| 399 } | 431 } |
| 400 | 432 |
| 401 } // namespace data_reduction_proxy | 433 } // namespace data_reduction_proxy |
| OLD | NEW |