Commit 236ccaa1 authored by xingx@chromium.org's avatar xingx@chromium.org

1. Adds action-parsing functionality for data reduction proxy header.

2. Adds a couple of functions to return different fingerprint value for tamper detection.

3. Adds a function to remove Chrome-Proxy header's fingerprint from its header values, and return the rest of header values.

4. Changes HasDataReductionProxyViaHeader to also tell 
whether data reduction proxy Via header occurs at the last 
or not.


BUG=381907

Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=287561

Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=287855

Review URL: https://codereview.chromium.org/387353003

Cr-Commit-Position: refs/heads/master@{#288272}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288272 0039d316-1c4b-4281-b951-d872f2087c98
parent 8b12bb8a
......@@ -62,7 +62,7 @@ void InterceptDownloadResourceThrottle::ProcessDownloadRequest() {
if (headers.HasHeader(net::HttpRequestHeaders::kAuthorization) ||
!(request_->response_info().headers &&
data_reduction_proxy::HasDataReductionProxyViaHeader(
request_->response_info().headers))) {
request_->response_info().headers, NULL))) {
return;
}
#else
......
......@@ -177,7 +177,8 @@ bool DataReductionProxyWasUsed(WebFrame* frame) {
std::replace(headers.begin(), headers.end(), '\n', '\0');
scoped_refptr<net::HttpResponseHeaders> response_headers(
new net::HttpResponseHeaders(headers));
return data_reduction_proxy::HasDataReductionProxyViaHeader(response_headers);
return data_reduction_proxy::HasDataReductionProxyViaHeader(
response_headers, NULL);
}
// Returns true if the provided URL is a referrer string that came from
......
......@@ -315,7 +315,7 @@ DataReductionProxyRequestType GetDataReductionProxyRequestType(
}
#endif
if (request->response_info().headers &&
HasDataReductionProxyViaHeader(request->response_info().headers)) {
HasDataReductionProxyViaHeader(request->response_info().headers, NULL)) {
return VIA_DATA_REDUCTION_PROXY;
}
return UNKNOWN_TYPE;
......
......@@ -5,6 +5,7 @@
#include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
#include <string>
#include <vector>
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
......@@ -21,6 +22,18 @@ using net::ProxyService;
namespace {
const char kChromeProxyHeader[] = "chrome-proxy";
const char kActionValueDelimiter = '=';
const char kChromeProxyActionBlock[] = "block";
const char kChromeProxyActionBypass[] = "bypass";
// Actions for tamper detection fingerprints.
const char kChromeProxyActionFingerprintChromeProxy[] = "fcp";
const char kChromeProxyActionFingerprintVia[] = "fvia";
const char kChromeProxyActionFingerprintOtherHeaders[] = "foh";
const char kChromeProxyActionFingerprintContentLength[] = "fcl";
const int kShortBypassMaxSeconds = 59;
const int kMediumBypassMaxSeconds = 300;
......@@ -35,21 +48,51 @@ base::TimeDelta GetDefaultBypassDuration() {
namespace data_reduction_proxy {
bool GetDataReductionProxyActionValue(
const net::HttpResponseHeaders* headers,
const std::string& action_prefix,
std::string* action_value) {
DCHECK(headers);
DCHECK(!action_prefix.empty());
// A valid action does not include a trailing '='.
DCHECK(action_prefix[action_prefix.size() - 1] != kActionValueDelimiter);
void* iter = NULL;
std::string value;
std::string prefix = action_prefix + kActionValueDelimiter;
while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
if (value.size() > prefix.size()) {
if (LowerCaseEqualsASCII(value.begin(),
value.begin() + prefix.size(),
prefix.c_str())) {
if (action_value)
*action_value = value.substr(prefix.size());
return true;
}
}
}
return false;
}
bool ParseHeadersAndSetBypassDuration(const net::HttpResponseHeaders* headers,
const std::string& action_prefix,
base::TimeDelta* bypass_duration) {
DCHECK(headers);
DCHECK(!action_prefix.empty());
// A valid action does not include a trailing '='.
DCHECK(action_prefix[action_prefix.size() - 1] != kActionValueDelimiter);
void* iter = NULL;
std::string value;
std::string name = "chrome-proxy";
std::string prefix = action_prefix + kActionValueDelimiter;
while (headers->EnumerateHeader(&iter, name, &value)) {
if (value.size() > action_prefix.size()) {
while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
if (value.size() > prefix.size()) {
if (LowerCaseEqualsASCII(value.begin(),
value.begin() + action_prefix.size(),
action_prefix.c_str())) {
value.begin() + prefix.size(),
prefix.c_str())) {
int64 seconds;
if (!base::StringToInt64(
StringPiece(value.begin() + action_prefix.size(), value.end()),
StringPiece(value.begin() + prefix.size(), value.end()),
&seconds) || seconds < 0) {
continue; // In case there is a well formed instruction.
}
......@@ -82,20 +125,21 @@ bool ParseHeadersAndSetProxyInfo(const net::HttpResponseHeaders* headers,
// 'block' takes precedence over 'bypass', so look for it first.
// TODO(bengr): Reduce checks for 'block' and 'bypass' to a single loop.
if (ParseHeadersAndSetBypassDuration(
headers, "block=", &proxy_info->bypass_duration)) {
headers, kChromeProxyActionBlock, &proxy_info->bypass_duration)) {
proxy_info->bypass_all = true;
return true;
}
// Next, look for 'bypass'.
if (ParseHeadersAndSetBypassDuration(
headers, "bypass=", &proxy_info->bypass_duration)) {
headers, kChromeProxyActionBypass, &proxy_info->bypass_duration)) {
return true;
}
return false;
}
bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers) {
bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers,
bool* has_intermediary) {
const size_t kVersionSize = 4;
const char kDataReductionProxyViaValue[] = "Chrome-Compression-Proxy";
size_t value_len = strlen(kDataReductionProxyViaValue);
......@@ -107,8 +151,13 @@ bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers) {
// 'Via: 1.1 Chrome-Compression-Proxy'
while (headers->EnumerateHeader(&iter, "via", &value)) {
if (value.size() >= kVersionSize + value_len &&
!value.compare(kVersionSize, value_len, kDataReductionProxyViaValue))
!value.compare(kVersionSize, value_len, 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));
return true;
}
}
// TODO(bengr): Remove deprecated header value.
......@@ -116,8 +165,11 @@ bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers) {
"1.1 Chrome Compression Proxy";
iter = NULL;
while (headers->EnumerateHeader(&iter, "via", &value))
if (value == kDeprecatedDataReductionProxyViaValue)
if (value == kDeprecatedDataReductionProxyViaValue) {
if (has_intermediary)
*has_intermediary = !(headers->EnumerateHeader(&iter, "via", &value));
return true;
}
return false;
}
......@@ -151,7 +203,7 @@ GetDataReductionProxyBypassType(
!headers->HasHeader("Proxy-Authenticate")) {
return ProxyService::MALFORMED_407;
}
if (!HasDataReductionProxyViaHeader(headers) &&
if (!HasDataReductionProxyViaHeader(headers, NULL) &&
(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
......@@ -170,4 +222,62 @@ GetDataReductionProxyBypassType(
return ProxyService::BYPASS_EVENT_TYPE_MAX;
}
bool GetDataReductionProxyActionFingerprintChromeProxy(
const net::HttpResponseHeaders* headers,
std::string* chrome_proxy_fingerprint) {
return GetDataReductionProxyActionValue(
headers,
kChromeProxyActionFingerprintChromeProxy,
chrome_proxy_fingerprint);
}
bool GetDataReductionProxyActionFingerprintVia(
const net::HttpResponseHeaders* headers,
std::string* via_fingerprint) {
return GetDataReductionProxyActionValue(
headers,
kChromeProxyActionFingerprintVia,
via_fingerprint);
}
bool GetDataReductionProxyActionFingerprintOtherHeaders(
const net::HttpResponseHeaders* headers,
std::string* other_headers_fingerprint) {
return GetDataReductionProxyActionValue(
headers,
kChromeProxyActionFingerprintOtherHeaders,
other_headers_fingerprint);
}
bool GetDataReductionProxyActionFingerprintContentLength(
const net::HttpResponseHeaders* headers,
std::string* content_length_fingerprint) {
return GetDataReductionProxyActionValue(
headers,
kChromeProxyActionFingerprintContentLength,
content_length_fingerprint);
}
void GetDataReductionProxyHeaderWithFingerprintRemoved(
const net::HttpResponseHeaders* headers,
std::vector<std::string>* values) {
DCHECK(values);
std::string chrome_proxy_fingerprint_prefix = std::string(
kChromeProxyActionFingerprintChromeProxy) + kActionValueDelimiter;
std::string value;
void* iter = NULL;
while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
if (value.size() > chrome_proxy_fingerprint_prefix.size()) {
if (LowerCaseEqualsASCII(
value.begin(),
value.begin() + chrome_proxy_fingerprint_prefix.size(),
chrome_proxy_fingerprint_prefix.c_str())) {
continue;
}
}
values->push_back(value);
}
}
} // namespace data_reduction_proxy
......@@ -41,8 +41,12 @@ bool ParseHeadersAndSetProxyInfo(const net::HttpResponseHeaders* headers,
DataReductionProxyInfo* proxy_info);
// Returns true if the response contains the data reduction proxy Via header
// value. Used to check the integrity of data reduction proxy responses.
bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers);
// value. If non-NULL, sets |has_intermediary| to true if another server added
// a Via header after the data reduction proxy, and to false otherwise. Used to
// check the integrity of data reduction proxy responses and whether there are
// other middleboxes between the data reduction proxy and the client.
bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers,
bool* has_intermediary);
// Returns the reason why the Chrome proxy should be bypassed or not, and
// populates |proxy_info| with information on how long to bypass if
......@@ -51,11 +55,44 @@ net::ProxyService::DataReductionProxyBypassType GetDataReductionProxyBypassType(
const net::HttpResponseHeaders* headers,
DataReductionProxyInfo* proxy_info);
// Searches for the specified Chrome-Proxy action, and if present saves its
// value as a string in |action_value|. Only returns the first one and ignores
// the rest if multiple actions match |action_prefix|.
bool GetDataReductionProxyActionValue(
const net::HttpResponseHeaders* headers,
const std::string& action_prefix,
std::string* action_value);
// Searches for the specified Chrome-Proxy action, and if present interprets
// its value as a duration in seconds.
bool ParseHeadersAndSetBypassDuration(const net::HttpResponseHeaders* headers,
const std::string& action_prefix,
base::TimeDelta* bypass_duration);
// Gets the fingerprint of the Chrome-Proxy header.
bool GetDataReductionProxyActionFingerprintChromeProxy(
const net::HttpResponseHeaders* headers,
std::string* chrome_proxy_fingerprint);
// Gets the fingerprint of the Via header.
bool GetDataReductionProxyActionFingerprintVia(
const net::HttpResponseHeaders* headers,
std::string* via_fingerprint);
// Gets the fingerprint of a list of headers.
bool GetDataReductionProxyActionFingerprintOtherHeaders(
const net::HttpResponseHeaders* headers,
std::string* other_headers_fingerprint);
// Gets the fingerprint of Content-Length header.
bool GetDataReductionProxyActionFingerprintContentLength(
const net::HttpResponseHeaders* headers,
std::string* content_length_fingerprint);
// Returns values of the Chrome-Proxy header, but with its fingerprint removed.
void GetDataReductionProxyHeaderWithFingerprintRemoved(
const net::HttpResponseHeaders* headers,
std::vector<std::string>* values);
} // namespace data_reduction_proxy
#endif // COMPONENTS_DATA_REDUCTION_PROXY_COMMON_DATA_REDUCTION_PROXY_HEADERS_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment