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() { ...@@ -62,7 +62,7 @@ void InterceptDownloadResourceThrottle::ProcessDownloadRequest() {
if (headers.HasHeader(net::HttpRequestHeaders::kAuthorization) || if (headers.HasHeader(net::HttpRequestHeaders::kAuthorization) ||
!(request_->response_info().headers && !(request_->response_info().headers &&
data_reduction_proxy::HasDataReductionProxyViaHeader( data_reduction_proxy::HasDataReductionProxyViaHeader(
request_->response_info().headers))) { request_->response_info().headers, NULL))) {
return; return;
} }
#else #else
......
...@@ -177,7 +177,8 @@ bool DataReductionProxyWasUsed(WebFrame* frame) { ...@@ -177,7 +177,8 @@ bool DataReductionProxyWasUsed(WebFrame* frame) {
std::replace(headers.begin(), headers.end(), '\n', '\0'); std::replace(headers.begin(), headers.end(), '\n', '\0');
scoped_refptr<net::HttpResponseHeaders> response_headers( scoped_refptr<net::HttpResponseHeaders> response_headers(
new net::HttpResponseHeaders(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 // Returns true if the provided URL is a referrer string that came from
......
...@@ -315,7 +315,7 @@ DataReductionProxyRequestType GetDataReductionProxyRequestType( ...@@ -315,7 +315,7 @@ DataReductionProxyRequestType GetDataReductionProxyRequestType(
} }
#endif #endif
if (request->response_info().headers && if (request->response_info().headers &&
HasDataReductionProxyViaHeader(request->response_info().headers)) { HasDataReductionProxyViaHeader(request->response_info().headers, NULL)) {
return VIA_DATA_REDUCTION_PROXY; return VIA_DATA_REDUCTION_PROXY;
} }
return UNKNOWN_TYPE; return UNKNOWN_TYPE;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h" #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
#include <string> #include <string>
#include <vector>
#include "base/rand_util.h" #include "base/rand_util.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
...@@ -21,6 +22,18 @@ using net::ProxyService; ...@@ -21,6 +22,18 @@ using net::ProxyService;
namespace { 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 kShortBypassMaxSeconds = 59;
const int kMediumBypassMaxSeconds = 300; const int kMediumBypassMaxSeconds = 300;
...@@ -35,21 +48,51 @@ base::TimeDelta GetDefaultBypassDuration() { ...@@ -35,21 +48,51 @@ base::TimeDelta GetDefaultBypassDuration() {
namespace data_reduction_proxy { 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, bool ParseHeadersAndSetBypassDuration(const net::HttpResponseHeaders* headers,
const std::string& action_prefix, const std::string& action_prefix,
base::TimeDelta* bypass_duration) { 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; void* iter = NULL;
std::string value; std::string value;
std::string name = "chrome-proxy"; std::string prefix = action_prefix + kActionValueDelimiter;
while (headers->EnumerateHeader(&iter, name, &value)) { while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
if (value.size() > action_prefix.size()) { if (value.size() > prefix.size()) {
if (LowerCaseEqualsASCII(value.begin(), if (LowerCaseEqualsASCII(value.begin(),
value.begin() + action_prefix.size(), value.begin() + prefix.size(),
action_prefix.c_str())) { prefix.c_str())) {
int64 seconds; int64 seconds;
if (!base::StringToInt64( if (!base::StringToInt64(
StringPiece(value.begin() + action_prefix.size(), value.end()), StringPiece(value.begin() + prefix.size(), value.end()),
&seconds) || seconds < 0) { &seconds) || seconds < 0) {
continue; // In case there is a well formed instruction. continue; // In case there is a well formed instruction.
} }
...@@ -82,20 +125,21 @@ bool ParseHeadersAndSetProxyInfo(const net::HttpResponseHeaders* headers, ...@@ -82,20 +125,21 @@ bool ParseHeadersAndSetProxyInfo(const net::HttpResponseHeaders* headers,
// 'block' takes precedence over 'bypass', so look for it first. // 'block' takes precedence over 'bypass', so look for it first.
// TODO(bengr): Reduce checks for 'block' and 'bypass' to a single loop. // TODO(bengr): Reduce checks for 'block' and 'bypass' to a single loop.
if (ParseHeadersAndSetBypassDuration( if (ParseHeadersAndSetBypassDuration(
headers, "block=", &proxy_info->bypass_duration)) { headers, kChromeProxyActionBlock, &proxy_info->bypass_duration)) {
proxy_info->bypass_all = true; proxy_info->bypass_all = true;
return true; return true;
} }
// Next, look for 'bypass'. // Next, look for 'bypass'.
if (ParseHeadersAndSetBypassDuration( if (ParseHeadersAndSetBypassDuration(
headers, "bypass=", &proxy_info->bypass_duration)) { headers, kChromeProxyActionBypass, &proxy_info->bypass_duration)) {
return true; return true;
} }
return false; return false;
} }
bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers) { bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers,
bool* has_intermediary) {
const size_t kVersionSize = 4; const size_t kVersionSize = 4;
const char kDataReductionProxyViaValue[] = "Chrome-Compression-Proxy"; const char kDataReductionProxyViaValue[] = "Chrome-Compression-Proxy";
size_t value_len = strlen(kDataReductionProxyViaValue); size_t value_len = strlen(kDataReductionProxyViaValue);
...@@ -107,8 +151,13 @@ bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers) { ...@@ -107,8 +151,13 @@ bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers) {
// 'Via: 1.1 Chrome-Compression-Proxy' // 'Via: 1.1 Chrome-Compression-Proxy'
while (headers->EnumerateHeader(&iter, "via", &value)) { while (headers->EnumerateHeader(&iter, "via", &value)) {
if (value.size() >= kVersionSize + value_len && 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; return true;
}
} }
// TODO(bengr): Remove deprecated header value. // TODO(bengr): Remove deprecated header value.
...@@ -116,8 +165,11 @@ bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers) { ...@@ -116,8 +165,11 @@ bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers) {
"1.1 Chrome Compression Proxy"; "1.1 Chrome Compression Proxy";
iter = NULL; iter = NULL;
while (headers->EnumerateHeader(&iter, "via", &value)) 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 true;
}
return false; return false;
} }
...@@ -151,7 +203,7 @@ GetDataReductionProxyBypassType( ...@@ -151,7 +203,7 @@ GetDataReductionProxyBypassType(
!headers->HasHeader("Proxy-Authenticate")) { !headers->HasHeader("Proxy-Authenticate")) {
return ProxyService::MALFORMED_407; return ProxyService::MALFORMED_407;
} }
if (!HasDataReductionProxyViaHeader(headers) && if (!HasDataReductionProxyViaHeader(headers, NULL) &&
(headers->response_code() != net::HTTP_NOT_MODIFIED)) { (headers->response_code() != net::HTTP_NOT_MODIFIED)) {
// A Via header might not be present in a 304. Since the goal of a 304 // 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 // response is to minimize information transfer, a sender in general
...@@ -170,4 +222,62 @@ GetDataReductionProxyBypassType( ...@@ -170,4 +222,62 @@ GetDataReductionProxyBypassType(
return ProxyService::BYPASS_EVENT_TYPE_MAX; 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 } // namespace data_reduction_proxy
...@@ -41,8 +41,12 @@ bool ParseHeadersAndSetProxyInfo(const net::HttpResponseHeaders* headers, ...@@ -41,8 +41,12 @@ bool ParseHeadersAndSetProxyInfo(const net::HttpResponseHeaders* headers,
DataReductionProxyInfo* proxy_info); DataReductionProxyInfo* proxy_info);
// Returns true if the response contains the data reduction proxy Via header // Returns true if the response contains the data reduction proxy Via header
// value. Used to check the integrity of data reduction proxy responses. // value. If non-NULL, sets |has_intermediary| to true if another server added
bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers); // 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 // Returns the reason why the Chrome proxy should be bypassed or not, and
// populates |proxy_info| with information on how long to bypass if // populates |proxy_info| with information on how long to bypass if
...@@ -51,11 +55,44 @@ net::ProxyService::DataReductionProxyBypassType GetDataReductionProxyBypassType( ...@@ -51,11 +55,44 @@ net::ProxyService::DataReductionProxyBypassType GetDataReductionProxyBypassType(
const net::HttpResponseHeaders* headers, const net::HttpResponseHeaders* headers,
DataReductionProxyInfo* proxy_info); 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 // Searches for the specified Chrome-Proxy action, and if present interprets
// its value as a duration in seconds. // its value as a duration in seconds.
bool ParseHeadersAndSetBypassDuration(const net::HttpResponseHeaders* headers, bool ParseHeadersAndSetBypassDuration(const net::HttpResponseHeaders* headers,
const std::string& action_prefix, const std::string& action_prefix,
base::TimeDelta* bypass_duration); 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 } // namespace data_reduction_proxy
#endif // COMPONENTS_DATA_REDUCTION_PROXY_COMMON_DATA_REDUCTION_PROXY_HEADERS_H_ #endif // COMPONENTS_DATA_REDUCTION_PROXY_COMMON_DATA_REDUCTION_PROXY_HEADERS_H_
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h" #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
#include <vector>
#include "net/http/http_response_headers.h" #include "net/http/http_response_headers.h"
#include "net/proxy/proxy_service.h" #include "net/proxy/proxy_service.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -24,6 +26,92 @@ namespace data_reduction_proxy { ...@@ -24,6 +26,92 @@ namespace data_reduction_proxy {
class DataReductionProxyHeadersTest : public testing::Test {}; class DataReductionProxyHeadersTest : public testing::Test {};
TEST_F(DataReductionProxyHeadersTest, GetDataReductionProxyActionValue) {
const struct {
const char* headers;
std::string action_key;
bool expected_result;
std::string expected_action_value;
} tests[] = {
{ "HTTP/1.1 200 OK\n"
"Content-Length: 999\n",
"a",
false,
"",
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Content-Length: 999\n",
"a",
false,
"",
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: bypass=86400\n"
"Content-Length: 999\n",
"bypass",
true,
"86400",
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: bypass86400\n"
"Content-Length: 999\n",
"bypass",
false,
"",
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: bypass=0\n"
"Content-Length: 999\n",
"bypass",
true,
"0",
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: bypass=1500\n"
"Chrome-Proxy: bypass=86400\n"
"Content-Length: 999\n",
"bypass",
true,
"1500",
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: block=1500, block=3600\n"
"Content-Length: 999\n",
"block",
true,
"1500",
},
{ "HTTP/1.1 200 OK\n"
"connection: proxy-bypass\n"
"Chrome-Proxy: key=123 \n"
"Content-Length: 999\n",
"key",
true,
"123",
},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
std::string headers(tests[i].headers);
HeadersToRaw(&headers);
scoped_refptr<net::HttpResponseHeaders> parsed(
new net::HttpResponseHeaders(headers));
std::string action_value;
bool has_action_key = GetDataReductionProxyActionValue(
parsed, tests[i].action_key, &action_value);
EXPECT_EQ(tests[i].expected_result, has_action_key);
if (has_action_key) {
EXPECT_EQ(tests[i].expected_action_value, action_value);
}
}
}
TEST_F(DataReductionProxyHeadersTest, GetProxyBypassInfo) { TEST_F(DataReductionProxyHeadersTest, GetProxyBypassInfo) {
const struct { const struct {
const char* headers; const char* headers;
...@@ -202,66 +290,117 @@ TEST_F(DataReductionProxyHeadersTest, ParseHeadersAndSetProxyInfo) { ...@@ -202,66 +290,117 @@ TEST_F(DataReductionProxyHeadersTest, ParseHeadersAndSetProxyInfo) {
TEST_F(DataReductionProxyHeadersTest, HasDataReductionProxyViaHeader) { TEST_F(DataReductionProxyHeadersTest, HasDataReductionProxyViaHeader) {
const struct { const struct {
const char* headers; const char* headers;
bool expected_result; bool expected_result;
bool expected_has_intermediary;
bool ignore_intermediary;
} tests[] = { } tests[] = {
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.1 Chrome-Proxy\n", "Via: 1.1 Chrome-Proxy\n",
false, false,
false,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1\n", "Via: 1\n",
false, false,
false,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.1 Chrome-Compression-Proxy\n", "Via: 1.1 Chrome-Compression-Proxy\n",
true, true,
true,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.0 Chrome-Compression-Proxy\n", "Via: 1.0 Chrome-Compression-Proxy\n",
true, true,
true,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.1 Foo-Bar, 1.1 Chrome-Compression-Proxy\n", "Via: 1.1 Foo-Bar, 1.1 Chrome-Compression-Proxy\n",
true, true,
true,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.1 Chrome-Compression-Proxy, 1.1 Bar-Foo\n", "Via: 1.1 Chrome-Compression-Proxy, 1.1 Bar-Foo\n",
true, true,
false,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.1 chrome-compression-proxy\n", "Via: 1.1 chrome-compression-proxy\n",
false, false,
false,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.1 Foo-Bar\n" "Via: 1.1 Foo-Bar\n"
"Via: 1.1 Chrome-Compression-Proxy\n", "Via: 1.1 Chrome-Compression-Proxy\n",
true, true,
true,
false,
},
{ "HTTP/1.1 200 OK\n"
"Via: 1.1 Chrome-Compression-Proxy\n"
"Via: 1.1 Foo-Bar\n",
true,
false,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.1 Chrome-Proxy\n", "Via: 1.1 Chrome-Proxy\n",
false, false,
false,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.1 Chrome Compression Proxy\n", "Via: 1.1 Chrome Compression Proxy\n",
true, true,
true,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.1 Foo-Bar, 1.1 Chrome Compression Proxy\n", "Via: 1.1 Foo-Bar, 1.1 Chrome Compression Proxy\n",
true, true,
true,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.1 Chrome Compression Proxy, 1.1 Bar-Foo\n", "Via: 1.1 Chrome Compression Proxy, 1.1 Bar-Foo\n",
true, true,
false,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.1 chrome compression proxy\n", "Via: 1.1 chrome compression proxy\n",
false, false,
false,
false,
}, },
{ "HTTP/1.1 200 OK\n" { "HTTP/1.1 200 OK\n"
"Via: 1.1 Foo-Bar\n" "Via: 1.1 Foo-Bar\n"
"Via: 1.1 Chrome Compression Proxy\n", "Via: 1.1 Chrome Compression Proxy\n",
true, true,
true,
false,
},
{ "HTTP/1.1 200 OK\n"
"Via: 1.1 Chrome Compression Proxy\n"
"Via: 1.1 Foo-Bar\n",
true,
false,
false,
},
{ "HTTP/1.1 200 OK\n"
"Via: 1.1 Chrome Compression Proxy\n"
"Via: 1.1 Foo-Bar\n",
true,
false,
true,
}, },
}; };
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
...@@ -270,8 +409,19 @@ TEST_F(DataReductionProxyHeadersTest, HasDataReductionProxyViaHeader) { ...@@ -270,8 +409,19 @@ TEST_F(DataReductionProxyHeadersTest, HasDataReductionProxyViaHeader) {
scoped_refptr<net::HttpResponseHeaders> parsed( scoped_refptr<net::HttpResponseHeaders> parsed(
new net::HttpResponseHeaders(headers)); new net::HttpResponseHeaders(headers));
EXPECT_EQ(tests[i].expected_result, bool has_chrome_proxy_via_header, has_intermediary;
HasDataReductionProxyViaHeader(parsed)); if (tests[i].ignore_intermediary) {
has_chrome_proxy_via_header =
HasDataReductionProxyViaHeader(parsed, NULL);
}
else {
has_chrome_proxy_via_header =
HasDataReductionProxyViaHeader(parsed, &has_intermediary);
}
EXPECT_EQ(tests[i].expected_result, has_chrome_proxy_via_header);
if (has_chrome_proxy_via_header && !tests[i].ignore_intermediary) {
EXPECT_EQ(tests[i].expected_has_intermediary, has_intermediary);
}
} }
} }
...@@ -381,4 +531,248 @@ TEST_F(DataReductionProxyHeadersTest, GetDataReductionProxyBypassEventType) { ...@@ -381,4 +531,248 @@ TEST_F(DataReductionProxyHeadersTest, GetDataReductionProxyBypassEventType) {
GetDataReductionProxyBypassType(parsed, &chrome_proxy_info)); GetDataReductionProxyBypassType(parsed, &chrome_proxy_info));
} }
} }
TEST_F(DataReductionProxyHeadersTest,
GetDataReductionProxyActionFingerprintChromeProxy) {
const struct {
std::string label;
const char* headers;
bool expected_fingerprint_exist;
std::string expected_fingerprint;
} tests[] = {
{ "fingerprint doesn't exist",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: bypass=0\n",
false,
"",
},
{ "fingerprint occurs once",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: bypass=1, fcp=fp\n",
true,
"fp",
},
{ "fingerprint occurs twice",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: bypass=2, fcp=fp1, fcp=fp2\n",
true,
"fp1",
},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
std::string headers(tests[i].headers);
HeadersToRaw(&headers);
scoped_refptr<net::HttpResponseHeaders> parsed(
new net::HttpResponseHeaders(headers));
std::string fingerprint;
bool fingerprint_exist = GetDataReductionProxyActionFingerprintChromeProxy(
parsed, &fingerprint);
EXPECT_EQ(tests[i].expected_fingerprint_exist, fingerprint_exist)
<< tests[i].label;
if (fingerprint_exist)
EXPECT_EQ(tests[i].expected_fingerprint, fingerprint) << tests[i].label;
}
}
TEST_F(DataReductionProxyHeadersTest,
GetDataReductionProxyActionFingerprintVia) {
const struct {
std::string label;
const char* headers;
bool expected_fingerprint_exist;
std::string expected_fingerprint;
} tests[] = {
{ "fingerprint doesn't exist",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: bypass=0\n",
false,
"",
},
{ "fingerprint occurs once",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: bypass=1, fvia=fvia\n",
true,
"fvia",
},
{ "fingerprint occurs twice",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: bypass=2, fvia=fvia1, fvia=fvia2\n",
true,
"fvia1",
},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
std::string headers(tests[i].headers);
HeadersToRaw(&headers);
scoped_refptr<net::HttpResponseHeaders> parsed(
new net::HttpResponseHeaders(headers));
std::string fingerprint;
bool fingerprint_exist =
GetDataReductionProxyActionFingerprintVia(parsed, &fingerprint);
EXPECT_EQ(tests[i].expected_fingerprint_exist, fingerprint_exist)
<< tests[i].label;
if (fingerprint_exist)
EXPECT_EQ(tests[i].expected_fingerprint, fingerprint) << tests[i].label;
}
}
TEST_F(DataReductionProxyHeadersTest,
GetDataReductionProxyActionFingerprintOtherHeaders) {
const struct {
std::string label;
const char* headers;
bool expected_fingerprint_exist;
std::string expected_fingerprint;
} tests[] = {
{ "fingerprint doesn't exist",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: bypass=0\n",
false,
"",
},
{ "fingerprint occurs once",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: bypass=1, foh=foh\n",
true,
"foh",
},
{ "fingerprint occurs twice",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: bypass=2, foh=foh1, foh=foh2\n",
true,
"foh1",
},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
std::string headers(tests[i].headers);
HeadersToRaw(&headers);
scoped_refptr<net::HttpResponseHeaders> parsed(
new net::HttpResponseHeaders(headers));
std::string fingerprint;
bool fingerprint_exist =
GetDataReductionProxyActionFingerprintOtherHeaders(
parsed, &fingerprint);
EXPECT_EQ(tests[i].expected_fingerprint_exist, fingerprint_exist)
<< tests[i].label;
if (fingerprint_exist)
EXPECT_EQ(tests[i].expected_fingerprint, fingerprint) << tests[i].label;
}
}
TEST_F(DataReductionProxyHeadersTest,
GetDataReductionProxyActionFingerprintContentLength) {
const struct {
std::string label;
const char* headers;
bool expected_fingerprint_exist;
std::string expected_fingerprint;
} tests[] = {
{ "fingerprint doesn't exist",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: bypass=0\n",
false,
"",
},
{ "fingerprint occurs once",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: bypass=1, fcl=fcl\n",
true,
"fcl",
},
{ "fingerprint occurs twice",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: bypass=2, fcl=fcl1, fcl=fcl2\n",
true,
"fcl1",
},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
std::string headers(tests[i].headers);
HeadersToRaw(&headers);
scoped_refptr<net::HttpResponseHeaders> parsed(
new net::HttpResponseHeaders(headers));
std::string fingerprint;
bool fingerprint_exist =
GetDataReductionProxyActionFingerprintContentLength(
parsed, &fingerprint);
EXPECT_EQ(tests[i].expected_fingerprint_exist, fingerprint_exist)
<< tests[i].label;
if (fingerprint_exist)
EXPECT_EQ(tests[i].expected_fingerprint, fingerprint) << tests[i].label;
}
}
TEST_F(DataReductionProxyHeadersTest,
GetDataReductionProxyHeaderWithFingerprintRemoved) {
const struct {
std::string label;
const char* headers;
std::string expected_output_values_string;
} test[] = {
{
"Checks the case that there is no Chrome-Proxy header's fingerprint.",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: 1,2,3,5\n",
"1,2,3,5,",
},
{
"Checks the case that there is Chrome-Proxy header's fingerprint.",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: 1,2,3,fcp=4,5\n",
"1,2,3,5,",
},
{
"Checks the case that there is Chrome-Proxy header's fingerprint, and it"
"occurs at the end.",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: 1,2,3,fcp=4,",
"1,2,3,",
},
{
"Checks the case that there is Chrome-Proxy header's fingerprint, and it"
"occurs at the beginning.",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: fcp=1,2,3,",
"2,3,",
},
{
"Checks the case that value is longer than prefix.",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: fcp=1,fcp!=1,fcp!=2,fcpfcp=3",
"fcp!=1,fcp!=2,fcpfcp=3,",
},
{
"Checks the case that value is shorter than prefix but similar.",
"HTTP/1.1 200 OK\n"
"Chrome-Proxy: fcp=1,fcp,fcp=",
"fcp,fcp=,",
},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test); ++i) {
std::string headers(test[i].headers);
HeadersToRaw(&headers);
scoped_refptr<net::HttpResponseHeaders> parsed(
new net::HttpResponseHeaders(headers));
std::vector<std::string> output_values;
GetDataReductionProxyHeaderWithFingerprintRemoved(parsed, &output_values);
std::string output_values_string;
for (size_t j = 0; j < output_values.size(); ++j)
output_values_string += output_values[j] + ",";
EXPECT_EQ(test[i].expected_output_values_string, output_values_string)
<< test[i].label;
}
}
} // namespace data_reduction_proxy } // namespace data_reduction_proxy
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