1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_protocol.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/run_loop.h"
13 #include "base/strings/stringprintf.h"
14 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h"
15 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats.h"
16 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
17 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers_test_utils.h"
18 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
19 #include "net/base/completion_callback.h"
20 #include "net/base/host_port_pair.h"
21 #include "net/base/load_flags.h"
22 #include "net/base/network_delegate.h"
23 #include "net/http/http_response_headers.h"
24 #include "net/http/http_transaction_test_util.h"
25 #include "net/proxy/proxy_service.h"
26 #include "net/socket/socket_test_util.h"
27 #include "net/url_request/static_http_user_agent_settings.h"
28 #include "net/url_request/url_request.h"
29 #include "net/url_request/url_request_context.h"
30 #include "net/url_request/url_request_filter.h"
31 #include "net/url_request/url_request_http_job.h"
32 #include "net/url_request/url_request_intercepting_job_factory.h"
33 #include "net/url_request/url_request_interceptor.h"
34 #include "net/url_request/url_request_job_factory.h"
35 #include "net/url_request/url_request_job_factory_impl.h"
36 #include "net/url_request/url_request_test_util.h"
37 #include "testing/gtest/include/gtest/gtest.h"
40 using net::HttpResponseHeaders;
41 using net::HostPortPair;
44 using net::ProxyRetryInfoMap;
45 using net::ProxyService;
46 using net::StaticSocketDataProvider;
47 using net::TestDelegate;
48 using net::URLRequest;
49 using net::TestURLRequestContext;
52 namespace data_reduction_proxy {
54 class SimpleURLRequestInterceptor : public net::URLRequestInterceptor {
56 net::URLRequestJob* MaybeInterceptRequest(
57 net::URLRequest* request,
58 net::NetworkDelegate* network_delegate) const override {
59 return net::URLRequestHttpJob::Factory(request, network_delegate, "http");
63 // Constructs a |TestURLRequestContext| that uses a |MockSocketFactory| to
64 // simulate requests and responses.
65 class DataReductionProxyProtocolTest : public testing::Test {
67 DataReductionProxyProtocolTest() : http_user_agent_settings_("", "") {
69 new TestDataReductionProxyParams(
70 DataReductionProxyParams::kAllowed |
71 DataReductionProxyParams::kFallbackAllowed |
72 DataReductionProxyParams::kPromoAllowed,
73 TestDataReductionProxyParams::HAS_EVERYTHING &
74 ~TestDataReductionProxyParams::HAS_DEV_ORIGIN &
75 ~TestDataReductionProxyParams::HAS_DEV_FALLBACK_ORIGIN));
76 simple_interceptor_.reset(new SimpleURLRequestInterceptor());
77 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
78 "http", "www.google.com", simple_interceptor_.Pass());
80 ~DataReductionProxyProtocolTest() override {
81 // URLRequestJobs may post clean-up tasks on destruction.
82 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(
83 "http", "www.google.com");
84 base::RunLoop().RunUntilIdle();
87 // Sets up the |TestURLRequestContext| with the provided |ProxyService| and
88 // |bypass_type| to store bypass reasons.
89 void ConfigureTestDependencies(ProxyService* proxy_service,
90 DataReductionProxyBypassType* bypass_type) {
91 // Create a context with delayed initialization.
92 context_.reset(new TestURLRequestContext(true));
94 proxy_service_.reset(proxy_service);
95 context_->set_client_socket_factory(&mock_socket_factory_);
96 context_->set_proxy_service(proxy_service_.get());
97 network_delegate_.reset(new net::TestNetworkDelegate());
98 context_->set_network_delegate(network_delegate_.get());
99 // This is needed to prevent the test context from adding language headers
101 context_->set_http_user_agent_settings(&http_user_agent_settings_);
102 usage_stats_.reset(new DataReductionProxyUsageStats(
103 proxy_params_.get(), base::MessageLoopProxy::current()));
104 DataReductionProxyInterceptor* interceptor =
105 new DataReductionProxyInterceptor(proxy_params_.get(),
108 scoped_ptr<net::URLRequestJobFactoryImpl> job_factory_impl(
109 new net::URLRequestJobFactoryImpl());
111 new net::URLRequestInterceptingJobFactory(
112 job_factory_impl.Pass(),
113 make_scoped_ptr(interceptor)));
114 context_->set_job_factory(job_factory_.get());
118 // Simulates a request to a data reduction proxy that may result in bypassing
119 // the proxy and retrying the the request.
120 // Runs a test with the given request |method| that expects the first response
121 // from the server to be |first_response|. If |expected_retry|, the test
122 // will expect a retry of the request. A response body will be expected
123 // if |expect_response_body|.
124 void TestProxyFallback(const char* method,
125 const char* first_response,
128 size_t expected_bad_proxy_count,
129 bool expect_response_body) {
130 std::string payload1 =
131 (expected_retry ? "Bypass message" : "content");
132 MockRead data_reads[] = {
133 MockRead(first_response),
134 MockRead(payload1.c_str()),
135 MockRead(net::SYNCHRONOUS, net::OK),
137 std::string origin = has_origin ? "Origin: foo.com\r\n" : "";
139 std::string m(method);
140 std::string trailer =
141 (m == "HEAD" || m == "PUT" || m == "POST") ?
142 "Content-Length: 0\r\n" : "";
144 std::string request1 =
145 base::StringPrintf("%s http://www.google.com/ HTTP/1.1\r\n"
146 "Host: www.google.com\r\n"
147 "Proxy-Connection: keep-alive\r\n%s%s"
149 "Accept-Encoding: gzip, deflate\r\n\r\n",
150 method, origin.c_str(), trailer.c_str());
151 MockWrite data_writes[] = {
152 MockWrite(request1.c_str()),
154 StaticSocketDataProvider data1(data_reads, arraysize(data_reads),
155 data_writes, arraysize(data_writes));
156 mock_socket_factory_.AddSocketDataProvider(&data1);
158 std::string response2;
159 std::string request2;
160 if (expected_bad_proxy_count >= 2u ||
161 (m != "POST" && expected_retry && expected_bad_proxy_count == 0u)) {
163 "HTTP/1.0 200 OK\r\n"
164 "Server: not-proxy\r\n\r\n";
165 request2 = base::StringPrintf(
167 "Host: www.google.com\r\n"
168 "Connection: keep-alive\r\n%s%s"
170 "Accept-Encoding: gzip, deflate\r\n\r\n",
171 method, origin.c_str(), trailer.c_str());
172 } else if (expected_bad_proxy_count <= 1u) {
174 "HTTP/1.0 200 OK\r\n"
175 "Server: not-proxy\r\n"
176 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n";
177 request2 = base::StringPrintf(
178 "%s http://www.google.com/ HTTP/1.1\r\n"
179 "Host: www.google.com\r\n"
180 "Proxy-Connection: keep-alive\r\n%s%s"
182 "Accept-Encoding: gzip, deflate\r\n\r\n",
183 method, origin.c_str(), trailer.c_str());
185 MockRead data_reads2[] = {
186 MockRead(response2.c_str()),
188 MockRead(net::SYNCHRONOUS, net::OK),
190 MockWrite data_writes2[] = {
191 MockWrite(request2.c_str()),
193 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
194 data_writes2, arraysize(data_writes2));
195 if (expected_retry) {
196 mock_socket_factory_.AddSocketDataProvider(&data2);
199 // Expect that we get "content" and not "Bypass message", and that there's
200 // a "not-proxy" "Server:" header in the final response.
201 ExecuteRequestExpectingContentAndHeader(
203 (expect_response_body ? "content" : ""),
205 (expected_retry == 0 ? "proxy" : "not-proxy"),
210 // Starts a request with the given |method| and checks that the response
211 // contains |content| and the the header |header|: |value|, if |header| is
212 // non-empty. Verifies that the request's URL chain is the right length
213 // depending on whether or not a retry was expected (|expected_retry|).
214 void ExecuteRequestExpectingContentAndHeader(const std::string& method,
215 const std::string& content,
216 const std::string& header,
217 const std::string& value,
219 bool expected_retry) {
221 scoped_ptr<URLRequest> r(context_->CreateRequest(
222 GURL("http://www.google.com/"),
223 net::DEFAULT_PRIORITY,
226 r->set_method(method);
227 r->SetLoadFlags(net::LOAD_NORMAL);
229 r->SetExtraRequestHeaderByName("Origin", "foo.com", true);
232 base::RunLoop().Run();
234 EXPECT_EQ(net::URLRequestStatus::SUCCESS, r->status().status());
235 EXPECT_EQ(net::OK, r->status().error());
237 EXPECT_EQ(2, network_delegate_->headers_received_count());
239 EXPECT_EQ(1, network_delegate_->headers_received_count());
241 if (!header.empty()) {
242 // We also have a server header here that isn't set by the proxy.
243 EXPECT_TRUE(r->response_headers()->HasHeaderValue(header, value));
246 EXPECT_EQ(content, d.data_received());
249 // Returns the key to the |ProxyRetryInfoMap|.
250 std::string GetProxyKey(std::string proxy) {
252 std::string host_port = HostPortPair::FromURL(GURL(proxy)).ToString();
253 if (gurl.SchemeIs("https"))
254 return "https://" + host_port;
258 // Checks that |expected_num_bad_proxies| proxies are on the proxy retry list.
259 // If the list has one proxy, it should match |bad_proxy|. If it has two
260 // proxies, it should match |bad_proxy| and |bad_proxy2|. Checks also that
261 // the current delay associated with each bad proxy is |duration_seconds|.
262 void TestBadProxies(unsigned int expected_num_bad_proxies,
263 int duration_seconds,
264 const std::string& bad_proxy,
265 const std::string& bad_proxy2) {
266 const ProxyRetryInfoMap& retry_info = proxy_service_->proxy_retry_info();
267 ASSERT_EQ(expected_num_bad_proxies, retry_info.size());
269 base::TimeDelta expected_min_duration;
270 base::TimeDelta expected_max_duration;
271 if (duration_seconds == 0) {
272 expected_min_duration = base::TimeDelta::FromMinutes(1);
273 expected_max_duration = base::TimeDelta::FromMinutes(5);
275 expected_min_duration = base::TimeDelta::FromSeconds(duration_seconds);
276 expected_max_duration = base::TimeDelta::FromSeconds(duration_seconds);
279 if (expected_num_bad_proxies >= 1u) {
280 ProxyRetryInfoMap::const_iterator i =
281 retry_info.find(GetProxyKey(bad_proxy));
282 ASSERT_TRUE(i != retry_info.end());
283 EXPECT_TRUE(expected_min_duration <= (*i).second.current_delay);
284 EXPECT_TRUE((*i).second.current_delay <= expected_max_duration);
286 if (expected_num_bad_proxies == 2u) {
287 ProxyRetryInfoMap::const_iterator i =
288 retry_info.find(GetProxyKey(bad_proxy2));
289 ASSERT_TRUE(i != retry_info.end());
290 EXPECT_TRUE(expected_min_duration <= (*i).second.current_delay);
291 EXPECT_TRUE((*i).second.current_delay <= expected_max_duration);
296 base::MessageLoopForIO loop_;
298 scoped_ptr<net::URLRequestInterceptor> simple_interceptor_;
299 net::MockClientSocketFactory mock_socket_factory_;
300 scoped_ptr<net::TestNetworkDelegate> network_delegate_;
301 scoped_ptr<ProxyService> proxy_service_;
302 scoped_ptr<TestDataReductionProxyParams> proxy_params_;
303 scoped_ptr<DataReductionProxyUsageStats> usage_stats_;
304 net::StaticHttpUserAgentSettings http_user_agent_settings_;
306 scoped_ptr<net::URLRequestInterceptingJobFactory> job_factory_;
307 scoped_ptr<TestURLRequestContext> context_;
310 // Tests that request are deemed idempotent or not according to the method used.
311 TEST_F(DataReductionProxyProtocolTest, TestIdempotency) {
312 net::TestURLRequestContext context;
315 bool expected_result;
324 { "CONNECT", false },
326 for (size_t i = 0; i < arraysize(tests); ++i) {
327 scoped_ptr<net::URLRequest> request(
328 context.CreateRequest(GURL("http://www.google.com/"),
329 net::DEFAULT_PRIORITY,
332 request->set_method(tests[i].method);
333 EXPECT_EQ(tests[i].expected_result, IsRequestIdempotent(request.get()));
337 // After each test, the proxy retry info will contain zero, one, or two of the
338 // data reduction proxies depending on whether no bypass was indicated by the
339 // initial response, a single proxy bypass was indicated, or a double bypass
340 // was indicated. In both the single and double bypass cases, if the request
341 // was idempotent, it will be retried over a direct connection.
342 TEST_F(DataReductionProxyProtocolTest, BypassLogic) {
345 const char* first_response;
348 size_t expected_bad_proxy_count;
349 bool expect_response_body;
350 int expected_duration;
351 DataReductionProxyBypassType expected_bypass_type;
353 // Valid data reduction proxy response with no bypass message.
355 "HTTP/1.1 200 OK\r\n"
357 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
363 BYPASS_EVENT_TYPE_MAX,
365 // Valid data reduction proxy response with older, but still valid via
368 "HTTP/1.1 200 OK\r\n"
370 "Via: 1.1 Chrome Compression Proxy\r\n\r\n",
376 BYPASS_EVENT_TYPE_MAX
378 // Valid data reduction proxy response with chained via header,
379 // no bypass message.
381 "HTTP/1.1 200 OK\r\n"
383 "Via: 1.1 Chrome-Compression-Proxy, 1.0 some-other-proxy\r\n\r\n",
389 BYPASS_EVENT_TYPE_MAX
391 // Valid data reduction proxy response with a bypass message.
393 "HTTP/1.1 200 OK\r\n"
395 "Chrome-Proxy: bypass=0\r\n"
396 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
402 BYPASS_EVENT_TYPE_MEDIUM
404 // Valid data reduction proxy response with a bypass message.
406 "HTTP/1.1 200 OK\r\n"
408 "Chrome-Proxy: bypass=1\r\n"
409 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
415 BYPASS_EVENT_TYPE_SHORT
417 // Same as above with the OPTIONS method, which is idempotent.
419 "HTTP/1.1 200 OK\r\n"
421 "Chrome-Proxy: bypass=0\r\n"
422 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
428 BYPASS_EVENT_TYPE_MEDIUM
430 // Same as above with the HEAD method, which is idempotent.
432 "HTTP/1.1 200 OK\r\n"
434 "Chrome-Proxy: bypass=0\r\n"
435 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
441 BYPASS_EVENT_TYPE_MEDIUM
443 // Same as above with the PUT method, which is idempotent.
445 "HTTP/1.1 200 OK\r\n"
447 "Chrome-Proxy: bypass=0\r\n"
448 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
454 BYPASS_EVENT_TYPE_MEDIUM
456 // Same as above with the DELETE method, which is idempotent.
458 "HTTP/1.1 200 OK\r\n"
460 "Chrome-Proxy: bypass=0\r\n"
461 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
467 BYPASS_EVENT_TYPE_MEDIUM
469 // Same as above with the TRACE method, which is idempotent.
471 "HTTP/1.1 200 OK\r\n"
473 "Chrome-Proxy: bypass=0\r\n"
474 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
480 BYPASS_EVENT_TYPE_MEDIUM
482 // 500 responses should be bypassed.
484 "HTTP/1.1 500 Internal Server Error\r\n"
486 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
492 BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR
494 // 502 responses should be bypassed.
496 "HTTP/1.1 502 Internal Server Error\r\n"
498 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
504 BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY
506 // 503 responses should be bypassed.
508 "HTTP/1.1 503 Internal Server Error\r\n"
510 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
516 BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE
518 // Invalid data reduction proxy 4xx response. Missing Via header.
520 "HTTP/1.1 404 Not Found\r\n"
521 "Server: proxy\r\n\r\n",
527 BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX
529 // Invalid data reduction proxy response. Missing Via header.
531 "HTTP/1.1 200 OK\r\n"
532 "Server: proxy\r\n\r\n",
538 BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER
540 // Invalid data reduction proxy response. Wrong Via header.
542 "HTTP/1.1 200 OK\r\n"
544 "Via: 1.0 some-other-proxy\r\n\r\n",
550 BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER
552 // Valid data reduction proxy response. 304 missing Via header.
554 "HTTP/1.1 304 Not Modified\r\n"
555 "Server: proxy\r\n\r\n",
561 BYPASS_EVENT_TYPE_MAX
563 // Valid data reduction proxy response with a bypass message. It will
564 // not be retried because the request is non-idempotent.
566 "HTTP/1.1 200 OK\r\n"
568 "Chrome-Proxy: bypass=0\r\n"
569 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
575 BYPASS_EVENT_TYPE_MEDIUM
577 // Valid data reduction proxy response with block message. Both proxies
578 // should be on the retry list when it completes.
580 "HTTP/1.1 200 OK\r\n"
582 "Chrome-Proxy: block=1\r\n"
583 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
589 BYPASS_EVENT_TYPE_SHORT
591 // Valid data reduction proxy response with a block-once message. It will be
592 // retried, and there will be no proxies on the retry list since block-once
593 // only affects the current request.
595 "HTTP/1.1 200 OK\r\n"
597 "Chrome-Proxy: block-once\r\n"
598 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
604 BYPASS_EVENT_TYPE_CURRENT
606 // Same as above with the OPTIONS method, which is idempotent.
608 "HTTP/1.1 200 OK\r\n"
610 "Chrome-Proxy: block-once\r\n"
611 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
617 BYPASS_EVENT_TYPE_CURRENT
619 // Same as above with the HEAD method, which is idempotent.
621 "HTTP/1.1 200 OK\r\n"
623 "Chrome-Proxy: block-once\r\n"
624 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
630 BYPASS_EVENT_TYPE_CURRENT
632 // Same as above with the PUT method, which is idempotent.
634 "HTTP/1.1 200 OK\r\n"
636 "Chrome-Proxy: block-once\r\n"
637 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
643 BYPASS_EVENT_TYPE_CURRENT
645 // Same as above with the DELETE method, which is idempotent.
647 "HTTP/1.1 200 OK\r\n"
649 "Chrome-Proxy: block-once\r\n"
650 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
656 BYPASS_EVENT_TYPE_CURRENT
658 // Same as above with the TRACE method, which is idempotent.
660 "HTTP/1.1 200 OK\r\n"
662 "Chrome-Proxy: block-once\r\n"
663 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
669 BYPASS_EVENT_TYPE_CURRENT
671 // Valid data reduction proxy response with a block-once message. It will
672 // not be retried because the request is non-idempotent, and there will be
673 // no proxies on the retry list since block-once only affects the current
676 "HTTP/1.1 200 OK\r\n"
678 "Chrome-Proxy: block-once\r\n"
679 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
685 BYPASS_EVENT_TYPE_CURRENT
687 // Valid data reduction proxy response with block and block-once messages.
688 // The block message will override the block-once message, so both proxies
689 // should be on the retry list when it completes.
691 "HTTP/1.1 200 OK\r\n"
693 "Chrome-Proxy: block=1, block-once\r\n"
694 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
700 BYPASS_EVENT_TYPE_SHORT
702 // Valid data reduction proxy response with bypass and block-once messages.
703 // The bypass message will override the block-once message, so one proxy
704 // should be on the retry list when it completes.
706 "HTTP/1.1 200 OK\r\n"
708 "Chrome-Proxy: bypass=1, block-once\r\n"
709 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
715 BYPASS_EVENT_TYPE_SHORT
718 std::string primary = proxy_params_->DefaultOrigin();
719 std::string fallback = proxy_params_->DefaultFallbackOrigin();
720 for (size_t i = 0; i < arraysize(tests); ++i) {
721 DataReductionProxyBypassType bypass_type;
722 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
724 HostPortPair::FromURL(GURL(primary)).ToString() + "; PROXY " +
725 HostPortPair::FromURL(GURL(fallback)).ToString() + "; DIRECT"),
727 TestProxyFallback(tests[i].method,
728 tests[i].first_response,
730 tests[i].expected_retry,
731 tests[i].expected_bad_proxy_count,
732 tests[i].expect_response_body);
733 EXPECT_EQ(tests[i].expected_bypass_type, usage_stats_->GetBypassType());
734 // We should also observe the bad proxy in the retry list.
735 TestBadProxies(tests[i].expected_bad_proxy_count,
736 tests[i].expected_duration,
741 TEST_F(DataReductionProxyProtocolTest,
742 ProxyBypassIgnoredOnDirectConnection) {
743 // Verify that a Chrome-Proxy header is ignored when returned from a directly
744 // connected origin server.
745 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult("DIRECT"),
748 MockRead data_reads[] = {
749 MockRead("HTTP/1.1 200 OK\r\n"
750 "Chrome-Proxy: bypass=0\r\n\r\n"),
751 MockRead("Bypass message"),
752 MockRead(net::SYNCHRONOUS, net::OK),
754 MockWrite data_writes[] = {
755 MockWrite("GET / HTTP/1.1\r\n"
756 "Host: www.google.com\r\n"
757 "Connection: keep-alive\r\n"
759 "Accept-Encoding: gzip, deflate\r\n\r\n"),
761 StaticSocketDataProvider data1(data_reads, arraysize(data_reads),
762 data_writes, arraysize(data_writes));
763 mock_socket_factory_.AddSocketDataProvider(&data1);
766 scoped_ptr<URLRequest> r(context_->CreateRequest(
767 GURL("http://www.google.com/"),
768 net::DEFAULT_PRIORITY,
771 r->set_method("GET");
772 r->SetLoadFlags(net::LOAD_NORMAL);
775 base::RunLoop().Run();
777 EXPECT_EQ(net::URLRequestStatus::SUCCESS, r->status().status());
778 EXPECT_EQ(net::OK, r->status().error());
780 EXPECT_EQ("Bypass message", d.data_received());
782 // We should have no entries in our bad proxy list.
783 TestBadProxies(0, -1, "", "");
786 class BadEntropyProvider : public base::FieldTrial::EntropyProvider {
788 ~BadEntropyProvider() override {}
790 double GetEntropyForTrial(const std::string& trial_name,
791 uint32 randomization_seed) const override {
796 TEST_F(DataReductionProxyProtocolTest, OnResolveProxyHandler) {
797 int load_flags = net::LOAD_NORMAL;
798 GURL url("http://www.google.com/");
799 net::ProxyConfig proxy_config_direct = net::ProxyConfig::CreateDirect();
801 TestDataReductionProxyParams test_params(
802 DataReductionProxyParams::kAllowed |
803 DataReductionProxyParams::kFallbackAllowed |
804 DataReductionProxyParams::kPromoAllowed,
805 TestDataReductionProxyParams::HAS_EVERYTHING &
806 ~TestDataReductionProxyParams::HAS_DEV_ORIGIN &
807 ~TestDataReductionProxyParams::HAS_DEV_FALLBACK_ORIGIN);
809 // Data reduction proxy info
810 net::ProxyInfo data_reduction_proxy_info;
811 std::string data_reduction_proxy;
812 base::TrimString(test_params.DefaultOrigin(), "/", &data_reduction_proxy);
813 data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy);
814 EXPECT_FALSE(data_reduction_proxy_info.is_empty());
816 // Data reduction proxy config
817 net::ProxyConfig data_reduction_proxy_config;
818 data_reduction_proxy_config.proxy_rules().ParseFromString(
819 "http=" + data_reduction_proxy + ",direct://;");
820 data_reduction_proxy_config.set_id(1);
823 net::ProxyInfo other_proxy_info;
824 other_proxy_info.UseNamedProxy("proxy.com");
825 EXPECT_FALSE(other_proxy_info.is_empty());
828 net::ProxyInfo direct_proxy_info;
829 direct_proxy_info.UseDirect();
830 EXPECT_TRUE(direct_proxy_info.is_direct());
832 // Empty retry info map
833 net::ProxyRetryInfoMap empty_proxy_retry_info;
835 // Retry info map with the data reduction proxy;
836 net::ProxyRetryInfoMap data_reduction_proxy_retry_info;
837 net::ProxyRetryInfo retry_info;
838 retry_info.current_delay = base::TimeDelta::FromSeconds(1000);
839 retry_info.bad_until = base::TimeTicks().Now() + retry_info.current_delay;
840 retry_info.try_while_bad = false;
841 data_reduction_proxy_retry_info[
842 data_reduction_proxy_info.proxy_server().ToURI()] = retry_info;
844 net::ProxyInfo result;
846 // The data reduction proxy is used. It should be used afterwards.
847 result.Use(data_reduction_proxy_info);
848 OnResolveProxyHandler(url, load_flags, data_reduction_proxy_config,
849 proxy_config_direct, empty_proxy_retry_info,
850 &test_params, &result);
851 EXPECT_EQ(data_reduction_proxy_info.proxy_server(), result.proxy_server());
853 // Another proxy is used. It should be used afterwards.
854 result.Use(other_proxy_info);
855 OnResolveProxyHandler(url, load_flags, data_reduction_proxy_config,
856 proxy_config_direct, empty_proxy_retry_info,
857 &test_params, &result);
858 EXPECT_EQ(other_proxy_info.proxy_server(), result.proxy_server());
860 // A direct connection is used. The data reduction proxy should be used
862 // Another proxy is used. It should be used afterwards.
863 result.Use(direct_proxy_info);
864 net::ProxyConfig::ID prev_id = result.config_id();
865 OnResolveProxyHandler(url, load_flags, data_reduction_proxy_config,
866 proxy_config_direct, empty_proxy_retry_info,
867 &test_params, &result);
868 EXPECT_EQ(data_reduction_proxy_info.proxy_server(), result.proxy_server());
869 // Only the proxy list should be updated, not he proxy info.
870 EXPECT_EQ(result.config_id(), prev_id);
872 // A direct connection is used, but the data reduction proxy is on the retry
873 // list. A direct connection should be used afterwards.
874 result.Use(direct_proxy_info);
875 prev_id = result.config_id();
876 OnResolveProxyHandler(url, load_flags, data_reduction_proxy_config,
877 proxy_config_direct, data_reduction_proxy_retry_info,
878 &test_params, &result);
879 EXPECT_TRUE(result.proxy_server().is_direct());
880 EXPECT_EQ(result.config_id(), prev_id);
883 // Without DataCompressionProxyCriticalBypass Finch trial set, should never
885 OnResolveProxyHandler(url, load_flags, data_reduction_proxy_config,
886 proxy_config_direct, empty_proxy_retry_info,
887 &test_params, &data_reduction_proxy_info);
888 EXPECT_FALSE(data_reduction_proxy_info.is_direct());
890 OnResolveProxyHandler(url, load_flags, data_reduction_proxy_config,
891 proxy_config_direct, empty_proxy_retry_info,
892 &test_params, &other_proxy_info);
893 EXPECT_FALSE(other_proxy_info.is_direct());
895 load_flags |= net::LOAD_BYPASS_DATA_REDUCTION_PROXY;
897 OnResolveProxyHandler(url, load_flags, data_reduction_proxy_config,
898 proxy_config_direct, empty_proxy_retry_info,
899 &test_params, &data_reduction_proxy_info);
900 EXPECT_FALSE(data_reduction_proxy_info.is_direct());
902 OnResolveProxyHandler(url, load_flags, data_reduction_proxy_config,
903 proxy_config_direct, empty_proxy_retry_info,
904 &test_params, &other_proxy_info);
905 EXPECT_FALSE(other_proxy_info.is_direct());
907 // With Finch trial set, should only bypass if LOAD flag is set and the
908 // effective proxy is the data compression proxy.
909 base::FieldTrialList field_trial_list(new BadEntropyProvider());
910 base::FieldTrialList::CreateFieldTrial("DataCompressionProxyCriticalBypass",
913 DataReductionProxyParams::IsIncludedInCriticalPathBypassFieldTrial());
915 load_flags = net::LOAD_NORMAL;
917 OnResolveProxyHandler(url, load_flags, data_reduction_proxy_config,
918 proxy_config_direct, empty_proxy_retry_info,
919 &test_params, &data_reduction_proxy_info);
920 EXPECT_FALSE(data_reduction_proxy_info.is_direct());
922 OnResolveProxyHandler(url, load_flags, data_reduction_proxy_config,
923 proxy_config_direct, empty_proxy_retry_info,
924 &test_params, &other_proxy_info);
925 EXPECT_FALSE(other_proxy_info.is_direct());
927 load_flags |= net::LOAD_BYPASS_DATA_REDUCTION_PROXY;
929 OnResolveProxyHandler(url, load_flags, data_reduction_proxy_config,
930 proxy_config_direct, empty_proxy_retry_info,
931 &test_params, &other_proxy_info);
932 EXPECT_FALSE(other_proxy_info.is_direct());
934 OnResolveProxyHandler(url, load_flags, data_reduction_proxy_config,
935 proxy_config_direct, empty_proxy_retry_info,
936 &test_params, &data_reduction_proxy_info);
937 EXPECT_TRUE(data_reduction_proxy_info.is_direct());
940 } // namespace data_reduction_proxy