| Index: components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
|
| diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
|
| index a8dca30a4f656e1d5a40a5e3703b85387eb506f2..b3c2f6caed1fe8ad6f0150081ebc518cff16606f 100644
|
| --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
|
| +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
|
| @@ -20,6 +20,7 @@
|
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
|
| #include "net/http/http_response_headers.h"
|
| #include "net/http/http_status_code.h"
|
| +#include "net/url_request/url_request.h"
|
|
|
| using base::StringPiece;
|
| using base::TimeDelta;
|
| @@ -106,6 +107,17 @@ bool IsPreviewType(const net::HttpResponseHeaders& headers,
|
| return IsPreviewTypeInHeaderValue(header_value, transform_type);
|
| }
|
|
|
| +// Returns true if there is a cycle in |url_chain|.
|
| +bool HasURLRedirectCycle(const std::vector<GURL>& url_chain) {
|
| + if (url_chain.size() <= 1)
|
| + return false;
|
| +
|
| + // If the last entry occurs earlier in the |url_chain|, then very likely there
|
| + // is a redirect cycle.
|
| + return std::find(url_chain.rbegin() + 1, url_chain.rend(),
|
| + url_chain.back()) != url_chain.rend();
|
| +}
|
| +
|
| } // namespace
|
|
|
| namespace data_reduction_proxy {
|
| @@ -180,14 +192,13 @@ bool GetDataReductionProxyActionValue(const net::HttpResponseHeaders* headers,
|
| return false;
|
| }
|
|
|
| -bool ParseHeadersAndSetBypassDuration(const net::HttpResponseHeaders* headers,
|
| +bool ParseHeadersAndSetBypassDuration(const net::HttpResponseHeaders& headers,
|
| base::StringPiece action_prefix,
|
| base::TimeDelta* bypass_duration) {
|
| - DCHECK(headers);
|
| size_t iter = 0;
|
| std::string value;
|
|
|
| - while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
|
| + while (headers.EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
|
| if (StartsWithActionPrefix(value, action_prefix)) {
|
| int64_t seconds;
|
| if (!base::StringToInt64(
|
| @@ -208,7 +219,7 @@ bool ParseHeadersAndSetBypassDuration(const net::HttpResponseHeaders* headers,
|
| return false;
|
| }
|
|
|
| -bool ParseHeadersForBypassInfo(const net::HttpResponseHeaders* headers,
|
| +bool ParseHeadersForBypassInfo(const net::HttpResponseHeaders& headers,
|
| DataReductionProxyInfo* proxy_info) {
|
| DCHECK(proxy_info);
|
|
|
| @@ -245,8 +256,7 @@ bool ParseHeadersForBypassInfo(const net::HttpResponseHeaders* headers,
|
| // reduction proxies. Unlike 'block', 'block-once' does not cause data
|
| // reduction proxies to be bypassed for an extended period of time;
|
| // 'block-once' only affects the retry of the current request.
|
| - if (headers->HasHeaderValue(kChromeProxyHeader,
|
| - kChromeProxyActionBlockOnce)) {
|
| + if (headers.HasHeaderValue(kChromeProxyHeader, kChromeProxyActionBlockOnce)) {
|
| proxy_info->bypass_all = true;
|
| proxy_info->mark_proxies_as_bad = false;
|
| proxy_info->bypass_duration = TimeDelta();
|
| @@ -257,7 +267,7 @@ bool ParseHeadersForBypassInfo(const net::HttpResponseHeaders* headers,
|
| return false;
|
| }
|
|
|
| -bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers,
|
| +bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders& headers,
|
| bool* has_intermediary) {
|
| static const size_t kVersionSize = 4;
|
| static const char kDataReductionProxyViaValue[] = "Chrome-Compression-Proxy";
|
| @@ -267,14 +277,14 @@ bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers,
|
| // Case-sensitive comparison of |value|. Assumes the received protocol and the
|
| // space following it are always |kVersionSize| characters. E.g.,
|
| // 'Via: 1.1 Chrome-Compression-Proxy'
|
| - while (headers->EnumerateHeader(&iter, "via", &value)) {
|
| + while (headers.EnumerateHeader(&iter, "via", &value)) {
|
| if (base::StringPiece(value).substr(
|
| kVersionSize, arraysize(kDataReductionProxyViaValue) - 1) ==
|
| kDataReductionProxyViaValue) {
|
| if (has_intermediary)
|
| // We assume intermediary exists if there is another Via header after
|
| // the data reduction proxy's Via header.
|
| - *has_intermediary = !(headers->EnumerateHeader(&iter, "via", &value));
|
| + *has_intermediary = !(headers.EnumerateHeader(&iter, "via", &value));
|
| return true;
|
| }
|
| }
|
| @@ -283,9 +293,21 @@ bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers,
|
| }
|
|
|
| DataReductionProxyBypassType GetDataReductionProxyBypassType(
|
| - const net::HttpResponseHeaders* headers,
|
| + const std::vector<GURL>& url_chain,
|
| + const net::HttpResponseHeaders& headers,
|
| DataReductionProxyInfo* data_reduction_proxy_info) {
|
| DCHECK(data_reduction_proxy_info);
|
| +
|
| + bool has_via_header = HasDataReductionProxyViaHeader(headers, nullptr);
|
| +
|
| + if (has_via_header && HasURLRedirectCycle(url_chain)) {
|
| + data_reduction_proxy_info->bypass_all = true;
|
| + data_reduction_proxy_info->mark_proxies_as_bad = false;
|
| + data_reduction_proxy_info->bypass_duration = base::TimeDelta();
|
| + data_reduction_proxy_info->bypass_action = BYPASS_ACTION_TYPE_BLOCK_ONCE;
|
| + return BYPASS_EVENT_TYPE_URL_REDIRECT_CYCLE;
|
| + }
|
| +
|
| if (ParseHeadersForBypassInfo(headers, data_reduction_proxy_info)) {
|
| // A chrome-proxy response header is only present in a 502. For proper
|
| // reporting, this check must come before the 5xx checks below.
|
| @@ -307,20 +329,19 @@ DataReductionProxyBypassType GetDataReductionProxyBypassType(
|
| data_reduction_proxy_info->bypass_duration = GetDefaultBypassDuration();
|
|
|
| // Fall back if a 500, 502 or 503 is returned.
|
| - if (headers->response_code() == net::HTTP_INTERNAL_SERVER_ERROR)
|
| + if (headers.response_code() == net::HTTP_INTERNAL_SERVER_ERROR)
|
| return BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR;
|
| - if (headers->response_code() == net::HTTP_BAD_GATEWAY)
|
| + if (headers.response_code() == net::HTTP_BAD_GATEWAY)
|
| return BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY;
|
| - if (headers->response_code() == net::HTTP_SERVICE_UNAVAILABLE)
|
| + if (headers.response_code() == net::HTTP_SERVICE_UNAVAILABLE)
|
| return BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE;
|
| // TODO(kundaji): Bypass if Proxy-Authenticate header value cannot be
|
| // interpreted by data reduction proxy.
|
| - if (headers->response_code() == net::HTTP_PROXY_AUTHENTICATION_REQUIRED &&
|
| - !headers->HasHeader("Proxy-Authenticate")) {
|
| + if (headers.response_code() == net::HTTP_PROXY_AUTHENTICATION_REQUIRED &&
|
| + !headers.HasHeader("Proxy-Authenticate")) {
|
| return BYPASS_EVENT_TYPE_MALFORMED_407;
|
| }
|
| - if (!HasDataReductionProxyViaHeader(headers, NULL) &&
|
| - (headers->response_code() != net::HTTP_NOT_MODIFIED)) {
|
| + if (!has_via_header && (headers.response_code() != net::HTTP_NOT_MODIFIED)) {
|
| // A Via header might not be present in a 304. Since the goal of a 304
|
| // response is to minimize information transfer, a sender in general
|
| // should not generate representation metadata other than Cache-Control,
|
| @@ -328,8 +349,8 @@ DataReductionProxyBypassType GetDataReductionProxyBypassType(
|
|
|
| // The proxy Via header might also not be present in a 4xx response.
|
| // Separate this case from other responses that are missing the header.
|
| - if (headers->response_code() >= net::HTTP_BAD_REQUEST &&
|
| - headers->response_code() < net::HTTP_INTERNAL_SERVER_ERROR) {
|
| + if (headers.response_code() >= net::HTTP_BAD_REQUEST &&
|
| + headers.response_code() < net::HTTP_INTERNAL_SERVER_ERROR) {
|
| // At this point, any 4xx response that is missing the via header
|
| // indicates an issue that is scoped to only the current request, so only
|
| // bypass the data reduction proxy for the current request.
|
|
|