blob: 5c3886d257a905f96f769c4c976823f828f91c30 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h"
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <string>
#include <utility>
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
#include "base/numerics/safe_conversions.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/test/histogram_tester.h"
#include "base/test/mock_entropy_provider.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
#include "components/data_reduction_proxy/core/common/lofi_decider.h"
#include "components/data_reduction_proxy/proto/client_config.pb.h"
#include "net/base/host_port_pair.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/nqe/effective_connection_type.h"
#include "net/nqe/network_quality_estimator_test_util.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_retry_info.h"
#include "net/proxy/proxy_server.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/socket_test_util.h"
#include "net/test/cert_test_util.h"
#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job_factory_impl.h"
#include "net/url_request/url_request_status.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace data_reduction_proxy {
namespace {
using TestNetworkDelegate = net::NetworkDelegateImpl;
const char kOtherProxy[] = "testproxy:17";
const char kTestURL[] = "http://www.google.com/";
const char kSecureTestURL[] = "https://www.google.com/";
const std::string kReceivedValidOCLHistogramName =
"Net.HttpContentLengthWithValidOCL";
const std::string kOriginalValidOCLHistogramName =
"Net.HttpOriginalContentLengthWithValidOCL";
const std::string kDifferenceValidOCLHistogramName =
"Net.HttpContentLengthDifferenceWithValidOCL";
// Lo-Fi histograms.
const std::string kReceivedValidOCLLoFiOnHistogramName =
"Net.HttpContentLengthWithValidOCL.LoFiOn";
const std::string kOriginalValidOCLLoFiOnHistogramName =
"Net.HttpOriginalContentLengthWithValidOCL.LoFiOn";
const std::string kDifferenceValidOCLLoFiOnHistogramName =
"Net.HttpContentLengthDifferenceWithValidOCL.LoFiOn";
const std::string kReceivedHistogramName = "Net.HttpContentLength";
const std::string kReceivedInsecureHistogramName = "Net.HttpContentLength.Http";
const std::string kReceivedSecureHistogramName = "Net.HttpContentLength.Https";
const std::string kReceivedVideoHistogramName = "Net.HttpContentLength.Video";
const std::string kOriginalHistogramName = "Net.HttpOriginalContentLength";
const std::string kDifferenceHistogramName = "Net.HttpContentLengthDifference";
const std::string kFreshnessLifetimeHistogramName =
"Net.HttpContentFreshnessLifetime";
const std::string kCacheableHistogramName = "Net.HttpContentLengthCacheable";
const std::string kCacheable4HoursHistogramName =
"Net.HttpContentLengthCacheable4Hours";
const std::string kCacheable24HoursHistogramName =
"Net.HttpContentLengthCacheable24Hours";
const int64_t kResponseContentLength = 100;
const int64_t kOriginalContentLength = 200;
#if defined(OS_ANDROID)
const Client kClient = Client::CHROME_ANDROID;
#elif defined(OS_IOS)
const Client kClient = Client::CHROME_IOS;
#elif defined(OS_MACOSX)
const Client kClient = Client::CHROME_MAC;
#elif defined(OS_CHROMEOS)
const Client kClient = Client::CHROME_CHROMEOS;
#elif defined(OS_LINUX)
const Client kClient = Client::CHROME_LINUX;
#elif defined(OS_WIN)
const Client kClient = Client::CHROME_WINDOWS;
#elif defined(OS_FREEBSD)
const Client kClient = Client::CHROME_FREEBSD;
#elif defined(OS_OPENBSD)
const Client kClient = Client::CHROME_OPENBSD;
#elif defined(OS_SOLARIS)
const Client kClient = Client::CHROME_SOLARIS;
#elif defined(OS_QNX)
const Client kClient = Client::CHROME_QNX;
#else
const Client kClient = Client::UNKNOWN;
#endif
class TestLoFiDecider : public LoFiDecider {
public:
TestLoFiDecider()
: should_request_lofi_resource_(false),
ignore_is_using_data_reduction_proxy_check_(false) {}
~TestLoFiDecider() override {}
bool IsUsingLoFi(const net::URLRequest& request) const override {
return should_request_lofi_resource_;
}
void SetIsUsingLoFi(bool should_request_lofi_resource) {
should_request_lofi_resource_ = should_request_lofi_resource;
}
void MaybeSetAcceptTransformHeader(
const net::URLRequest& request,
bool is_previews_disabled,
net::HttpRequestHeaders* headers) const override {
if (should_request_lofi_resource_) {
headers->SetHeader(chrome_proxy_accept_transform_header(),
empty_image_directive());
}
}
bool IsSlowPagePreviewRequested(
const net::HttpRequestHeaders& headers) const override {
std::string header_value;
if (headers.GetHeader(chrome_proxy_accept_transform_header(),
&header_value)) {
return header_value == empty_image_directive();
}
return false;
}
bool IsLitePagePreviewRequested(
const net::HttpRequestHeaders& headers) const override {
std::string header_value;
if (headers.GetHeader(chrome_proxy_accept_transform_header(),
&header_value)) {
return header_value == lite_page_directive();
}
return false;
}
void RemoveAcceptTransformHeader(
net::HttpRequestHeaders* headers) const override {
if (ignore_is_using_data_reduction_proxy_check_)
return;
headers->RemoveHeader(chrome_proxy_accept_transform_header());
}
void MaybeSetIgnorePreviewsBlacklistDirective(
net::HttpRequestHeaders* headers) const override {}
bool ShouldRecordLoFiUMA(const net::URLRequest& request) const override {
return should_request_lofi_resource_;
}
void ignore_is_using_data_reduction_proxy_check() {
ignore_is_using_data_reduction_proxy_check_ = true;
}
private:
bool should_request_lofi_resource_;
bool ignore_is_using_data_reduction_proxy_check_;
};
class TestLoFiUIService : public LoFiUIService {
public:
TestLoFiUIService() : on_lofi_response_(false) {}
~TestLoFiUIService() override {}
bool DidNotifyLoFiResponse() const { return on_lofi_response_; }
void OnLoFiReponseReceived(const net::URLRequest& request) override {
on_lofi_response_ = true;
}
private:
bool on_lofi_response_;
};
enum ProxyTestConfig { USE_SECURE_PROXY, USE_INSECURE_PROXY, BYPASS_PROXY };
class DataReductionProxyNetworkDelegateTest : public testing::Test {
public:
DataReductionProxyNetworkDelegateTest()
: context_(true),
context_storage_(&context_),
ssl_socket_data_provider_(net::ASYNC, net::OK) {
ssl_socket_data_provider_.next_proto = net::kProtoHTTP11;
ssl_socket_data_provider_.cert = net::ImportCertFromFile(
net::GetTestCertsDirectory(), "unittest.selfsigned.der");
}
void Init(ProxyTestConfig proxy_config, bool enable_brotli_globally) {
net::ProxyServer proxy_server;
switch (proxy_config) {
case BYPASS_PROXY:
proxy_server = net::ProxyServer::Direct();
break;
case USE_SECURE_PROXY:
proxy_server = net::ProxyServer::FromURI(
"https://origin.net:443", net::ProxyServer::SCHEME_HTTPS);
break;
case USE_INSECURE_PROXY:
proxy_server = net::ProxyServer::FromURI("http://origin.net:80",
net::ProxyServer::SCHEME_HTTP);
break;
}
proxy_service_ =
net::ProxyService::CreateFixedFromPacResult(proxy_server.ToPacString());
context_.set_proxy_service(proxy_service_.get());
DataReductionProxyTestContext::Builder builder;
builder = builder.WithClient(kClient)
.WithMockClientSocketFactory(&mock_socket_factory_)
.WithURLRequestContext(&context_);
if (proxy_config != BYPASS_PROXY) {
builder = builder.WithProxiesForHttp({DataReductionProxyServer(
proxy_server, ProxyServer::UNSPECIFIED_TYPE)});
}
test_context_ = builder.Build();
context_.set_client_socket_factory(&mock_socket_factory_);
test_context_->AttachToURLRequestContext(&context_storage_);
std::unique_ptr<TestLoFiDecider> lofi_decider(new TestLoFiDecider());
lofi_decider_ = lofi_decider.get();
test_context_->io_data()->set_lofi_decider(std::move(lofi_decider));
std::unique_ptr<TestLoFiUIService> lofi_ui_service(new TestLoFiUIService());
lofi_ui_service_ = lofi_ui_service.get();
test_context_->io_data()->set_lofi_ui_service(std::move(lofi_ui_service));
context_.set_enable_brotli(enable_brotli_globally);
context_.set_network_quality_estimator(&test_network_quality_estimator_);
context_.Init();
test_context_->EnableDataReductionProxyWithSecureProxyCheckSuccess();
}
static void VerifyHeaders(bool expected_data_reduction_proxy_used,
bool expected_lofi_used,
const net::HttpRequestHeaders& headers) {
EXPECT_EQ(expected_data_reduction_proxy_used,
headers.HasHeader(chrome_proxy_header()));
std::string header_value;
headers.GetHeader(chrome_proxy_accept_transform_header(), &header_value);
EXPECT_EQ(expected_data_reduction_proxy_used && expected_lofi_used,
header_value.find("empty-image") != std::string::npos);
}
void VerifyDidNotifyLoFiResponse(bool lofi_response) const {
EXPECT_EQ(lofi_response, lofi_ui_service_->DidNotifyLoFiResponse());
}
void VerifyDataReductionProxyData(const net::URLRequest& request,
bool data_reduction_proxy_used,
bool lofi_used) {
DataReductionProxyData* data = DataReductionProxyData::GetData(request);
if (!data_reduction_proxy_used) {
EXPECT_FALSE(data);
} else {
EXPECT_TRUE(data->used_data_reduction_proxy());
EXPECT_EQ(lofi_used, data->lofi_requested());
}
}
// Each line in |response_headers| should end with "\r\n" and not '\0', and
// the last line should have a second "\r\n".
// An empty |response_headers| is allowed. It works by making this look like
// an HTTP/0.9 response, since HTTP/0.9 responses don't have headers.
std::unique_ptr<net::URLRequest> FetchURLRequest(
const GURL& url,
net::HttpRequestHeaders* request_headers,
const std::string& response_headers,
int64_t response_content_length,
int load_flags) {
const std::string response_body(
base::checked_cast<size_t>(response_content_length), ' ');
net::MockRead reads[] = {net::MockRead(response_headers.c_str()),
net::MockRead(response_body.c_str()),
net::MockRead(net::SYNCHRONOUS, net::OK)};
net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
mock_socket_factory_.AddSocketDataProvider(&socket);
net::TestDelegate delegate;
std::unique_ptr<net::URLRequest> request =
context_.CreateRequest(url, net::IDLE, &delegate);
if (request_headers)
request->SetExtraRequestHeaders(*request_headers);
request->SetLoadFlags(request->load_flags() | load_flags);
request->Start();
base::RunLoop().RunUntilIdle();
return request;
}
// Reads brotli encoded content to |encoded_brotli_buffer_|.
void ReadBrotliFile() {
// Get the path of data directory.
const size_t kDefaultBufferSize = 4096;
base::FilePath data_dir;
PathService::Get(base::DIR_SOURCE_ROOT, &data_dir);
data_dir = data_dir.AppendASCII("net");
data_dir = data_dir.AppendASCII("data");
data_dir = data_dir.AppendASCII("filter_unittests");
// Read data from the encoded file into buffer.
base::FilePath encoded_file_path;
encoded_file_path = data_dir.AppendASCII("google.br");
ASSERT_TRUE(
base::ReadFileToString(encoded_file_path, &encoded_brotli_buffer_));
ASSERT_GE(kDefaultBufferSize, encoded_brotli_buffer_.size());
}
// Fetches a single URL request, verifies the correctness of Accept-Encoding
// header, and verifies that the response is cached only if |expect_cached|
// is set to true. Each line in |response_headers| should end with "\r\n" and
// not '\0', and the last line should have a second "\r\n". An empty
// |response_headers| is allowed. It works by making this look like an
// HTTP/0.9 response, since HTTP/0.9 responses don't have headers.
void FetchURLRequestAndVerifyBrotli(net::HttpRequestHeaders* request_headers,
const std::string& response_headers,
bool expect_cached,
bool expect_brotli) {
test_network_quality_estimator()->set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
GURL url(kTestURL);
int response_body_size = 140;
std::string response_body;
if (expect_brotli && !expect_cached) {
response_body = encoded_brotli_buffer_;
response_body_size = response_body.size();
} else {
response_body =
std::string(base::checked_cast<size_t>(response_body_size), ' ');
}
mock_socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider_);
net::MockRead reads[] = {net::MockRead(response_headers.c_str()),
net::MockRead(response_body.c_str()),
net::MockRead(net::SYNCHRONOUS, net::OK)};
if (io_data()->test_request_options()->GetHeaderValueForTesting().empty()) {
// Force regeneration of Chrome-Proxy header.
io_data()->test_request_options()->SetSecureSession("123");
}
EXPECT_FALSE(
io_data()->test_request_options()->GetHeaderValueForTesting().empty());
std::string host = GURL(kTestURL).host();
std::string prefix_headers = std::string("GET ")
.append(kTestURL)
.append(
" HTTP/1.1\r\n"
"Host: ")
.append(host)
.append(
"\r\n"
"Proxy-Connection: keep-alive\r\n"
"User-Agent:\r\n");
std::string accept_language_header("Accept-Language: en-us,fr\r\n");
// Brotli is included in accept-encoding header only if the request went
// to the network (i.e., it was not a cached response), and if data
// reduction ptroxy network delegate added Brotli to the header.
std::string accept_encoding_header =
expect_brotli && !expect_cached
? "Accept-Encoding: gzip, deflate, br\r\n"
: "Accept-Encoding: gzip, deflate\r\n";
std::string suffix_headers =
std::string("Chrome-Proxy: ") +
io_data()->test_request_options()->GetHeaderValueForTesting() +
std::string("\r\n\r\n");
std::string mock_write = prefix_headers + accept_language_header +
accept_encoding_header + suffix_headers;
if (expect_cached || !expect_brotli) {
// Order of headers is different if the headers were modified by data
// reduction proxy network delegate.
mock_write = prefix_headers + accept_encoding_header +
accept_language_header + suffix_headers;
}
net::MockWrite writes[] = {net::MockWrite(mock_write.c_str())};
net::StaticSocketDataProvider socket(reads, arraysize(reads), writes,
arraysize(writes));
mock_socket_factory_.AddSocketDataProvider(&socket);
net::TestDelegate delegate;
std::unique_ptr<net::URLRequest> request =
context_.CreateRequest(url, net::IDLE, &delegate);
if (request_headers)
request->SetExtraRequestHeaders(*request_headers);
request->Start();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, request->status().ToNetError());
if (!expect_cached) {
EXPECT_EQ(response_body_size,
request->received_response_content_length());
EXPECT_NE(0, request->GetTotalSentBytes());
EXPECT_NE(0, request->GetTotalReceivedBytes());
EXPECT_FALSE(request->was_cached());
VerifyBrotliPresent(request.get(), expect_brotli);
} else {
EXPECT_TRUE(request->was_cached());
std::string content_encoding_value;
request->GetResponseHeaderByName("Content-Encoding",
&content_encoding_value);
EXPECT_EQ(expect_brotli, content_encoding_value == "br");
}
}
void VerifyBrotliPresent(net::URLRequest* request, bool expect_brotli) {
net::HttpRequestHeaders request_headers_sent;
EXPECT_TRUE(request->GetFullRequestHeaders(&request_headers_sent));
std::string accept_encoding_value;
EXPECT_TRUE(request_headers_sent.GetHeader("Accept-Encoding",
&accept_encoding_value));
EXPECT_NE(std::string::npos, accept_encoding_value.find("gzip"));
std::string content_encoding_value;
request->GetResponseHeaderByName("Content-Encoding",
&content_encoding_value);
if (expect_brotli) {
// Brotli should be the last entry in the Accept-Encoding header.
EXPECT_EQ(accept_encoding_value.length() - 2,
accept_encoding_value.find("br"));
EXPECT_EQ("br", content_encoding_value);
} else {
EXPECT_EQ(std::string::npos, accept_encoding_value.find("br"));
}
}
void FetchURLRequestAndVerifyPageIdDirective(const std::string& page_id_value,
bool redirect_once) {
std::string response_headers =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 140\r\n"
"Via: 1.1 Chrome-Compression-Proxy\r\n"
"x-original-content-length: 200\r\n"
"Cache-Control: max-age=1200\r\n"
"Vary: accept-encoding\r\n\r\n";
GURL url(kTestURL);
int response_body_size = 140;
std::string response_body =
std::string(base::checked_cast<size_t>(response_body_size), ' ');
mock_socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider_);
net::MockRead redirect_reads[] = {
net::MockRead("HTTP/1.1 302 Redirect\r\n"),
net::MockRead("Location: http://www.google.com/\r\n"),
net::MockRead("Content-Length: 0\r\n\r\n"),
net::MockRead(net::SYNCHRONOUS, net::OK),
net::MockRead(response_headers.c_str()),
net::MockRead(response_body.c_str()),
net::MockRead(net::SYNCHRONOUS, net::OK)};
net::MockRead reads[] = {net::MockRead(response_headers.c_str()),
net::MockRead(response_body.c_str()),
net::MockRead(net::SYNCHRONOUS, net::OK)};
EXPECT_FALSE(
io_data()->test_request_options()->GetHeaderValueForTesting().empty());
std::string mock_write =
"GET http://www.google.com/ HTTP/1.1\r\nHost: "
"www.google.com\r\nProxy-Connection: "
"keep-alive\r\nUser-Agent:\r\nAccept-Encoding: gzip, "
"deflate\r\nAccept-Language: en-us,fr\r\n"
"Chrome-Proxy: " +
io_data()->test_request_options()->GetHeaderValueForTesting() +
(page_id_value.empty() ? "" : (", " + page_id_value)) + "\r\n\r\n";
net::MockWrite redirect_writes[] = {net::MockWrite(mock_write.c_str()),
net::MockWrite(mock_write.c_str())};
net::MockWrite writes[] = {net::MockWrite(mock_write.c_str())};
std::unique_ptr<net::StaticSocketDataProvider> socket;
if (!redirect_once) {
socket = base::MakeUnique<net::StaticSocketDataProvider>(
reads, arraysize(reads), writes, arraysize(writes));
} else {
socket = base::MakeUnique<net::StaticSocketDataProvider>(
redirect_reads, arraysize(redirect_reads), redirect_writes,
arraysize(redirect_writes));
}
mock_socket_factory_.AddSocketDataProvider(socket.get());
net::TestDelegate delegate;
std::unique_ptr<net::URLRequest> request =
context_.CreateRequest(url, net::IDLE, &delegate);
if (!page_id_value.empty()) {
request->SetLoadFlags(request->load_flags() |
net::LOAD_MAIN_FRAME_DEPRECATED);
}
request->Start();
base::RunLoop().RunUntilIdle();
}
void DelegateStageDone(int result) {}
void NotifyNetworkDelegate(net::URLRequest* request,
const net::ProxyInfo& data_reduction_proxy_info,
const net::ProxyRetryInfoMap& proxy_retry_info,
net::HttpRequestHeaders* headers) {
network_delegate()->NotifyBeforeURLRequest(
request,
base::Bind(&DataReductionProxyNetworkDelegateTest::DelegateStageDone,
base::Unretained(this)),
nullptr);
network_delegate()->NotifyBeforeStartTransaction(
request,
base::Bind(&DataReductionProxyNetworkDelegateTest::DelegateStageDone,
base::Unretained(this)),
headers);
network_delegate()->NotifyBeforeSendHeaders(
request, data_reduction_proxy_info, proxy_retry_info, headers);
}
net::MockClientSocketFactory* mock_socket_factory() {
return &mock_socket_factory_;
}
net::TestURLRequestContext* context() { return &context_; }
net::NetworkDelegate* network_delegate() const {
return context_.network_delegate();
}
TestDataReductionProxyParams* params() const {
return test_context_->config()->test_params();
}
TestDataReductionProxyConfig* config() const {
return test_context_->config();
}
TestDataReductionProxyIOData* io_data() const {
return test_context_->io_data();
}
TestLoFiDecider* lofi_decider() const { return lofi_decider_; }
net::TestNetworkQualityEstimator* test_network_quality_estimator() {
return &test_network_quality_estimator_;
}
net::SSLSocketDataProvider* ssl_socket_data_provider() {
return &ssl_socket_data_provider_;
}
private:
base::MessageLoopForIO message_loop_;
net::MockClientSocketFactory mock_socket_factory_;
std::unique_ptr<net::ProxyService> proxy_service_;
net::TestURLRequestContext context_;
net::URLRequestContextStorage context_storage_;
TestLoFiDecider* lofi_decider_;
TestLoFiUIService* lofi_ui_service_;
std::unique_ptr<DataReductionProxyTestContext> test_context_;
net::TestNetworkQualityEstimator test_network_quality_estimator_;
net::SSLSocketDataProvider ssl_socket_data_provider_;
std::unique_ptr<net::StaticSocketDataProvider> socket_;
// Encoded Brotli content read from a file. May be empty.
std::string encoded_brotli_buffer_;
};
TEST_F(DataReductionProxyNetworkDelegateTest, AuthenticationTest) {
Init(USE_INSECURE_PROXY, false);
std::unique_ptr<net::URLRequest> fake_request(
FetchURLRequest(GURL(kTestURL), nullptr, std::string(), 0, 0));
net::ProxyInfo data_reduction_proxy_info;
net::ProxyRetryInfoMap proxy_retry_info;
std::string data_reduction_proxy;
base::TrimString(params()->DefaultOrigin(), "/", &data_reduction_proxy);
data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy);
net::HttpRequestHeaders headers;
// Call network delegate methods to ensure that appropriate chrome proxy
// headers get added/removed.
network_delegate()->NotifyBeforeStartTransaction(
fake_request.get(),
base::Bind(&DataReductionProxyNetworkDelegateTest::DelegateStageDone,
base::Unretained(this)),
&headers);
network_delegate()->NotifyBeforeSendHeaders(fake_request.get(),
data_reduction_proxy_info,
proxy_retry_info, &headers);
EXPECT_TRUE(headers.HasHeader(chrome_proxy_header()));
std::string header_value;
headers.GetHeader(chrome_proxy_header(), &header_value);
EXPECT_TRUE(header_value.find("ps=") != std::string::npos);
EXPECT_TRUE(header_value.find("sid=") != std::string::npos);
}
TEST_F(DataReductionProxyNetworkDelegateTest, LoFiTransitions) {
Init(USE_INSECURE_PROXY, false);
// Enable Lo-Fi.
const struct {
bool lofi_switch_enabled;
bool auto_lofi_enabled;
bool is_data_reduction_proxy;
} tests[] = {
{
// Lo-Fi enabled through switch and not using a Data Reduction Proxy.
true, false, false,
},
{
// Lo-Fi enabled through switch and using a Data Reduction Proxy.
true, false, true,
},
{
// Lo-Fi enabled through field trial and not using a Data Reduction
// Proxy.
false, true, false,
},
{
// Lo-Fi enabled through field trial and using a Data Reduction Proxy.
false, true, true,
},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
if (tests[i].lofi_switch_enabled) {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kDataReductionProxyLoFi,
switches::kDataReductionProxyLoFiValueAlwaysOn);
}
base::FieldTrialList field_trial_list(nullptr);
if (tests[i].auto_lofi_enabled) {
base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
"Enabled");
}
config()->SetNetworkProhibitivelySlow(tests[i].auto_lofi_enabled);
io_data()->SetLoFiModeActiveOnMainFrame(false);
net::ProxyInfo data_reduction_proxy_info;
std::string proxy;
if (tests[i].is_data_reduction_proxy)
base::TrimString(params()->DefaultOrigin(), "/", &proxy);
else
base::TrimString(kOtherProxy, "/", &proxy);
data_reduction_proxy_info.UseNamedProxy(proxy);
{
// Main frame loaded. Lo-Fi should be used.
net::HttpRequestHeaders headers;
net::ProxyRetryInfoMap proxy_retry_info;
net::TestDelegate delegate;
std::unique_ptr<net::URLRequest> fake_request =
context()->CreateRequest(GURL(kTestURL), net::IDLE, &delegate);
fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
lofi_decider()->SetIsUsingLoFi(
config()->ShouldEnableLoFi(*fake_request.get()));
NotifyNetworkDelegate(fake_request.get(), data_reduction_proxy_info,
proxy_retry_info, &headers);
VerifyHeaders(tests[i].is_data_reduction_proxy, true, headers);
VerifyDataReductionProxyData(
*fake_request, tests[i].is_data_reduction_proxy,
config()->ShouldEnableLoFi(*fake_request.get()));
}
{
// Lo-Fi is already off. Lo-Fi should not be used.
net::HttpRequestHeaders headers;
net::ProxyRetryInfoMap proxy_retry_info;
net::TestDelegate delegate;
std::unique_ptr<net::URLRequest> fake_request =
context()->CreateRequest(GURL(kTestURL), net::IDLE, &delegate);
lofi_decider()->SetIsUsingLoFi(false);
NotifyNetworkDelegate(fake_request.get(), data_reduction_proxy_info,
proxy_retry_info, &headers);
VerifyHeaders(tests[i].is_data_reduction_proxy, false, headers);
VerifyDataReductionProxyData(*fake_request,
tests[i].is_data_reduction_proxy, false);
}
{
// Lo-Fi is already on. Lo-Fi should be used.
net::HttpRequestHeaders headers;
net::ProxyRetryInfoMap proxy_retry_info;
net::TestDelegate delegate;
std::unique_ptr<net::URLRequest> fake_request =
context()->CreateRequest(GURL(kTestURL), net::IDLE, &delegate);
lofi_decider()->SetIsUsingLoFi(true);
NotifyNetworkDelegate(fake_request.get(), data_reduction_proxy_info,
proxy_retry_info, &headers);
VerifyHeaders(tests[i].is_data_reduction_proxy, true, headers);
VerifyDataReductionProxyData(*fake_request,
tests[i].is_data_reduction_proxy, true);
}
{
// Main frame request with Lo-Fi off. Lo-Fi should not be used.
// State of Lo-Fi should persist until next page load.
net::HttpRequestHeaders headers;
net::ProxyRetryInfoMap proxy_retry_info;
net::TestDelegate delegate;
std::unique_ptr<net::URLRequest> fake_request =
context()->CreateRequest(GURL(kTestURL), net::IDLE, &delegate);
fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
lofi_decider()->SetIsUsingLoFi(false);
NotifyNetworkDelegate(fake_request.get(), data_reduction_proxy_info,
proxy_retry_info, &headers);
VerifyHeaders(tests[i].is_data_reduction_proxy, false, headers);
VerifyDataReductionProxyData(*fake_request,
tests[i].is_data_reduction_proxy, false);
}
{
// Lo-Fi is off. Lo-Fi is still not used.
net::HttpRequestHeaders headers;
net::ProxyRetryInfoMap proxy_retry_info;
net::TestDelegate delegate;
std::unique_ptr<net::URLRequest> fake_request =
context()->CreateRequest(GURL(kTestURL), net::IDLE, &delegate);
lofi_decider()->SetIsUsingLoFi(false);
NotifyNetworkDelegate(fake_request.get(), data_reduction_proxy_info,
proxy_retry_info, &headers);
VerifyHeaders(tests[i].is_data_reduction_proxy, false, headers);
VerifyDataReductionProxyData(*fake_request,
tests[i].is_data_reduction_proxy, false);
}
{
// Main frame request. Lo-Fi should be used.
net::HttpRequestHeaders headers;
net::ProxyRetryInfoMap proxy_retry_info;
net::TestDelegate delegate;
std::unique_ptr<net::URLRequest> fake_request =
context()->CreateRequest(GURL(kTestURL), net::IDLE, &delegate);
fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
lofi_decider()->SetIsUsingLoFi(
config()->ShouldEnableLoFi(*fake_request.get()));
NotifyNetworkDelegate(fake_request.get(), data_reduction_proxy_info,
proxy_retry_info, &headers);
VerifyDataReductionProxyData(
*fake_request, tests[i].is_data_reduction_proxy,
config()->ShouldEnableLoFi(*fake_request.get()));
}
}
}
TEST_F(DataReductionProxyNetworkDelegateTest, RequestDataConfigurations) {
Init(USE_INSECURE_PROXY, false);
const struct {
bool lofi_on;
bool used_data_reduction_proxy;
bool main_frame;
} tests[] = {
// Lo-Fi off. Main Frame Request.
{false, true, true},
// Data reduction proxy not used. Main Frame Request.
{false, false, true},
// Data reduction proxy not used, Lo-Fi should not be used. Main Frame
// Request.
{true, false, true},
// Lo-Fi on. Main Frame Request.
{true, true, true},
// Lo-Fi off. Not a Main Frame Request.
{false, true, false},
// Data reduction proxy not used. Not a Main Frame Request.
{false, false, false},
// Data reduction proxy not used, Lo-Fi should not be used. Not a Main
// Frame Request.
{true, false, false},
// Lo-Fi on. Not a Main Frame Request.
{true, true, false},
};
for (const auto& test : tests) {
net::ProxyInfo data_reduction_proxy_info;
std::string data_reduction_proxy;
base::TrimString(params()->DefaultOrigin(), "/", &data_reduction_proxy);
if (test.used_data_reduction_proxy)
data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy);
else
data_reduction_proxy_info.UseNamedProxy("port.of.other.proxy");
// Main frame loaded. Lo-Fi should be used.
net::HttpRequestHeaders headers;
net::ProxyRetryInfoMap proxy_retry_info;
test_network_quality_estimator()->set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
std::unique_ptr<net::URLRequest> request = context()->CreateRequest(
GURL(kTestURL), net::RequestPriority::IDLE, nullptr);
request->SetLoadFlags(test.main_frame ? net::LOAD_MAIN_FRAME_DEPRECATED
: 0);
lofi_decider()->SetIsUsingLoFi(test.lofi_on);
io_data()->request_options()->SetSecureSession("fake-session");
// Call network delegate methods to ensure that appropriate chrome proxy
// headers get added/removed.
network_delegate()->NotifyBeforeStartTransaction(
request.get(),
base::Bind(&DataReductionProxyNetworkDelegateTest::DelegateStageDone,
base::Unretained(this)),
&headers);
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
DataReductionProxyData* data =
DataReductionProxyData::GetData(*request.get());
if (!test.used_data_reduction_proxy) {
EXPECT_FALSE(data);
} else {
EXPECT_TRUE(data);
EXPECT_EQ(test.main_frame ? net::EFFECTIVE_CONNECTION_TYPE_OFFLINE
: net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
data->effective_connection_type());
EXPECT_TRUE(data->used_data_reduction_proxy());
EXPECT_EQ(test.main_frame ? GURL(kTestURL) : GURL(), data->request_url());
EXPECT_EQ(test.main_frame ? "fake-session" : "", data->session_key());
EXPECT_EQ(test.lofi_on, data->lofi_requested());
}
}
}
TEST_F(DataReductionProxyNetworkDelegateTest,
RequestDataHoldbackConfigurations) {
Init(USE_INSECURE_PROXY, false);
const struct {
bool data_reduction_proxy_enabled;
bool used_direct;
} tests[] = {
{
false, true,
},
{
false, false,
},
{
true, false,
},
{
true, true,
},
};
base::FieldTrialList field_trial_list(nullptr);
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
"DataCompressionProxyHoldback", "Enabled"));
for (const auto& test : tests) {
net::ProxyInfo data_reduction_proxy_info;
if (test.used_direct)
data_reduction_proxy_info.UseDirect();
else
data_reduction_proxy_info.UseNamedProxy("some.other.proxy");
config()->UpdateConfigForTesting(test.data_reduction_proxy_enabled, true);
std::unique_ptr<net::URLRequest> request = context()->CreateRequest(
GURL(kTestURL), net::RequestPriority::IDLE, nullptr);
request->set_method("GET");
net::HttpRequestHeaders headers;
net::ProxyRetryInfoMap proxy_retry_info;
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
DataReductionProxyData* data =
DataReductionProxyData::GetData(*request.get());
if (!test.data_reduction_proxy_enabled || !test.used_direct) {
EXPECT_FALSE(data);
} else {
EXPECT_TRUE(data);
EXPECT_TRUE(data->used_data_reduction_proxy());
}
}
}
TEST_F(DataReductionProxyNetworkDelegateTest, RedirectRequestDataCleared) {
Init(USE_INSECURE_PROXY, false);
net::ProxyInfo data_reduction_proxy_info;
std::string data_reduction_proxy;
base::TrimString(params()->DefaultOrigin(), "/", &data_reduction_proxy);
data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy);
// Main frame loaded. Lo-Fi should be used.
net::HttpRequestHeaders headers_original;
net::ProxyRetryInfoMap proxy_retry_info;
test_network_quality_estimator()->set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
std::unique_ptr<net::URLRequest> request = context()->CreateRequest(
GURL(kTestURL), net::RequestPriority::IDLE, nullptr);
request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
lofi_decider()->SetIsUsingLoFi(true);
io_data()->request_options()->SetSecureSession("fake-session");
// Call network delegate methods to ensure that appropriate chrome proxy
// headers get added/removed.
network_delegate()->NotifyBeforeStartTransaction(
request.get(),
base::Bind(&DataReductionProxyNetworkDelegateTest::DelegateStageDone,
base::Unretained(this)),
&headers_original);
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info,
&headers_original);
DataReductionProxyData* data =
DataReductionProxyData::GetData(*request.get());
EXPECT_TRUE(data);
EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE,
data->effective_connection_type());
EXPECT_TRUE(data->used_data_reduction_proxy());
EXPECT_EQ(GURL(kTestURL), data->request_url());
EXPECT_EQ("fake-session", data->session_key());
EXPECT_TRUE(data->lofi_requested());
data_reduction_proxy_info.UseNamedProxy("port.of.other.proxy");
// Simulate a redirect even though the same URL is used. Should clear
// DataReductionProxyData.
network_delegate()->NotifyBeforeRedirect(request.get(), GURL(kTestURL));
data = DataReductionProxyData::GetData(*request.get());
EXPECT_FALSE(data && data->used_data_reduction_proxy());
// Call NotifyBeforeSendHeaders again with different proxy info to check that
// new data isn't added. Use a new set of headers since the redirected HTTP
// jobs do not reuse headers from the previous jobs. Also, call network
// delegate methods to ensure that appropriate chrome proxy headers get
// added/removed.
net::HttpRequestHeaders headers_redirect;
network_delegate()->NotifyBeforeStartTransaction(
request.get(),
base::Bind(&DataReductionProxyNetworkDelegateTest::DelegateStageDone,
base::Unretained(this)),
&headers_redirect);
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info,
&headers_redirect);
data = DataReductionProxyData::GetData(*request.get());
EXPECT_FALSE(data);
}
TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
Init(USE_INSECURE_PROXY, false);
base::HistogramTester histogram_tester;
std::string response_headers =
"HTTP/1.1 200 OK\r\n"
"Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
"Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
"Via: 1.1 Chrome-Compression-Proxy\r\n"
"x-original-content-length: " +
base::Int64ToString(kOriginalContentLength) + "\r\n\r\n";
std::unique_ptr<net::URLRequest> fake_request(FetchURLRequest(
GURL(kTestURL), nullptr, response_headers, kResponseContentLength, 0));
fake_request->SetLoadFlags(fake_request->load_flags() |
net::LOAD_MAIN_FRAME_DEPRECATED);
base::TimeDelta freshness_lifetime =
fake_request->response_info().headers->GetFreshnessLifetimes(
fake_request->response_info().response_time).freshness;
histogram_tester.ExpectUniqueSample(kReceivedValidOCLHistogramName,
kResponseContentLength, 1);
histogram_tester.ExpectUniqueSample(kOriginalValidOCLHistogramName,
kOriginalContentLength, 1);
histogram_tester.ExpectUniqueSample(
kDifferenceValidOCLHistogramName,
kOriginalContentLength - kResponseContentLength, 1);
histogram_tester.ExpectUniqueSample(kReceivedHistogramName,
kResponseContentLength, 1);
histogram_tester.ExpectUniqueSample(kReceivedInsecureHistogramName,
kResponseContentLength, 1);
histogram_tester.ExpectTotalCount(kReceivedSecureHistogramName, 0);
histogram_tester.ExpectTotalCount(kReceivedVideoHistogramName, 0);
histogram_tester.ExpectUniqueSample(kReceivedInsecureHistogramName,
kResponseContentLength, 1);
histogram_tester.ExpectUniqueSample(kOriginalHistogramName,
kOriginalContentLength, 1);
histogram_tester.ExpectUniqueSample(
kDifferenceHistogramName,
kOriginalContentLength - kResponseContentLength, 1);
histogram_tester.ExpectUniqueSample(kFreshnessLifetimeHistogramName,
freshness_lifetime.InSeconds(), 1);
histogram_tester.ExpectUniqueSample(kCacheableHistogramName,
kResponseContentLength, 1);
histogram_tester.ExpectUniqueSample(kCacheable4HoursHistogramName,
kResponseContentLength, 1);
histogram_tester.ExpectUniqueSample(kCacheable24HoursHistogramName,
kResponseContentLength, 1);
// Check Lo-Fi histograms.
const struct {
bool lofi_enabled_through_switch;
bool auto_lofi_enabled;
int expected_count;
} tests[] = {
{
// Lo-Fi disabled.
false, false, 0,
},
{
// Auto Lo-Fi enabled.
// This should populate Lo-Fi content length histogram.
false, true, 1,
},
{
// Lo-Fi enabled through switch.
// This should populate Lo-Fi content length histogram.
true, false, 1,
},
{
// Lo-Fi enabled through switch and Auto Lo-Fi also enabled.
// This should populate Lo-Fi content length histogram.
true, true, 1,
},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
config()->ResetLoFiStatusForTest();
config()->SetNetworkProhibitivelySlow(tests[i].auto_lofi_enabled);
base::FieldTrialList field_trial_list(nullptr);
if (tests[i].auto_lofi_enabled) {
base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
"Enabled");
}
if (tests[i].lofi_enabled_through_switch) {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kDataReductionProxyLoFi,
switches::kDataReductionProxyLoFiValueAlwaysOn);
}
lofi_decider()->SetIsUsingLoFi(
config()->ShouldEnableLoFi(*fake_request.get()));
fake_request = (FetchURLRequest(GURL(kTestURL), nullptr, response_headers,
kResponseContentLength, 0));
fake_request->SetLoadFlags(fake_request->load_flags() |
net::LOAD_MAIN_FRAME_DEPRECATED);
// Histograms are accumulative, so get the sum of all the tests so far.
int expected_count = 0;
for (size_t j = 0; j <= i; ++j)
expected_count += tests[j].expected_count;
if (expected_count == 0) {
histogram_tester.ExpectTotalCount(kReceivedValidOCLLoFiOnHistogramName,
expected_count);
histogram_tester.ExpectTotalCount(kOriginalValidOCLLoFiOnHistogramName,
expected_count);
histogram_tester.ExpectTotalCount(kDifferenceValidOCLLoFiOnHistogramName,
expected_count);
} else {
histogram_tester.ExpectUniqueSample(kReceivedValidOCLLoFiOnHistogramName,
kResponseContentLength,
expected_count);
histogram_tester.ExpectUniqueSample(kOriginalValidOCLLoFiOnHistogramName,
kOriginalContentLength,
expected_count);
histogram_tester.ExpectUniqueSample(
kDifferenceValidOCLLoFiOnHistogramName,
kOriginalContentLength - kResponseContentLength, expected_count);
}
}
}
TEST_F(DataReductionProxyNetworkDelegateTest, NetVideoHistograms) {
Init(USE_INSECURE_PROXY, false);
base::HistogramTester histogram_tester;
// Check video
std::string video_response_headers =
"HTTP/1.1 200 OK\r\n"
"Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
"Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
"Content-Type: video/mp4\r\n"
"Via: 1.1 Chrome-Compression-Proxy\r\n"
"x-original-content-length: " +
base::Int64ToString(kOriginalContentLength) + "\r\n\r\n";
FetchURLRequest(GURL(kTestURL), nullptr, video_response_headers,
kResponseContentLength, 0);
histogram_tester.ExpectUniqueSample(kReceivedInsecureHistogramName,
kResponseContentLength, 1);
histogram_tester.ExpectTotalCount(kReceivedSecureHistogramName, 0);
histogram_tester.ExpectUniqueSample(kReceivedVideoHistogramName,
kResponseContentLength, 1);
}
TEST_F(DataReductionProxyNetworkDelegateTest, NetSSLHistograms) {
Init(BYPASS_PROXY, false);
base::HistogramTester histogram_tester;
// Check https
std::string secure_response_headers =
"HTTP/1.1 200 OK\r\n"
"Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
"Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
"Via: 1.1 Chrome-Compression-Proxy\r\n"
"x-original-content-length: " +
base::Int64ToString(kOriginalContentLength) + "\r\n\r\n";
mock_socket_factory()->AddSSLSocketDataProvider(ssl_socket_data_provider());
FetchURLRequest(GURL(kSecureTestURL), nullptr, secure_response_headers,
kResponseContentLength, 0);
histogram_tester.ExpectTotalCount(kReceivedInsecureHistogramName, 0);
histogram_tester.ExpectUniqueSample(kReceivedSecureHistogramName,
kResponseContentLength, 1);
histogram_tester.ExpectTotalCount(kReceivedVideoHistogramName, 0);
}
TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedInternalLoFi) {
Init(USE_INSECURE_PROXY, false);
// Enable Lo-Fi.
const struct {
bool lofi_response;
} tests[] = {
{false}, {true},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
std::string response_headers =
"HTTP/1.1 200 OK\r\n"
"Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
"Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
"Via: 1.1 Chrome-Compression-Proxy\r\n"
"x-original-content-length: 200\r\n";
if (tests[i].lofi_response)
response_headers += "Chrome-Proxy-Content-Transform: empty-image\r\n";
response_headers += "\r\n";
auto request =
FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0);
EXPECT_EQ(tests[i].lofi_response,
DataReductionProxyData::GetData(*request)->lofi_received());
VerifyDidNotifyLoFiResponse(tests[i].lofi_response);
}
}
TEST_F(DataReductionProxyNetworkDelegateTest,
TestLoFiTransformationTypeHistogram) {
Init(USE_INSECURE_PROXY, false);
const char kLoFiTransformationTypeHistogram[] =
"DataReductionProxy.LoFi.TransformationType";
base::HistogramTester histogram_tester;
net::HttpRequestHeaders request_headers;
request_headers.SetHeader("chrome-proxy-accept-transform", "lite-page");
lofi_decider()->ignore_is_using_data_reduction_proxy_check();
FetchURLRequest(GURL(kTestURL), &request_headers, std::string(), 140, 0);
histogram_tester.ExpectBucketCount(kLoFiTransformationTypeHistogram,
NO_TRANSFORMATION_LITE_PAGE_REQUESTED, 1);
std::string response_headers =
"HTTP/1.1 200 OK\r\n"
"Chrome-Proxy-Content-Transform: lite-page\r\n"
"Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
"Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
"Via: 1.1 Chrome-Compression-Proxy\r\n"
"x-original-content-length: 200\r\n";
response_headers += "\r\n";
auto request =
FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0);
EXPECT_TRUE(DataReductionProxyData::GetData(*request)->lite_page_received());
histogram_tester.ExpectBucketCount(kLoFiTransformationTypeHistogram,
LITE_PAGE, 1);
}
// Test that Brotli is not added to the accept-encoding header when it is
// disabled globally.
TEST_F(DataReductionProxyNetworkDelegateTest,
BrotliAdvertisement_BrotliDisabled) {
Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
ReadBrotliFile();
std::string response_headers =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 140\r\n"
"Via: 1.1 Chrome-Compression-Proxy\r\n"
"x-original-content-length: 200\r\n"
"Cache-Control: max-age=1200\r\n"
"Vary: accept-encoding\r\n";
response_headers += "\r\n";
// Use secure sockets when fetching the request since Brotli is only enabled
// for secure connections.
FetchURLRequestAndVerifyBrotli(nullptr, response_headers, false, false);
}
// Test that Brotli is not added to the accept-encoding header when the request
// is fetched from an insecure proxy.
TEST_F(DataReductionProxyNetworkDelegateTest,
BrotliAdvertisementInsecureProxy) {
Init(USE_INSECURE_PROXY, true /* enable_brotli_globally */);
std::string response_headers =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 140\r\n"
"Via: 1.1 Chrome-Compression-Proxy\r\n"
"x-original-content-length: 200\r\n"
"Cache-Control: max-age=1200\r\n"
"Vary: accept-encoding\r\n";
response_headers += "\r\n";
// Use secure sockets when fetching the request since Brotli is only enabled
// for secure connections.
std::unique_ptr<net::URLRequest> request(
FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0));
EXPECT_EQ(140, request->received_response_content_length());
EXPECT_NE(0, request->GetTotalSentBytes());
EXPECT_NE(0, request->GetTotalReceivedBytes());
EXPECT_FALSE(request->was_cached());
// Brotli should be added to Accept Encoding header only if secure proxy is in
VerifyBrotliPresent(request.get(), false);
}
// Test that Brotli is not added to the accept-encoding header when it is
// disabled via data reduction proxy field trial.
TEST_F(DataReductionProxyNetworkDelegateTest,
BrotliAdvertisementDisabledViaFieldTrial) {
Init(USE_SECURE_PROXY, true /* enable_brotli_globally */);
base::FieldTrialList field_trial_list(nullptr);
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
"DataReductionProxyBrotliAcceptEncoding", "Disabled"));
std::string response_headers =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 140\r\n"
"Via: 1.1 Chrome-Compression-Proxy\r\n"
"x-original-content-length: 200\r\n"
"Cache-Control: max-age=1200\r\n"
"Vary: accept-encoding\r\n";
response_headers += "\r\n";
FetchURLRequestAndVerifyBrotli(nullptr, response_headers, false, false);
FetchURLRequestAndVerifyBrotli(nullptr, response_headers, true, false);
}
// Test that Brotli is correctly added to the accept-encoding header when it is
// enabled globally.
TEST_F(DataReductionProxyNetworkDelegateTest, BrotliAdvertisement) {
Init(USE_SECURE_PROXY, true /* enable_brotli_globally */);
std::string response_headers =
"HTTP/1.1 200 OK\r\n"
"Via: 1.1 Chrome-Compression-Proxy\r\n"
"x-original-content-length: 200\r\n"
"Cache-Control: max-age=1200\r\n"
"Content-Encoding: br\r\n"
"Vary: accept-encoding\r\n";
response_headers += "\r\n";
FetchURLRequestAndVerifyBrotli(nullptr, response_headers, false, true);
FetchURLRequestAndVerifyBrotli(nullptr, response_headers, true, true);
}
TEST_F(DataReductionProxyNetworkDelegateTest, IncrementingMainFramePageId) {
// This is unaffacted by brotil and insecure proxy.
Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
io_data()->request_options()->SetSecureSession("new-session");
FetchURLRequestAndVerifyPageIdDirective("pid=1", false);
FetchURLRequestAndVerifyPageIdDirective("pid=2", false);
FetchURLRequestAndVerifyPageIdDirective("pid=3", false);
}
TEST_F(DataReductionProxyNetworkDelegateTest, ResetSessionResetsId) {
// This is unaffacted by brotil and insecure proxy.
Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
io_data()->request_options()->SetSecureSession("new-session");
FetchURLRequestAndVerifyPageIdDirective("pid=1", false);
io_data()->request_options()->SetSecureSession("new-session-2");
FetchURLRequestAndVerifyPageIdDirective("pid=1", false);
}
TEST_F(DataReductionProxyNetworkDelegateTest, SubResourceNoPageId) {
// This is unaffacted by brotil and insecure proxy.
Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
io_data()->request_options()->SetSecureSession("new-session");
FetchURLRequestAndVerifyPageIdDirective(std::string(), false);
}
TEST_F(DataReductionProxyNetworkDelegateTest, RedirectSharePid) {
// This is unaffacted by brotil and insecure proxy.
Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
io_data()->request_options()->SetSecureSession("new-session");
FetchURLRequestAndVerifyPageIdDirective("pid=1", true);
}
TEST_F(DataReductionProxyNetworkDelegateTest,
SessionChangeResetsPageIDOnRedirect) {
// This test calls directly into network delegate as it is difficult to mock
// state changing in between redirects within an URLRequest's lifetime.
// This is unaffacted by brotil and insecure proxy.
Init(USE_INSECURE_PROXY, false /* enable_brotli_globally */);
net::ProxyInfo data_reduction_proxy_info;
std::string data_reduction_proxy;
base::TrimString(params()->DefaultOrigin(), "/", &data_reduction_proxy);
data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy);
std::unique_ptr<net::URLRequest> request = context()->CreateRequest(
GURL(kTestURL), net::RequestPriority::IDLE, nullptr);
request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
io_data()->request_options()->SetSecureSession("fake-session");
net::HttpRequestHeaders headers;
net::ProxyRetryInfoMap proxy_retry_info;
// Send a request and verify the page ID is 1.
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
DataReductionProxyData* data =
DataReductionProxyData::GetData(*request.get());
EXPECT_TRUE(data_reduction_proxy_info.is_http());
EXPECT_EQ(1u, data->page_id().value());
// Send a second request and verify the page ID incremements.
request = context()->CreateRequest(GURL(kTestURL), net::RequestPriority::IDLE,
nullptr);
request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
data = DataReductionProxyData::GetData(*request.get());
EXPECT_EQ(2u, data->page_id().value());
// Verify that redirects are the same page ID.
network_delegate()->NotifyBeforeRedirect(request.get(), GURL(kTestURL));
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
data = DataReductionProxyData::GetData(*request.get());
EXPECT_EQ(2u, data->page_id().value());
// Verify that redirects into a new session get a new page ID.
network_delegate()->NotifyBeforeRedirect(request.get(), GURL(kTestURL));
io_data()->request_options()->SetSecureSession("new-session");
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
data = DataReductionProxyData::GetData(*request.get());
EXPECT_EQ(1u, data->page_id().value());
}
} // namespace
} // namespace data_reduction_proxy