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/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/browser/data_reduction_proxy_params_test_utils.h"
15 #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
16 #include "net/base/completion_callback.h"
17 #include "net/base/host_port_pair.h"
18 #include "net/base/load_flags.h"
19 #include "net/base/network_delegate.h"
20 #include "net/http/http_response_headers.h"
21 #include "net/http/http_transaction_test_util.h"
22 #include "net/proxy/proxy_service.h"
23 #include "net/socket/socket_test_util.h"
24 #include "net/url_request/static_http_user_agent_settings.h"
25 #include "net/url_request/url_request.h"
26 #include "net/url_request/url_request_context.h"
27 #include "net/url_request/url_request_test_util.h"
28 #include "testing/gtest/include/gtest/gtest.h"
30 using net::HttpResponseHeaders
;
31 using net::HostPortPair
;
34 using net::ProxyRetryInfoMap
;
35 using net::ProxyService
;
36 using net::StaticSocketDataProvider
;
37 using net::TestDelegate
;
38 using net::URLRequest
;
39 using net::TestURLRequestContext
;
43 // Transform "normal"-looking headers (\n-separated) to the appropriate
44 // input format for ParseRawHeaders (\0-separated).
45 void HeadersToRaw(std::string
* headers
) {
46 std::replace(headers
->begin(), headers
->end(), '\n', '\0');
47 if (!headers
->empty())
54 namespace data_reduction_proxy
{
56 // A test network delegate that exercises the bypass logic of the data
58 class TestDataReductionProxyNetworkDelegate
: public net::NetworkDelegate
{
60 TestDataReductionProxyNetworkDelegate(
61 TestDataReductionProxyParams
* test_params
,
62 DataReductionProxyBypassType
* bypass_type
)
63 : net::NetworkDelegate(),
64 test_data_reduction_proxy_params_(test_params
),
65 bypass_type_(bypass_type
) {
68 virtual int OnHeadersReceived(
70 const net::CompletionCallback
& callback
,
71 const HttpResponseHeaders
* original_response_headers
,
72 scoped_refptr
<HttpResponseHeaders
>* override_response_headers
,
73 GURL
* allowed_unsafe_redirect_url
) OVERRIDE
{
74 data_reduction_proxy::MaybeBypassProxyAndPrepareToRetry(
75 test_data_reduction_proxy_params_
,
77 original_response_headers
,
78 override_response_headers
,
83 TestDataReductionProxyParams
* test_data_reduction_proxy_params_
;
84 DataReductionProxyBypassType
* bypass_type_
;
87 // Constructs a |TestURLRequestContext| that uses a |MockSocketFactory| to
88 // simulate requests and responses.
89 class DataReductionProxyProtocolTest
: public testing::Test
{
91 DataReductionProxyProtocolTest() : http_user_agent_settings_("", "") {
93 new TestDataReductionProxyParams(
94 DataReductionProxyParams::kAllowed
|
95 DataReductionProxyParams::kFallbackAllowed
|
96 DataReductionProxyParams::kPromoAllowed
,
97 TestDataReductionProxyParams::HAS_EVERYTHING
&
98 ~TestDataReductionProxyParams::HAS_DEV_ORIGIN
));
101 // Sets up the |TestURLRequestContext| with the provided |ProxyService| and
102 // |bypass_type| to store bypass reasons.
103 void ConfigureTestDependencies(ProxyService
* proxy_service
,
104 DataReductionProxyBypassType
* bypass_type
) {
105 // Create a context with delayed initialization.
106 context_
.reset(new TestURLRequestContext(true));
108 proxy_service_
.reset(proxy_service
);
109 network_delegate_
.reset(new TestDataReductionProxyNetworkDelegate(
110 proxy_params_
.get(), bypass_type
));
112 context_
->set_client_socket_factory(&mock_socket_factory_
);
113 context_
->set_proxy_service(proxy_service_
.get());
114 context_
->set_network_delegate(network_delegate_
.get());
115 // This is needed to prevent the test context from adding language headers
117 context_
->set_http_user_agent_settings(&http_user_agent_settings_
);
122 // Simulates a request to a data reduction proxy that may result in bypassing
123 // the proxy and retrying the the request.
124 // Runs a test with the given request |method| that expects the first response
125 // from the server to be |first_response|. If |expected_retry|, the test
126 // will expect a retry of the request. A response body will be expected
127 // if |expect_response_body|.
128 void TestProxyFallback(const char* method
,
129 const char* first_response
,
131 bool expect_response_body
) {
132 std::string payload1
=
133 (expected_retry
? "Bypass message" : "content");
134 MockRead data_reads
[] = {
135 MockRead(first_response
),
136 MockRead(payload1
.c_str()),
137 MockRead(net::SYNCHRONOUS
, net::OK
),
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"
149 "Accept-Encoding: gzip,deflate\r\n\r\n",
150 method
, 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 MockRead data_reads2
[] = {
159 MockRead("HTTP/1.0 200 OK\r\n"
160 "Server: not-proxy\r\n\r\n"),
162 MockRead(net::SYNCHRONOUS
, net::OK
),
164 std::string request2
=
165 base::StringPrintf("%s / HTTP/1.1\r\n"
166 "Host: www.google.com\r\n"
167 "Connection: keep-alive\r\n%s"
169 "Accept-Encoding: gzip,deflate\r\n\r\n",
170 method
, trailer
.c_str());
171 MockWrite data_writes2
[] = {
172 MockWrite(request2
.c_str()),
174 StaticSocketDataProvider
data2(data_reads2
, arraysize(data_reads2
),
175 data_writes2
, arraysize(data_writes2
));
176 if (expected_retry
) {
177 mock_socket_factory_
.AddSocketDataProvider(&data2
);
180 // Expect that we get "content" and not "Bypass message", and that there's
181 // a "not-proxy" "Server:" header in the final response.
182 ExecuteRequestExpectingContentAndHeader(
184 (expect_response_body
? "content" : ""),
186 (expected_retry
== 0 ? "proxy" : "not-proxy"),
190 // Starts a request with the given |method| and checks that the response
191 // contains |content| and the the header |header|: |value|, if |header| is
192 // non-empty. Verifies that the request's URL chain is the right length
193 // depending on whether or not a retry was expected (|expected_retry|).
194 void ExecuteRequestExpectingContentAndHeader(const std::string
& method
,
195 const std::string
& content
,
196 const std::string
& header
,
197 const std::string
& value
,
198 bool expected_retry
) {
200 scoped_ptr
<URLRequest
> r(context_
->CreateRequest(
201 GURL("http://www.google.com/"),
202 net::DEFAULT_PRIORITY
,
205 r
->set_method(method
);
206 r
->SetLoadFlags(net::LOAD_NORMAL
);
209 base::RunLoop().Run();
211 EXPECT_EQ(net::URLRequestStatus::SUCCESS
, r
->status().status());
212 EXPECT_EQ(net::OK
, r
->status().error());
214 EXPECT_EQ(2U, r
->url_chain().size());
216 EXPECT_EQ(1U, r
->url_chain().size());
218 if (!header
.empty()) {
219 // We also have a server header here that isn't set by the proxy.
220 EXPECT_TRUE(r
->response_headers()->HasHeaderValue(header
, value
));
223 EXPECT_EQ(content
, d
.data_received());
226 // Returns the key to the |ProxyRetryInfoMap|.
227 std::string
GetProxyKey(std::string proxy
) {
229 std::string host_port
= HostPortPair::FromURL(GURL(proxy
)).ToString();
230 if (gurl
.SchemeIs("https"))
231 return "https://" + host_port
;
235 // Checks that |expected_num_bad_proxies| proxies are on the proxy retry list.
236 // If the list has one proxy, it should match |bad_proxy|. If it has two
237 // proxies, it should match |bad_proxy| and |bad_proxy2|. Checks also that
238 // the current delay associated with each bad proxy is |duration_seconds|.
239 void TestBadProxies(unsigned int expected_num_bad_proxies
,
240 int duration_seconds
,
241 const std::string
& bad_proxy
,
242 const std::string
& bad_proxy2
) {
243 const ProxyRetryInfoMap
& retry_info
= proxy_service_
->proxy_retry_info();
244 ASSERT_EQ(expected_num_bad_proxies
, retry_info
.size());
246 base::TimeDelta expected_min_duration
;
247 base::TimeDelta expected_max_duration
;
248 if (duration_seconds
== 0) {
249 expected_min_duration
= base::TimeDelta::FromMinutes(1);
250 expected_max_duration
= base::TimeDelta::FromMinutes(5);
252 expected_min_duration
= base::TimeDelta::FromSeconds(duration_seconds
);
253 expected_max_duration
= base::TimeDelta::FromSeconds(duration_seconds
);
256 if (expected_num_bad_proxies
>= 1u) {
257 ProxyRetryInfoMap::const_iterator i
=
258 retry_info
.find(GetProxyKey(bad_proxy
));
259 ASSERT_TRUE(i
!= retry_info
.end());
260 EXPECT_TRUE(expected_min_duration
<= (*i
).second
.current_delay
);
261 EXPECT_TRUE((*i
).second
.current_delay
<= expected_max_duration
);
263 if (expected_num_bad_proxies
== 2u) {
264 ProxyRetryInfoMap::const_iterator i
=
265 retry_info
.find(GetProxyKey(bad_proxy2
));
266 ASSERT_TRUE(i
!= retry_info
.end());
267 EXPECT_TRUE(expected_min_duration
<= (*i
).second
.current_delay
);
268 EXPECT_TRUE((*i
).second
.current_delay
<= expected_max_duration
);
273 base::MessageLoopForIO loop_
;
275 net::MockClientSocketFactory mock_socket_factory_
;
276 scoped_ptr
<ProxyService
> proxy_service_
;
277 scoped_ptr
<TestDataReductionProxyParams
> proxy_params_
;
278 scoped_ptr
<TestDataReductionProxyNetworkDelegate
> network_delegate_
;
279 net::StaticHttpUserAgentSettings http_user_agent_settings_
;
281 scoped_ptr
<TestURLRequestContext
> context_
;
284 // Tests that request are deemed idempotent or not according to the method used.
285 TEST_F(DataReductionProxyProtocolTest
, TestIdempotency
) {
286 net::TestURLRequestContext context
;
289 bool expected_result
;
298 { "CONNECT", false },
300 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
301 net::TestURLRequest
request(GURL("http://www.google.com/"),
302 net::DEFAULT_PRIORITY
,
305 request
.set_method(tests
[i
].method
);
306 EXPECT_EQ(tests
[i
].expected_result
, IsRequestIdempotent(&request
));
310 // Tests that the response is correctly overwritten as a redirect.
311 TEST_F(DataReductionProxyProtocolTest
, OverrideResponseAsRedirect
) {
312 net::TestURLRequestContext context
;
315 const char* expected_headers
;
317 { "HTTP/1.1 200 0K\n"
318 "Chrome-Proxy: block=1\n"
319 "Via: 1.1 Chrome-Compression-Proxy\n",
321 "HTTP/1.1 302 Found\n"
322 "Chrome-Proxy: block=1\n"
323 "Via: 1.1 Chrome-Compression-Proxy\n"
324 "Location: http://www.google.com/\n"
326 { "HTTP/1.1 200 0K\n"
327 "Chrome-Proxy: block-once\n"
328 "Via: 1.1 Chrome-Compression-Proxy\n",
330 "HTTP/1.1 302 Found\n"
331 "Chrome-Proxy: block-once\n"
332 "Via: 1.1 Chrome-Compression-Proxy\n"
333 "Location: http://www.google.com/\n"
335 { "HTTP/1.1 302 Found\n"
336 "Location: http://foo.com/\n",
338 "HTTP/1.1 302 Found\n"
339 "Location: http://www.google.com/\n"
343 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
344 std::string
headers(tests
[i
].headers
);
345 HeadersToRaw(&headers
);
346 scoped_refptr
<HttpResponseHeaders
> original_response_headers(
347 new HttpResponseHeaders(headers
));
348 scoped_refptr
<HttpResponseHeaders
> override_response_headers
;
349 TestDelegate test_delegate
;
350 net::TestURLRequest
request(GURL("http://www.google.com/"),
351 net::DEFAULT_PRIORITY
,
354 OverrideResponseAsRedirect(
355 &request
, original_response_headers
.get(), &override_response_headers
);
356 int expected_flags
= net::LOAD_DISABLE_CACHE
| net::LOAD_BYPASS_PROXY
;
357 EXPECT_EQ(expected_flags
, request
.load_flags());
358 std::string override_headers
;
359 override_response_headers
->GetNormalizedHeaders(&override_headers
);
360 EXPECT_EQ(std::string(tests
[i
].expected_headers
), override_headers
);
365 // After each test, the proxy retry info will contain zero, one, or two of the
366 // data reduction proxies depending on whether no bypass was indicated by the
367 // initial response, a single proxy bypass was indicated, or a double bypass
368 // was indicated. In both the single and double bypass cases, if the request
369 // was idempotent, it will be retried over a direct connection.
370 TEST_F(DataReductionProxyProtocolTest
, BypassLogic
) {
373 const char* first_response
;
375 size_t expected_bad_proxy_count
;
376 bool expect_response_body
;
377 int expected_duration
;
378 DataReductionProxyBypassType expected_bypass_type
;
380 // Valid data reduction proxy response with no bypass message.
382 "HTTP/1.1 200 OK\r\n"
384 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
389 BYPASS_EVENT_TYPE_MAX
,
391 // Valid data reduction proxy response with older, but still valid via
394 "HTTP/1.1 200 OK\r\n"
396 "Via: 1.1 Chrome Compression Proxy\r\n\r\n",
401 BYPASS_EVENT_TYPE_MAX
403 // Valid data reduction proxy response with chained via header,
404 // no bypass message.
406 "HTTP/1.1 200 OK\r\n"
408 "Via: 1.1 Chrome-Compression-Proxy, 1.0 some-other-proxy\r\n\r\n",
413 BYPASS_EVENT_TYPE_MAX
415 // Valid data reduction proxy response with a bypass message.
417 "HTTP/1.1 200 OK\r\n"
419 "Chrome-Proxy: bypass=0\r\n"
420 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
425 BYPASS_EVENT_TYPE_MEDIUM
427 // Valid data reduction proxy response with a bypass message.
429 "HTTP/1.1 200 OK\r\n"
431 "Chrome-Proxy: bypass=1\r\n"
432 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
437 BYPASS_EVENT_TYPE_SHORT
439 // Same as above with the OPTIONS method, which is idempotent.
441 "HTTP/1.1 200 OK\r\n"
443 "Chrome-Proxy: bypass=0\r\n"
444 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
449 BYPASS_EVENT_TYPE_MEDIUM
451 // Same as above with the HEAD method, which is idempotent.
453 "HTTP/1.1 200 OK\r\n"
455 "Chrome-Proxy: bypass=0\r\n"
456 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
461 BYPASS_EVENT_TYPE_MEDIUM
463 // Same as above with the PUT method, which is idempotent.
465 "HTTP/1.1 200 OK\r\n"
467 "Chrome-Proxy: bypass=0\r\n"
468 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
473 BYPASS_EVENT_TYPE_MEDIUM
475 // Same as above with the DELETE method, which is idempotent.
477 "HTTP/1.1 200 OK\r\n"
479 "Chrome-Proxy: bypass=0\r\n"
480 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
485 BYPASS_EVENT_TYPE_MEDIUM
487 // Same as above with the TRACE method, which is idempotent.
489 "HTTP/1.1 200 OK\r\n"
491 "Chrome-Proxy: bypass=0\r\n"
492 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
497 BYPASS_EVENT_TYPE_MEDIUM
499 // 500 responses should be bypassed.
501 "HTTP/1.1 500 Internal Server Error\r\n"
503 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
508 BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR
510 // 502 responses should be bypassed.
512 "HTTP/1.1 502 Internal Server Error\r\n"
514 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
519 BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY
521 // 503 responses should be bypassed.
523 "HTTP/1.1 503 Internal Server Error\r\n"
525 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
530 BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE
532 // Invalid data reduction proxy response. Missing Via header.
534 "HTTP/1.1 200 OK\r\n"
535 "Server: proxy\r\n\r\n",
540 BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER
542 // Invalid data reduction proxy response. Wrong Via header.
544 "HTTP/1.1 200 OK\r\n"
546 "Via: 1.0 some-other-proxy\r\n\r\n",
551 BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER
553 // Valid data reduction proxy response. 304 missing Via header.
555 "HTTP/1.1 304 Not Modified\r\n"
556 "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",
574 BYPASS_EVENT_TYPE_MEDIUM
576 // Valid data reduction proxy response with block message. Both proxies
577 // should be on the retry list when it completes.
579 "HTTP/1.1 200 OK\r\n"
581 "Chrome-Proxy: block=1\r\n"
582 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
587 BYPASS_EVENT_TYPE_SHORT
589 // Valid data reduction proxy response with a block-once message. It will be
590 // retried, and there will be no proxies on the retry list since block-once
591 // only affects the current request.
593 "HTTP/1.1 200 OK\r\n"
595 "Chrome-Proxy: block-once\r\n"
596 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
601 BYPASS_EVENT_TYPE_CURRENT
603 // Same as above with the OPTIONS method, which is idempotent.
605 "HTTP/1.1 200 OK\r\n"
607 "Chrome-Proxy: block-once\r\n"
608 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
613 BYPASS_EVENT_TYPE_CURRENT
615 // Same as above with the HEAD method, which is idempotent.
617 "HTTP/1.1 200 OK\r\n"
619 "Chrome-Proxy: block-once\r\n"
620 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
625 BYPASS_EVENT_TYPE_CURRENT
627 // Same as above with the PUT method, which is idempotent.
629 "HTTP/1.1 200 OK\r\n"
631 "Chrome-Proxy: block-once\r\n"
632 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
637 BYPASS_EVENT_TYPE_CURRENT
639 // Same as above with the DELETE method, which is idempotent.
641 "HTTP/1.1 200 OK\r\n"
643 "Chrome-Proxy: block-once\r\n"
644 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
649 BYPASS_EVENT_TYPE_CURRENT
651 // Same as above with the TRACE method, which is idempotent.
653 "HTTP/1.1 200 OK\r\n"
655 "Chrome-Proxy: block-once\r\n"
656 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
661 BYPASS_EVENT_TYPE_CURRENT
663 // Valid data reduction proxy response with a block-once message. It will
664 // not be retried because the request is non-idempotent, and there will be
665 // no proxies on the retry list since block-once only affects the current
668 "HTTP/1.1 200 OK\r\n"
670 "Chrome-Proxy: block-once\r\n"
671 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
676 BYPASS_EVENT_TYPE_CURRENT
678 // Valid data reduction proxy response with block and block-once messages.
679 // The block message will override the block-once message, so both proxies
680 // should be on the retry list when it completes.
682 "HTTP/1.1 200 OK\r\n"
684 "Chrome-Proxy: block=1, block-once\r\n"
685 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
690 BYPASS_EVENT_TYPE_SHORT
692 // Valid data reduction proxy response with bypass and block-once messages.
693 // The bypass message will override the block-once message, so one proxy
694 // should be on the retry list when it completes.
696 "HTTP/1.1 200 OK\r\n"
698 "Chrome-Proxy: bypass=1, block-once\r\n"
699 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
704 BYPASS_EVENT_TYPE_SHORT
707 std::string primary
= proxy_params_
->DefaultOrigin();
708 std::string fallback
= proxy_params_
->DefaultFallbackOrigin();
709 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
710 DataReductionProxyBypassType bypass_type
;
711 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
713 HostPortPair::FromURL(GURL(primary
)).ToString() + "; PROXY " +
714 HostPortPair::FromURL(GURL(fallback
)).ToString() + "; DIRECT"),
716 TestProxyFallback(tests
[i
].method
,
717 tests
[i
].first_response
,
718 tests
[i
].expected_retry
,
719 tests
[i
].expect_response_body
);
721 EXPECT_EQ(tests
[i
].expected_bypass_type
, bypass_type
);
723 // We should also observe the bad proxy in the retry list.
724 TestBadProxies(tests
[i
].expected_bad_proxy_count
,
725 tests
[i
].expected_duration
,
730 TEST_F(DataReductionProxyProtocolTest
,
731 ProxyBypassIgnoredOnDirectConnection
) {
732 // Verify that a Chrome-Proxy header is ignored when returned from a directly
733 // connected origin server.
734 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult("DIRECT"),
737 MockRead data_reads
[] = {
738 MockRead("HTTP/1.1 200 OK\r\n"
739 "Chrome-Proxy: bypass=0\r\n\r\n"),
740 MockRead("Bypass message"),
741 MockRead(net::SYNCHRONOUS
, net::OK
),
743 MockWrite data_writes
[] = {
744 MockWrite("GET / HTTP/1.1\r\n"
745 "Host: www.google.com\r\n"
746 "Connection: keep-alive\r\n"
748 "Accept-Encoding: gzip,deflate\r\n\r\n"),
750 StaticSocketDataProvider
data1(data_reads
, arraysize(data_reads
),
751 data_writes
, arraysize(data_writes
));
752 mock_socket_factory_
.AddSocketDataProvider(&data1
);
755 scoped_ptr
<URLRequest
> r(context_
->CreateRequest(
756 GURL("http://www.google.com/"),
757 net::DEFAULT_PRIORITY
,
760 r
->set_method("GET");
761 r
->SetLoadFlags(net::LOAD_NORMAL
);
764 base::RunLoop().Run();
766 EXPECT_EQ(net::URLRequestStatus::SUCCESS
, r
->status().status());
767 EXPECT_EQ(net::OK
, r
->status().error());
769 EXPECT_EQ("Bypass message", d
.data_received());
771 // We should have no entries in our bad proxy list.
772 TestBadProxies(0, -1, "", "");
775 class BadEntropyProvider
: public base::FieldTrial::EntropyProvider
{
777 virtual ~BadEntropyProvider() {}
779 virtual double GetEntropyForTrial(const std::string
& trial_name
,
780 uint32 randomization_seed
) const OVERRIDE
{
785 TEST_F(DataReductionProxyProtocolTest
, OnResolveProxyHandler
) {
786 int load_flags
= net::LOAD_NORMAL
;
787 GURL
url("http://www.google.com/");
789 TestDataReductionProxyParams
test_params(
790 DataReductionProxyParams::kAllowed
|
791 DataReductionProxyParams::kFallbackAllowed
|
792 DataReductionProxyParams::kPromoAllowed
,
793 TestDataReductionProxyParams::HAS_EVERYTHING
&
794 ~TestDataReductionProxyParams::HAS_DEV_ORIGIN
);
796 // Data reduction proxy info
797 net::ProxyInfo data_reduction_proxy_info
;
798 std::string data_reduction_proxy
;
799 base::TrimString(test_params
.DefaultOrigin(), "/", &data_reduction_proxy
);
800 data_reduction_proxy_info
.UseNamedProxy(data_reduction_proxy
);
801 EXPECT_FALSE(data_reduction_proxy_info
.is_empty());
803 // Data reduction proxy config
804 net::ProxyConfig data_reduction_proxy_config
;
805 data_reduction_proxy_config
.proxy_rules().ParseFromString(
806 "http=" + data_reduction_proxy
+ ",direct://;");
807 data_reduction_proxy_config
.set_id(1);
810 net::ProxyInfo other_proxy_info
;
811 other_proxy_info
.UseNamedProxy("proxy.com");
812 EXPECT_FALSE(other_proxy_info
.is_empty());
815 net::ProxyInfo direct_proxy_info
;
816 direct_proxy_info
.UseDirect();
817 EXPECT_TRUE(direct_proxy_info
.is_direct());
819 // Empty retry info map
820 net::ProxyRetryInfoMap empty_proxy_retry_info
;
822 // Retry info map with the data reduction proxy;
823 net::ProxyRetryInfoMap data_reduction_proxy_retry_info
;
824 net::ProxyRetryInfo retry_info
;
825 retry_info
.current_delay
= base::TimeDelta::FromSeconds(1000);
826 retry_info
.bad_until
= base::TimeTicks().Now() + retry_info
.current_delay
;
827 retry_info
.try_while_bad
= false;
828 data_reduction_proxy_retry_info
[
829 data_reduction_proxy_info
.proxy_server().ToURI()] = retry_info
;
831 net::ProxyInfo result
;
833 // The data reduction proxy is used. It should be used afterwards.
834 result
.Use(data_reduction_proxy_info
);
835 OnResolveProxyHandler(url
, load_flags
, data_reduction_proxy_config
,
836 empty_proxy_retry_info
, &test_params
, &result
);
837 EXPECT_EQ(data_reduction_proxy_info
.proxy_server(), result
.proxy_server());
839 // Another proxy is used. It should be used afterwards.
840 result
.Use(other_proxy_info
);
841 OnResolveProxyHandler(url
, load_flags
, data_reduction_proxy_config
,
842 empty_proxy_retry_info
, &test_params
, &result
);
843 EXPECT_EQ(other_proxy_info
.proxy_server(), result
.proxy_server());
845 // A direct connection is used. The data reduction proxy should be used
847 // Another proxy is used. It should be used afterwards.
848 result
.Use(direct_proxy_info
);
849 OnResolveProxyHandler(url
, load_flags
, data_reduction_proxy_config
,
850 empty_proxy_retry_info
, &test_params
, &result
);
851 EXPECT_EQ(data_reduction_proxy_info
.proxy_server(), result
.proxy_server());
853 // A direct connection is used, but the data reduction proxy is on the retry
854 // list. A direct connection should be used afterwards.
855 result
.Use(direct_proxy_info
);
856 OnResolveProxyHandler(url
, load_flags
, data_reduction_proxy_config
,
857 data_reduction_proxy_retry_info
, &test_params
,
859 EXPECT_TRUE(result
.proxy_server().is_direct());
862 // Without DataCompressionProxyCriticalBypass Finch trial set, should never
864 OnResolveProxyHandler(url
, load_flags
, data_reduction_proxy_config
,
865 empty_proxy_retry_info
, &test_params
,
866 &data_reduction_proxy_info
);
867 EXPECT_FALSE(data_reduction_proxy_info
.is_direct());
869 OnResolveProxyHandler(url
, load_flags
, data_reduction_proxy_config
,
870 empty_proxy_retry_info
, &test_params
,
872 EXPECT_FALSE(other_proxy_info
.is_direct());
874 load_flags
|= net::LOAD_BYPASS_DATA_REDUCTION_PROXY
;
876 OnResolveProxyHandler(url
, load_flags
, data_reduction_proxy_config
,
877 empty_proxy_retry_info
, &test_params
,
878 &data_reduction_proxy_info
);
879 EXPECT_FALSE(data_reduction_proxy_info
.is_direct());
881 OnResolveProxyHandler(url
, load_flags
, data_reduction_proxy_config
,
882 empty_proxy_retry_info
, &test_params
,
884 EXPECT_FALSE(other_proxy_info
.is_direct());
886 // With Finch trial set, should only bypass if LOAD flag is set and the
887 // effective proxy is the data compression proxy.
888 base::FieldTrialList
field_trial_list(new BadEntropyProvider());
889 base::FieldTrialList::CreateFieldTrial("DataCompressionProxyRollout",
891 base::FieldTrialList::CreateFieldTrial("DataCompressionProxyCriticalBypass",
894 DataReductionProxyParams::IsIncludedInCriticalPathBypassFieldTrial());
896 load_flags
= net::LOAD_NORMAL
;
898 OnResolveProxyHandler(url
, load_flags
, data_reduction_proxy_config
,
899 empty_proxy_retry_info
, &test_params
,
900 &data_reduction_proxy_info
);
901 EXPECT_FALSE(data_reduction_proxy_info
.is_direct());
903 OnResolveProxyHandler(url
, load_flags
, data_reduction_proxy_config
,
904 empty_proxy_retry_info
, &test_params
,
906 EXPECT_FALSE(other_proxy_info
.is_direct());
908 load_flags
|= net::LOAD_BYPASS_DATA_REDUCTION_PROXY
;
910 OnResolveProxyHandler(url
, load_flags
, data_reduction_proxy_config
,
911 empty_proxy_retry_info
, &test_params
,
913 EXPECT_FALSE(other_proxy_info
.is_direct());
915 OnResolveProxyHandler(url
, load_flags
, data_reduction_proxy_config
,
916 empty_proxy_retry_info
, &test_params
,
917 &data_reduction_proxy_info
);
918 EXPECT_TRUE(data_reduction_proxy_info
.is_direct());
921 } // namespace data_reduction_proxy