Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(387)

Side by Side Diff: components/data_reduction_proxy/common/data_reduction_proxy_headers.cc

Issue 387353003: Modify data_reduction_proxy_header to support tamper detection logic. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@work
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 8
9 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_piece.h" 10 #include "base/strings/string_piece.h"
11 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
12 #include "base/time/time.h" 12 #include "base/time/time.h"
13 #include "net/http/http_response_headers.h" 13 #include "net/http/http_response_headers.h"
14 #include "net/http/http_status_code.h" 14 #include "net/http/http_status_code.h"
15 #include "net/proxy/proxy_service.h" 15 #include "net/proxy/proxy_service.h"
16 16
17 using base::StringPiece; 17 using base::StringPiece;
18 using base::TimeDelta; 18 using base::TimeDelta;
19 using net::ProxyService; 19 using net::ProxyService;
20 20
21 namespace {
22 const char kChromeProxyHeader[] = "chrome-proxy";
23 } // namespace
24
21 namespace data_reduction_proxy { 25 namespace data_reduction_proxy {
22 26
27 const char kChromeProxyActionFingerprintChromeProxy[] = "fcp";
28 const char kChromeProxyActionFingerprintVia[] = "fvia";
29 const char kChromeProxyActionFingerprintOtherHeaders[] = "foh";
30 const char kChromeProxyActionFingerprintContentLength[] = "fcl";
bengr 2014/07/29 17:50:28 I really don't like that you expose these names. I
xingx1 2014/07/30 03:32:55 Adding additional functions so that these constant
31
32 bool GetDataReductionProxyActionValue(
33 const net::HttpResponseHeaders* headers,
34 const std::string& action_prefix,
35 std::string* action_value) {
36 DCHECK(!action_prefix.empty());
bengr 2014/07/29 17:50:28 You should also check that header is not NULL.
xingx1 2014/07/30 03:32:55 Done.
37 void* iter = NULL;
38 std::string value;
39 std::string prefix = action_prefix + "=";
bengr 2014/07/29 17:50:27 Define "=" as kActionValueDelimiter in the anonymo
xingx1 2014/07/30 03:32:55 Done.
40
41 while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
42 // ">=" to allow empty action value.
bengr 2014/07/29 17:50:27 I don't think an empty value should be legal. Look
xingx1 2014/07/30 03:32:56 Done. Previously I'm allowing empty action value
43 if (value.size() >= prefix.size()) {
44 if (LowerCaseEqualsASCII(value.begin(),
45 value.begin() + prefix.size(),
46 prefix.c_str())) {
47 if (action_value)
48 *action_value = value.substr(prefix.size());
49 return true;
50 }
51 }
52 }
53 return false;
54 }
55
23 bool GetDataReductionProxyBypassDuration( 56 bool GetDataReductionProxyBypassDuration(
24 const net::HttpResponseHeaders* headers, 57 const net::HttpResponseHeaders* headers,
25 const std::string& action_prefix, 58 const std::string& action_prefix,
26 base::TimeDelta* duration) { 59 base::TimeDelta* duration) {
60 DCHECK(!action_prefix.empty());
61 DCHECK(action_prefix[action_prefix.size() - 1] != '=');
bolian 2014/07/29 17:03:50 same here, you don't need this DCHECK. Why not jus
bengr 2014/07/29 17:50:27 I asked for the '=' to be separate from the prefix
xingx1 2014/07/30 03:32:55 Done.
xingx1 2014/07/30 03:32:56 I coded DCHECK there for now.
27 void* iter = NULL; 62 void* iter = NULL;
28 std::string value; 63 std::string value;
29 std::string name = "chrome-proxy"; 64 std::string prefix = action_prefix + "=";
30 65
31 while (headers->EnumerateHeader(&iter, name, &value)) { 66 while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
32 if (value.size() > action_prefix.size()) { 67 if (value.size() > prefix.size()) {
33 if (LowerCaseEqualsASCII(value.begin(), 68 if (LowerCaseEqualsASCII(value.begin(),
34 value.begin() + action_prefix.size(), 69 value.begin() + prefix.size(),
35 action_prefix.c_str())) { 70 prefix.c_str())) {
36 int64 seconds; 71 int64 seconds;
37 if (!base::StringToInt64( 72 if (!base::StringToInt64(
38 StringPiece(value.begin() + action_prefix.size(), value.end()), 73 StringPiece(value.begin() + prefix.size(), value.end()),
39 &seconds) || seconds < 0) { 74 &seconds) || seconds < 0) {
40 continue; // In case there is a well formed instruction. 75 continue; // In case there is a well formed instruction.
41 } 76 }
42 *duration = TimeDelta::FromSeconds(seconds); 77 *duration = TimeDelta::FromSeconds(seconds);
43 return true; 78 return true;
44 } 79 }
45 } 80 }
46 } 81 }
47 return false; 82 return false;
48 } 83 }
49 84
50 bool GetDataReductionProxyInfo(const net::HttpResponseHeaders* headers, 85 bool GetDataReductionProxyInfo(const net::HttpResponseHeaders* headers,
51 DataReductionProxyInfo* proxy_info) { 86 DataReductionProxyInfo* proxy_info) {
52 DCHECK(proxy_info); 87 DCHECK(proxy_info);
53 proxy_info->bypass_all = false; 88 proxy_info->bypass_all = false;
54 proxy_info->bypass_duration = TimeDelta(); 89 proxy_info->bypass_duration = TimeDelta();
55 // Support header of the form Chrome-Proxy: bypass|block=<duration>, where 90 // Support header of the form Chrome-Proxy: bypass|block=<duration>, where
56 // <duration> is the number of seconds to wait before retrying 91 // <duration> is the number of seconds to wait before retrying
57 // the proxy. If the duration is 0, then the default proxy retry delay 92 // the proxy. If the duration is 0, then the default proxy retry delay
58 // (specified in |ProxyList::UpdateRetryInfoOnFallback|) will be used. 93 // (specified in |ProxyList::UpdateRetryInfoOnFallback|) will be used.
59 // 'bypass' instructs Chrome to bypass the currently connected data reduction 94 // 'bypass' instructs Chrome to bypass the currently connected data reduction
60 // proxy, whereas 'block' instructs Chrome to bypass all available data 95 // proxy, whereas 'block' instructs Chrome to bypass all available data
61 // reduction proxies. 96 // reduction proxies.
62 97
63 // 'block' takes precedence over 'bypass', so look for it first. 98 // 'block' takes precedence over 'bypass', so look for it first.
64 // TODO(bengr): Reduce checks for 'block' and 'bypass' to a single loop. 99 // TODO(bengr): Reduce checks for 'block' and 'bypass' to a single loop.
65 if (GetDataReductionProxyBypassDuration( 100 if (GetDataReductionProxyBypassDuration(
66 headers, "block=", &proxy_info->bypass_duration)) { 101 headers, "block", &proxy_info->bypass_duration)) {
bengr 2014/07/29 17:50:28 Add to the anonymous namespace: const char kChrome
xingx1 2014/07/30 03:32:55 Done.
67 proxy_info->bypass_all = true; 102 proxy_info->bypass_all = true;
68 return true; 103 return true;
69 } 104 }
70 105
71 // Next, look for 'bypass'. 106 // Next, look for 'bypass'.
72 if (GetDataReductionProxyBypassDuration( 107 if (GetDataReductionProxyBypassDuration(
73 headers, "bypass=", &proxy_info->bypass_duration)) { 108 headers, "bypass", &proxy_info->bypass_duration)) {
74 return true; 109 return true;
75 } 110 }
76 return false; 111 return false;
77 } 112 }
78 113
79 bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers) { 114 bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers,
115 bool* has_intermediary) {
80 const size_t kVersionSize = 4; 116 const size_t kVersionSize = 4;
81 const char kDataReductionProxyViaValue[] = "Chrome-Compression-Proxy"; 117 const char kDataReductionProxyViaValue[] = "Chrome-Compression-Proxy";
82 size_t value_len = strlen(kDataReductionProxyViaValue); 118 size_t value_len = strlen(kDataReductionProxyViaValue);
83 void* iter = NULL; 119 void* iter = NULL;
84 std::string value; 120 std::string value;
85 121
86 // Case-sensitive comparison of |value|. Assumes the received protocol and the 122 // Case-sensitive comparison of |value|. Assumes the received protocol and the
87 // space following it are always |kVersionSize| characters. E.g., 123 // space following it are always |kVersionSize| characters. E.g.,
88 // 'Via: 1.1 Chrome-Compression-Proxy' 124 // 'Via: 1.1 Chrome-Compression-Proxy'
89 while (headers->EnumerateHeader(&iter, "via", &value)) { 125 while (headers->EnumerateHeader(&iter, "via", &value)) {
90 if (value.size() >= kVersionSize + value_len && 126 if (value.size() >= kVersionSize + value_len &&
91 !value.compare(kVersionSize, value_len, kDataReductionProxyViaValue)) 127 !value.compare(kVersionSize, value_len, kDataReductionProxyViaValue)) {
128 if (has_intermediary)
bengr 2014/07/29 17:50:27 Add a comment here saying that we presume an inter
xingx1 2014/07/30 03:32:56 Done.
129 *has_intermediary = !(headers->EnumerateHeader(&iter, "via", &value));
92 return true; 130 return true;
131 }
93 } 132 }
94 133
95 // TODO(bengr): Remove deprecated header value. 134 // TODO(bengr): Remove deprecated header value.
96 const char kDeprecatedDataReductionProxyViaValue[] = 135 const char kDeprecatedDataReductionProxyViaValue[] =
97 "1.1 Chrome Compression Proxy"; 136 "1.1 Chrome Compression Proxy";
98 iter = NULL; 137 iter = NULL;
99 while (headers->EnumerateHeader(&iter, "via", &value)) 138 while (headers->EnumerateHeader(&iter, "via", &value))
100 if (value == kDeprecatedDataReductionProxyViaValue) 139 if (value == kDeprecatedDataReductionProxyViaValue) {
140 if (has_intermediary)
141 *has_intermediary = !(headers->EnumerateHeader(&iter, "via", &value));
101 return true; 142 return true;
143 }
102 144
103 return false; 145 return false;
104 } 146 }
105 147
106 const int kShortBypassMaxSeconds = 59; 148 const int kShortBypassMaxSeconds = 59;
107 const int kMediumBypassMaxSeconds = 300; 149 const int kMediumBypassMaxSeconds = 300;
108 net::ProxyService::DataReductionProxyBypassType 150 net::ProxyService::DataReductionProxyBypassType
109 GetDataReductionProxyBypassType( 151 GetDataReductionProxyBypassType(
110 const net::HttpResponseHeaders* headers, 152 const net::HttpResponseHeaders* headers,
111 DataReductionProxyInfo* data_reduction_proxy_info) { 153 DataReductionProxyInfo* data_reduction_proxy_info) {
(...skipping 17 matching lines...) Expand all
129 if (headers->response_code() == net::HTTP_BAD_GATEWAY) 171 if (headers->response_code() == net::HTTP_BAD_GATEWAY)
130 return ProxyService::STATUS_502_HTTP_BAD_GATEWAY; 172 return ProxyService::STATUS_502_HTTP_BAD_GATEWAY;
131 if (headers->response_code() == net::HTTP_SERVICE_UNAVAILABLE) 173 if (headers->response_code() == net::HTTP_SERVICE_UNAVAILABLE)
132 return ProxyService::STATUS_503_HTTP_SERVICE_UNAVAILABLE; 174 return ProxyService::STATUS_503_HTTP_SERVICE_UNAVAILABLE;
133 // TODO(kundaji): Bypass if Proxy-Authenticate header value cannot be 175 // TODO(kundaji): Bypass if Proxy-Authenticate header value cannot be
134 // interpreted by data reduction proxy. 176 // interpreted by data reduction proxy.
135 if (headers->response_code() == net::HTTP_PROXY_AUTHENTICATION_REQUIRED && 177 if (headers->response_code() == net::HTTP_PROXY_AUTHENTICATION_REQUIRED &&
136 !headers->HasHeader("Proxy-Authenticate")) { 178 !headers->HasHeader("Proxy-Authenticate")) {
137 return ProxyService::MALFORMED_407; 179 return ProxyService::MALFORMED_407;
138 } 180 }
139 if (!HasDataReductionProxyViaHeader(headers) && 181 if (!HasDataReductionProxyViaHeader(headers, NULL) &&
140 (headers->response_code() != net::HTTP_NOT_MODIFIED)) { 182 (headers->response_code() != net::HTTP_NOT_MODIFIED)) {
141 // A Via header might not be present in a 304. Since the goal of a 304 183 // A Via header might not be present in a 304. Since the goal of a 304
142 // response is to minimize information transfer, a sender in general 184 // response is to minimize information transfer, a sender in general
143 // should not generate representation metadata other than Cache-Control, 185 // should not generate representation metadata other than Cache-Control,
144 // Content-Location, Date, ETag, Expires, and Vary. 186 // Content-Location, Date, ETag, Expires, and Vary.
145 187
146 // The proxy Via header might also not be present in a 4xx response. 188 // The proxy Via header might also not be present in a 4xx response.
147 // Separate this case from other responses that are missing the header. 189 // Separate this case from other responses that are missing the header.
148 if (headers->response_code() >= net::HTTP_BAD_REQUEST && 190 if (headers->response_code() >= net::HTTP_BAD_REQUEST &&
149 headers->response_code() < net::HTTP_INTERNAL_SERVER_ERROR) { 191 headers->response_code() < net::HTTP_INTERNAL_SERVER_ERROR) {
150 return ProxyService::MISSING_VIA_HEADER_4XX; 192 return ProxyService::MISSING_VIA_HEADER_4XX;
151 } 193 }
152 return ProxyService::MISSING_VIA_HEADER_OTHER; 194 return ProxyService::MISSING_VIA_HEADER_OTHER;
153 } 195 }
154 // There is no bypass event. 196 // There is no bypass event.
155 return ProxyService::BYPASS_EVENT_TYPE_MAX; 197 return ProxyService::BYPASS_EVENT_TYPE_MAX;
156 } 198 }
157 199
158 } // namespace data_reduction_proxy 200 } // namespace data_reduction_proxy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698