• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
6 
7 #include <string>
8 
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_piece.h"
11 #include "base/strings/string_util.h"
12 #include "base/time/time.h"
13 #include "net/http/http_response_headers.h"
14 #include "net/http/http_status_code.h"
15 #include "net/proxy/proxy_service.h"
16 
17 using base::StringPiece;
18 using base::TimeDelta;
19 using net::ProxyService;
20 
21 namespace data_reduction_proxy {
22 
GetDataReductionProxyBypassDuration(const net::HttpResponseHeaders * headers,const std::string & action_prefix,base::TimeDelta * duration)23 bool GetDataReductionProxyBypassDuration(
24     const net::HttpResponseHeaders* headers,
25     const std::string& action_prefix,
26     base::TimeDelta* duration) {
27   void* iter = NULL;
28   std::string value;
29   std::string name = "chrome-proxy";
30 
31   while (headers->EnumerateHeader(&iter, name, &value)) {
32     if (value.size() > action_prefix.size()) {
33       if (LowerCaseEqualsASCII(value.begin(),
34                                value.begin() + action_prefix.size(),
35                                action_prefix.c_str())) {
36         int64 seconds;
37         if (!base::StringToInt64(
38                 StringPiece(value.begin() + action_prefix.size(), value.end()),
39                 &seconds) || seconds < 0) {
40           continue;  // In case there is a well formed instruction.
41         }
42         *duration = TimeDelta::FromSeconds(seconds);
43         return true;
44       }
45     }
46   }
47   return false;
48 }
49 
GetDataReductionProxyInfo(const net::HttpResponseHeaders * headers,DataReductionProxyInfo * proxy_info)50 bool GetDataReductionProxyInfo(const net::HttpResponseHeaders* headers,
51                                DataReductionProxyInfo* proxy_info) {
52   DCHECK(proxy_info);
53   proxy_info->bypass_all = false;
54   proxy_info->bypass_duration = TimeDelta();
55   // Support header of the form Chrome-Proxy: bypass|block=<duration>, where
56   // <duration> is the number of seconds to wait before retrying
57   // the proxy. If the duration is 0, then the default proxy retry delay
58   // (specified in |ProxyList::UpdateRetryInfoOnFallback|) will be used.
59   // 'bypass' instructs Chrome to bypass the currently connected data reduction
60   // proxy, whereas 'block' instructs Chrome to bypass all available data
61   // reduction proxies.
62 
63   // 'block' takes precedence over 'bypass', so look for it first.
64   // TODO(bengr): Reduce checks for 'block' and 'bypass' to a single loop.
65   if (GetDataReductionProxyBypassDuration(
66       headers, "block=", &proxy_info->bypass_duration)) {
67     proxy_info->bypass_all = true;
68     return true;
69   }
70 
71   // Next, look for 'bypass'.
72   if (GetDataReductionProxyBypassDuration(
73       headers, "bypass=", &proxy_info->bypass_duration)) {
74     return true;
75   }
76   return false;
77 }
78 
HasDataReductionProxyViaHeader(const net::HttpResponseHeaders * headers)79 bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers) {
80   const size_t kVersionSize = 4;
81   const char kDataReductionProxyViaValue[] = "Chrome-Compression-Proxy";
82   size_t value_len = strlen(kDataReductionProxyViaValue);
83   void* iter = NULL;
84   std::string value;
85 
86   // Case-sensitive comparison of |value|. Assumes the received protocol and the
87   // space following it are always |kVersionSize| characters. E.g.,
88   // 'Via: 1.1 Chrome-Compression-Proxy'
89   while (headers->EnumerateHeader(&iter, "via", &value)) {
90     if (value.size() >= kVersionSize + value_len &&
91         !value.compare(kVersionSize, value_len, kDataReductionProxyViaValue))
92       return true;
93   }
94 
95   // TODO(bengr): Remove deprecated header value.
96   const char kDeprecatedDataReductionProxyViaValue[] =
97       "1.1 Chrome Compression Proxy";
98   iter = NULL;
99   while (headers->EnumerateHeader(&iter, "via", &value))
100     if (value == kDeprecatedDataReductionProxyViaValue)
101       return true;
102 
103   return false;
104 }
105 
106 net::ProxyService::DataReductionProxyBypassEventType
GetDataReductionProxyBypassEventType(const net::HttpResponseHeaders * headers,DataReductionProxyInfo * data_reduction_proxy_info)107 GetDataReductionProxyBypassEventType(
108     const net::HttpResponseHeaders* headers,
109     DataReductionProxyInfo* data_reduction_proxy_info) {
110   DCHECK(data_reduction_proxy_info);
111   if (GetDataReductionProxyInfo(headers, data_reduction_proxy_info)) {
112     // A chrome-proxy response header is only present in a 502. For proper
113     // reporting, this check must come before the 5xx checks below.
114     if (data_reduction_proxy_info->bypass_duration < TimeDelta::FromMinutes(30))
115       return ProxyService::SHORT_BYPASS;
116     return ProxyService::LONG_BYPASS;
117   }
118   if (headers->response_code() == net::HTTP_INTERNAL_SERVER_ERROR ||
119       headers->response_code() == net::HTTP_BAD_GATEWAY ||
120       headers->response_code() == net::HTTP_SERVICE_UNAVAILABLE) {
121     // Fall back if a 500, 502 or 503 is returned.
122     return ProxyService::INTERNAL_SERVER_ERROR_BYPASS;
123   }
124   // TODO(kundaji): Bypass if Proxy-Authenticate header value cannot be
125   // interpreted by data reduction proxy.
126   if (headers->response_code() == net::HTTP_PROXY_AUTHENTICATION_REQUIRED &&
127       !headers->HasHeader("Proxy-Authenticate")) {
128     return ProxyService::MALFORMED_407_BYPASS;
129   }
130   if (!HasDataReductionProxyViaHeader(headers) &&
131       (headers->response_code() != net::HTTP_NOT_MODIFIED)) {
132     // A Via header might not be present in a 304. Since the goal of a 304
133     // response is to minimize information transfer, a sender in general
134     // should not generate representation metadata other than Cache-Control,
135     // Content-Location, Date, ETag, Expires, and Vary.
136 
137     // The proxy Via header might also not be present in a 4xx response.
138     // Separate this case from other responses that are missing the header.
139     if (headers->response_code() >= net::HTTP_BAD_REQUEST &&
140         headers->response_code() < net::HTTP_INTERNAL_SERVER_ERROR) {
141       return ProxyService::PROXY_4XX_BYPASS;
142     }
143     return ProxyService::MISSING_VIA_HEADER;
144   }
145   // There is no bypass event.
146   return ProxyService::BYPASS_EVENT_TYPE_MAX;
147 }
148 
149 }  // namespace data_reduction_proxy
150