Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / components / data_reduction_proxy / browser / data_reduction_proxy_protocol_unittest.cc
blob0e3b2377311ace47635803c4ec4e4934e9c59f9c
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"
7 #include <utility>
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;
32 using net::MockRead;
33 using net::MockWrite;
34 using net::ProxyRetryInfoMap;
35 using net::ProxyService;
36 using net::StaticSocketDataProvider;
37 using net::TestDelegate;
38 using net::URLRequest;
39 using net::TestURLRequestContext;
42 namespace {
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())
48 *headers += '\0';
51 } // namespace
54 namespace data_reduction_proxy {
56 // A test network delegate that exercises the bypass logic of the data
57 // reduction proxy.
58 class TestDataReductionProxyNetworkDelegate : public net::NetworkDelegate {
59 public:
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(
69 URLRequest* request,
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_,
76 request,
77 original_response_headers,
78 override_response_headers,
79 bypass_type_);
80 return net::OK;
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 {
90 public:
91 DataReductionProxyProtocolTest() : http_user_agent_settings_("", "") {
92 proxy_params_.reset(
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
116 // to requests.
117 context_->set_http_user_agent_settings(&http_user_agent_settings_);
119 context_->Init();
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,
130 bool expected_retry,
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"
148 "User-Agent:\r\n"
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"),
161 MockRead("content"),
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"
168 "User-Agent:\r\n"
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(
183 method,
184 (expect_response_body ? "content" : ""),
185 "server",
186 (expected_retry == 0 ? "proxy" : "not-proxy"),
187 expected_retry);
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) {
199 TestDelegate d;
200 scoped_ptr<URLRequest> r(context_->CreateRequest(
201 GURL("http://www.google.com/"),
202 net::DEFAULT_PRIORITY,
204 NULL));
205 r->set_method(method);
206 r->SetLoadFlags(net::LOAD_NORMAL);
208 r->Start();
209 base::RunLoop().Run();
211 EXPECT_EQ(net::URLRequestStatus::SUCCESS, r->status().status());
212 EXPECT_EQ(net::OK, r->status().error());
213 if (expected_retry)
214 EXPECT_EQ(2U, r->url_chain().size());
215 else
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) {
228 GURL gurl(proxy);
229 std::string host_port = HostPortPair::FromURL(GURL(proxy)).ToString();
230 if (gurl.SchemeIs("https"))
231 return "https://" + host_port;
232 return 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);
251 } else {
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);
272 protected:
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;
287 const struct {
288 const char* method;
289 bool expected_result;
290 } tests[] = {
291 { "GET", true },
292 { "OPTIONS", true },
293 { "HEAD", true },
294 { "PUT", true },
295 { "DELETE", true },
296 { "TRACE", true },
297 { "POST", false },
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,
303 NULL,
304 &context);
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;
313 const struct {
314 const char* headers;
315 const char* expected_headers;
316 } tests[] = {
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,
352 NULL,
353 &context);
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) {
371 const struct {
372 const char* method;
373 const char* first_response;
374 bool expected_retry;
375 size_t expected_bad_proxy_count;
376 bool expect_response_body;
377 int expected_duration;
378 DataReductionProxyBypassType expected_bypass_type;
379 } tests[] = {
380 // Valid data reduction proxy response with no bypass message.
381 { "GET",
382 "HTTP/1.1 200 OK\r\n"
383 "Server: proxy\r\n"
384 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
385 false,
387 true,
389 BYPASS_EVENT_TYPE_MAX,
391 // Valid data reduction proxy response with older, but still valid via
392 // header.
393 { "GET",
394 "HTTP/1.1 200 OK\r\n"
395 "Server: proxy\r\n"
396 "Via: 1.1 Chrome Compression Proxy\r\n\r\n",
397 false,
399 true,
401 BYPASS_EVENT_TYPE_MAX
403 // Valid data reduction proxy response with chained via header,
404 // no bypass message.
405 { "GET",
406 "HTTP/1.1 200 OK\r\n"
407 "Server: proxy\r\n"
408 "Via: 1.1 Chrome-Compression-Proxy, 1.0 some-other-proxy\r\n\r\n",
409 false,
411 true,
413 BYPASS_EVENT_TYPE_MAX
415 // Valid data reduction proxy response with a bypass message.
416 { "GET",
417 "HTTP/1.1 200 OK\r\n"
418 "Server: proxy\r\n"
419 "Chrome-Proxy: bypass=0\r\n"
420 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
421 true,
423 true,
425 BYPASS_EVENT_TYPE_MEDIUM
427 // Valid data reduction proxy response with a bypass message.
428 { "GET",
429 "HTTP/1.1 200 OK\r\n"
430 "Server: proxy\r\n"
431 "Chrome-Proxy: bypass=1\r\n"
432 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
433 true,
435 true,
437 BYPASS_EVENT_TYPE_SHORT
439 // Same as above with the OPTIONS method, which is idempotent.
440 { "OPTIONS",
441 "HTTP/1.1 200 OK\r\n"
442 "Server: proxy\r\n"
443 "Chrome-Proxy: bypass=0\r\n"
444 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
445 true,
447 true,
449 BYPASS_EVENT_TYPE_MEDIUM
451 // Same as above with the HEAD method, which is idempotent.
452 { "HEAD",
453 "HTTP/1.1 200 OK\r\n"
454 "Server: proxy\r\n"
455 "Chrome-Proxy: bypass=0\r\n"
456 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
457 true,
459 false,
461 BYPASS_EVENT_TYPE_MEDIUM
463 // Same as above with the PUT method, which is idempotent.
464 { "PUT",
465 "HTTP/1.1 200 OK\r\n"
466 "Server: proxy\r\n"
467 "Chrome-Proxy: bypass=0\r\n"
468 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
469 true,
471 true,
473 BYPASS_EVENT_TYPE_MEDIUM
475 // Same as above with the DELETE method, which is idempotent.
476 { "DELETE",
477 "HTTP/1.1 200 OK\r\n"
478 "Server: proxy\r\n"
479 "Chrome-Proxy: bypass=0\r\n"
480 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
481 true,
483 true,
485 BYPASS_EVENT_TYPE_MEDIUM
487 // Same as above with the TRACE method, which is idempotent.
488 { "TRACE",
489 "HTTP/1.1 200 OK\r\n"
490 "Server: proxy\r\n"
491 "Chrome-Proxy: bypass=0\r\n"
492 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
493 true,
495 true,
497 BYPASS_EVENT_TYPE_MEDIUM
499 // 500 responses should be bypassed.
500 { "GET",
501 "HTTP/1.1 500 Internal Server Error\r\n"
502 "Server: proxy\r\n"
503 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
504 true,
506 true,
508 BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR
510 // 502 responses should be bypassed.
511 { "GET",
512 "HTTP/1.1 502 Internal Server Error\r\n"
513 "Server: proxy\r\n"
514 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
515 true,
517 true,
519 BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY
521 // 503 responses should be bypassed.
522 { "GET",
523 "HTTP/1.1 503 Internal Server Error\r\n"
524 "Server: proxy\r\n"
525 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
526 true,
528 true,
530 BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE
532 // Invalid data reduction proxy response. Missing Via header.
533 { "GET",
534 "HTTP/1.1 200 OK\r\n"
535 "Server: proxy\r\n\r\n",
536 true,
538 true,
540 BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER
542 // Invalid data reduction proxy response. Wrong Via header.
543 { "GET",
544 "HTTP/1.1 200 OK\r\n"
545 "Server: proxy\r\n"
546 "Via: 1.0 some-other-proxy\r\n\r\n",
547 true,
549 true,
551 BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER
553 // Valid data reduction proxy response. 304 missing Via header.
554 { "GET",
555 "HTTP/1.1 304 Not Modified\r\n"
556 "Server: proxy\r\n\r\n",
557 false,
559 false,
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.
565 { "POST",
566 "HTTP/1.1 200 OK\r\n"
567 "Server: proxy\r\n"
568 "Chrome-Proxy: bypass=0\r\n"
569 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
570 false,
572 true,
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.
578 { "GET",
579 "HTTP/1.1 200 OK\r\n"
580 "Server: proxy\r\n"
581 "Chrome-Proxy: block=1\r\n"
582 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
583 true,
585 true,
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.
592 { "GET",
593 "HTTP/1.1 200 OK\r\n"
594 "Server: proxy\r\n"
595 "Chrome-Proxy: block-once\r\n"
596 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
597 true,
599 true,
601 BYPASS_EVENT_TYPE_CURRENT
603 // Same as above with the OPTIONS method, which is idempotent.
604 { "OPTIONS",
605 "HTTP/1.1 200 OK\r\n"
606 "Server: proxy\r\n"
607 "Chrome-Proxy: block-once\r\n"
608 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
609 true,
611 true,
613 BYPASS_EVENT_TYPE_CURRENT
615 // Same as above with the HEAD method, which is idempotent.
616 { "HEAD",
617 "HTTP/1.1 200 OK\r\n"
618 "Server: proxy\r\n"
619 "Chrome-Proxy: block-once\r\n"
620 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
621 true,
623 false,
625 BYPASS_EVENT_TYPE_CURRENT
627 // Same as above with the PUT method, which is idempotent.
628 { "PUT",
629 "HTTP/1.1 200 OK\r\n"
630 "Server: proxy\r\n"
631 "Chrome-Proxy: block-once\r\n"
632 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
633 true,
635 true,
637 BYPASS_EVENT_TYPE_CURRENT
639 // Same as above with the DELETE method, which is idempotent.
640 { "DELETE",
641 "HTTP/1.1 200 OK\r\n"
642 "Server: proxy\r\n"
643 "Chrome-Proxy: block-once\r\n"
644 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
645 true,
647 true,
649 BYPASS_EVENT_TYPE_CURRENT
651 // Same as above with the TRACE method, which is idempotent.
652 { "TRACE",
653 "HTTP/1.1 200 OK\r\n"
654 "Server: proxy\r\n"
655 "Chrome-Proxy: block-once\r\n"
656 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
657 true,
659 true,
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
666 // request.
667 { "POST",
668 "HTTP/1.1 200 OK\r\n"
669 "Server: proxy\r\n"
670 "Chrome-Proxy: block-once\r\n"
671 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
672 false,
674 true,
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.
681 { "GET",
682 "HTTP/1.1 200 OK\r\n"
683 "Server: proxy\r\n"
684 "Chrome-Proxy: block=1, block-once\r\n"
685 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
686 true,
688 true,
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.
695 { "GET",
696 "HTTP/1.1 200 OK\r\n"
697 "Server: proxy\r\n"
698 "Chrome-Proxy: bypass=1, block-once\r\n"
699 "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
700 true,
702 true,
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(
712 "PROXY " +
713 HostPortPair::FromURL(GURL(primary)).ToString() + "; PROXY " +
714 HostPortPair::FromURL(GURL(fallback)).ToString() + "; DIRECT"),
715 &bypass_type);
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,
726 primary, fallback);
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"),
735 NULL);
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"
747 "User-Agent:\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);
754 TestDelegate d;
755 scoped_ptr<URLRequest> r(context_->CreateRequest(
756 GURL("http://www.google.com/"),
757 net::DEFAULT_PRIORITY,
759 NULL));
760 r->set_method("GET");
761 r->SetLoadFlags(net::LOAD_NORMAL);
763 r->Start();
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 {
776 public:
777 virtual ~BadEntropyProvider() {}
779 virtual double GetEntropyForTrial(const std::string& trial_name,
780 uint32 randomization_seed) const OVERRIDE {
781 return 0.5;
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);
809 // Other proxy info
810 net::ProxyInfo other_proxy_info;
811 other_proxy_info.UseNamedProxy("proxy.com");
812 EXPECT_FALSE(other_proxy_info.is_empty());
814 // Direct
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
846 // afterwards.
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,
858 &result);
859 EXPECT_TRUE(result.proxy_server().is_direct());
862 // Without DataCompressionProxyCriticalBypass Finch trial set, should never
863 // bypass.
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,
871 &other_proxy_info);
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,
883 &other_proxy_info);
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",
890 "Enabled");
891 base::FieldTrialList::CreateFieldTrial("DataCompressionProxyCriticalBypass",
892 "Enabled");
893 EXPECT_TRUE(
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,
905 &other_proxy_info);
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,
912 &other_proxy_info);
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