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/common/data_reduction_proxy_headers.h"
9 #include "net/http/http_response_headers.h"
10 #include "net/proxy/proxy_service.h"
11 #include "testing/gtest/include/gtest/gtest.h"
15 // Transform "normal"-looking headers (\n-separated) to the appropriate
16 // input format for ParseRawHeaders (\0-separated).
17 void HeadersToRaw(std::string
* headers
) {
18 std::replace(headers
->begin(), headers
->end(), '\n', '\0');
19 if (!headers
->empty())
25 namespace data_reduction_proxy
{
27 class DataReductionProxyHeadersTest
: public testing::Test
{};
29 TEST_F(DataReductionProxyHeadersTest
, GetDataReductionProxyActionValue
) {
32 std::string action_key
;
34 std::string expected_action_value
;
37 "Content-Length: 999\n",
43 "connection: keep-alive\n"
44 "Content-Length: 999\n",
50 "connection: keep-alive\n"
51 "Chrome-Proxy: bypass=86400\n"
52 "Content-Length: 999\n",
58 "connection: keep-alive\n"
59 "Chrome-Proxy: bypass86400\n"
60 "Content-Length: 999\n",
66 "connection: keep-alive\n"
67 "Chrome-Proxy: bypass=0\n"
68 "Content-Length: 999\n",
74 "connection: keep-alive\n"
75 "Chrome-Proxy: bypass=1500\n"
76 "Chrome-Proxy: bypass=86400\n"
77 "Content-Length: 999\n",
83 "connection: keep-alive\n"
84 "Chrome-Proxy: block=1500, block=3600\n"
85 "Content-Length: 999\n",
91 "connection: proxy-bypass\n"
92 "Chrome-Proxy: key=123 \n"
93 "Content-Length: 999\n",
99 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
100 std::string
headers(tests
[i
].headers
);
101 HeadersToRaw(&headers
);
102 scoped_refptr
<net::HttpResponseHeaders
> parsed(
103 new net::HttpResponseHeaders(headers
));
105 std::string action_value
;
106 bool has_action_key
= GetDataReductionProxyActionValue(
107 parsed
, tests
[i
].action_key
, &action_value
);
108 EXPECT_EQ(tests
[i
].expected_result
, has_action_key
);
109 if (has_action_key
) {
110 EXPECT_EQ(tests
[i
].expected_action_value
, action_value
);
115 TEST_F(DataReductionProxyHeadersTest
, GetProxyBypassInfo
) {
118 bool expected_result
;
119 int64 expected_retry_delay
;
120 bool expected_bypass_all
;
122 { "HTTP/1.1 200 OK\n"
123 "Content-Length: 999\n",
128 { "HTTP/1.1 200 OK\n"
129 "connection: keep-alive\n"
130 "Content-Length: 999\n",
135 { "HTTP/1.1 200 OK\n"
136 "connection: keep-alive\n"
137 "Chrome-Proxy: bypass=86400\n"
138 "Content-Length: 999\n",
143 { "HTTP/1.1 200 OK\n"
144 "connection: keep-alive\n"
145 "Chrome-Proxy: bypass=-1\n"
146 "Content-Length: 999\n",
151 { "HTTP/1.1 200 OK\n"
152 "connection: keep-alive\n"
153 "Chrome-Proxy: bypass=xyz\n"
154 "Content-Length: 999\n",
159 { "HTTP/1.1 200 OK\n"
160 "connection: keep-alive\n"
161 "Chrome-Proxy: bypass\n"
162 "Content-Length: 999\n",
167 { "HTTP/1.1 200 OK\n"
168 "connection: keep-alive\n"
169 "Chrome-Proxy: foo=abc, bypass=86400\n"
170 "Content-Length: 999\n",
175 { "HTTP/1.1 200 OK\n"
176 "connection: keep-alive\n"
177 "Chrome-Proxy: bypass=86400, bar=abc\n"
178 "Content-Length: 999\n",
183 { "HTTP/1.1 200 OK\n"
184 "connection: keep-alive\n"
185 "Chrome-Proxy: bypass=3600\n"
186 "Chrome-Proxy: bypass=86400\n"
187 "Content-Length: 999\n",
192 { "HTTP/1.1 200 OK\n"
193 "connection: keep-alive\n"
194 "Chrome-Proxy: bypass=3600, bypass=86400\n"
195 "Content-Length: 999\n",
200 { "HTTP/1.1 200 OK\n"
201 "connection: keep-alive\n"
202 "Chrome-Proxy: bypass=, bypass=86400\n"
203 "Content-Length: 999\n",
208 { "HTTP/1.1 200 OK\n"
209 "connection: keep-alive\n"
210 "Chrome-Proxy: bypass\n"
211 "Chrome-Proxy: bypass=86400\n"
212 "Content-Length: 999\n",
217 { "HTTP/1.1 200 OK\n"
218 "connection: keep-alive\n"
219 "Chrome-Proxy: block=, block=3600\n"
220 "Content-Length: 999\n",
225 { "HTTP/1.1 200 OK\n"
226 "connection: keep-alive\n"
227 "Chrome-Proxy: bypass=86400, block=3600\n"
228 "Content-Length: 999\n",
233 { "HTTP/1.1 200 OK\n"
234 "connection: proxy-bypass\n"
235 "Chrome-Proxy: block=, bypass=86400\n"
236 "Content-Length: 999\n",
241 { "HTTP/1.1 200 OK\n"
242 "connection: proxy-bypass\n"
243 "Chrome-Proxy: block=-1\n"
244 "Content-Length: 999\n",
249 { "HTTP/1.1 200 OK\n"
250 "connection: proxy-bypass\n"
251 "Chrome-Proxy: block=99999999999999999999\n"
252 "Content-Length: 999\n",
258 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
259 std::string
headers(tests
[i
].headers
);
260 HeadersToRaw(&headers
);
261 scoped_refptr
<net::HttpResponseHeaders
> parsed(
262 new net::HttpResponseHeaders(headers
));
264 DataReductionProxyInfo data_reduction_proxy_info
;
265 EXPECT_EQ(tests
[i
].expected_result
,
266 ParseHeadersAndSetProxyInfo(parsed
, &data_reduction_proxy_info
));
267 EXPECT_EQ(tests
[i
].expected_retry_delay
,
268 data_reduction_proxy_info
.bypass_duration
.InSeconds());
269 EXPECT_EQ(tests
[i
].expected_bypass_all
,
270 data_reduction_proxy_info
.bypass_all
);
274 TEST_F(DataReductionProxyHeadersTest
, ParseHeadersAndSetProxyInfo
) {
275 std::string headers
=
277 "connection: keep-alive\n"
278 "Chrome-Proxy: bypass=0\n"
279 "Content-Length: 999\n";
280 HeadersToRaw(&headers
);
281 scoped_refptr
<net::HttpResponseHeaders
> parsed(
282 new net::HttpResponseHeaders(headers
));
284 DataReductionProxyInfo data_reduction_proxy_info
;
285 EXPECT_TRUE(ParseHeadersAndSetProxyInfo(parsed
, &data_reduction_proxy_info
));
286 EXPECT_LE(60, data_reduction_proxy_info
.bypass_duration
.InSeconds());
287 EXPECT_GE(5 * 60, data_reduction_proxy_info
.bypass_duration
.InSeconds());
288 EXPECT_FALSE(data_reduction_proxy_info
.bypass_all
);
291 TEST_F(DataReductionProxyHeadersTest
, HasDataReductionProxyViaHeader
) {
294 bool expected_result
;
295 bool expected_has_intermediary
;
296 bool ignore_intermediary
;
298 { "HTTP/1.1 200 OK\n"
299 "Via: 1.1 Chrome-Proxy\n",
304 { "HTTP/1.1 200 OK\n"
310 { "HTTP/1.1 200 OK\n"
311 "Via: 1.1 Chrome-Compression-Proxy\n",
316 { "HTTP/1.1 200 OK\n"
317 "Via: 1.0 Chrome-Compression-Proxy\n",
322 { "HTTP/1.1 200 OK\n"
323 "Via: 1.1 Foo-Bar, 1.1 Chrome-Compression-Proxy\n",
328 { "HTTP/1.1 200 OK\n"
329 "Via: 1.1 Chrome-Compression-Proxy, 1.1 Bar-Foo\n",
334 { "HTTP/1.1 200 OK\n"
335 "Via: 1.1 chrome-compression-proxy\n",
340 { "HTTP/1.1 200 OK\n"
342 "Via: 1.1 Chrome-Compression-Proxy\n",
347 { "HTTP/1.1 200 OK\n"
348 "Via: 1.1 Chrome-Compression-Proxy\n"
349 "Via: 1.1 Foo-Bar\n",
354 { "HTTP/1.1 200 OK\n"
355 "Via: 1.1 Chrome-Proxy\n",
360 { "HTTP/1.1 200 OK\n"
361 "Via: 1.1 Chrome Compression Proxy\n",
366 { "HTTP/1.1 200 OK\n"
367 "Via: 1.1 Foo-Bar, 1.1 Chrome Compression Proxy\n",
372 { "HTTP/1.1 200 OK\n"
373 "Via: 1.1 Chrome Compression Proxy, 1.1 Bar-Foo\n",
378 { "HTTP/1.1 200 OK\n"
379 "Via: 1.1 chrome compression proxy\n",
384 { "HTTP/1.1 200 OK\n"
386 "Via: 1.1 Chrome Compression Proxy\n",
391 { "HTTP/1.1 200 OK\n"
392 "Via: 1.1 Chrome Compression Proxy\n"
393 "Via: 1.1 Foo-Bar\n",
398 { "HTTP/1.1 200 OK\n"
399 "Via: 1.1 Chrome Compression Proxy\n"
400 "Via: 1.1 Foo-Bar\n",
406 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
407 std::string
headers(tests
[i
].headers
);
408 HeadersToRaw(&headers
);
409 scoped_refptr
<net::HttpResponseHeaders
> parsed(
410 new net::HttpResponseHeaders(headers
));
412 bool has_chrome_proxy_via_header
, has_intermediary
;
413 if (tests
[i
].ignore_intermediary
) {
414 has_chrome_proxy_via_header
=
415 HasDataReductionProxyViaHeader(parsed
, NULL
);
418 has_chrome_proxy_via_header
=
419 HasDataReductionProxyViaHeader(parsed
, &has_intermediary
);
421 EXPECT_EQ(tests
[i
].expected_result
, has_chrome_proxy_via_header
);
422 if (has_chrome_proxy_via_header
&& !tests
[i
].ignore_intermediary
) {
423 EXPECT_EQ(tests
[i
].expected_has_intermediary
, has_intermediary
);
428 TEST_F(DataReductionProxyHeadersTest
, GetDataReductionProxyBypassEventType
) {
431 net::ProxyService::DataReductionProxyBypassType expected_result
;
433 { "HTTP/1.1 200 OK\n"
434 "Chrome-Proxy: bypass=0\n"
435 "Via: 1.1 Chrome-Compression-Proxy\n",
436 net::ProxyService::MEDIUM_BYPASS
,
438 { "HTTP/1.1 200 OK\n"
439 "Chrome-Proxy: bypass=1\n"
440 "Via: 1.1 Chrome-Compression-Proxy\n",
441 net::ProxyService::SHORT_BYPASS
,
443 { "HTTP/1.1 200 OK\n"
444 "Chrome-Proxy: bypass=59\n"
445 "Via: 1.1 Chrome-Compression-Proxy\n",
446 net::ProxyService::SHORT_BYPASS
,
448 { "HTTP/1.1 200 OK\n"
449 "Chrome-Proxy: bypass=60\n"
450 "Via: 1.1 Chrome-Compression-Proxy\n",
451 net::ProxyService::MEDIUM_BYPASS
,
453 { "HTTP/1.1 200 OK\n"
454 "Chrome-Proxy: bypass=300\n"
455 "Via: 1.1 Chrome-Compression-Proxy\n",
456 net::ProxyService::MEDIUM_BYPASS
,
458 { "HTTP/1.1 200 OK\n"
459 "Chrome-Proxy: bypass=301\n"
460 "Via: 1.1 Chrome-Compression-Proxy\n",
461 net::ProxyService::LONG_BYPASS
,
463 { "HTTP/1.1 500 Internal Server Error\n"
464 "Via: 1.1 Chrome-Compression-Proxy\n",
465 net::ProxyService::STATUS_500_HTTP_INTERNAL_SERVER_ERROR
,
467 { "HTTP/1.1 501 Not Implemented\n"
468 "Via: 1.1 Chrome-Compression-Proxy\n",
469 net::ProxyService::BYPASS_EVENT_TYPE_MAX
,
471 { "HTTP/1.1 502 Bad Gateway\n"
472 "Via: 1.1 Chrome-Compression-Proxy\n",
473 net::ProxyService::STATUS_502_HTTP_BAD_GATEWAY
,
475 { "HTTP/1.1 503 Service Unavailable\n"
476 "Via: 1.1 Chrome-Compression-Proxy\n",
477 net::ProxyService::STATUS_503_HTTP_SERVICE_UNAVAILABLE
,
479 { "HTTP/1.1 504 Gateway Timeout\n"
480 "Via: 1.1 Chrome-Compression-Proxy\n",
481 net::ProxyService::BYPASS_EVENT_TYPE_MAX
,
483 { "HTTP/1.1 505 HTTP Version Not Supported\n"
484 "Via: 1.1 Chrome-Compression-Proxy\n",
485 net::ProxyService::BYPASS_EVENT_TYPE_MAX
,
487 { "HTTP/1.1 304 Not Modified\n",
488 net::ProxyService::BYPASS_EVENT_TYPE_MAX
,
490 { "HTTP/1.1 200 OK\n",
491 net::ProxyService::MISSING_VIA_HEADER_OTHER
,
493 { "HTTP/1.1 200 OK\n"
494 "Chrome-Proxy: bypass=59\n",
495 net::ProxyService::SHORT_BYPASS
,
497 { "HTTP/1.1 502 Bad Gateway\n",
498 net::ProxyService::STATUS_502_HTTP_BAD_GATEWAY
,
500 { "HTTP/1.1 502 Bad Gateway\n"
501 "Chrome-Proxy: bypass=59\n",
502 net::ProxyService::SHORT_BYPASS
,
504 { "HTTP/1.1 502 Bad Gateway\n"
505 "Chrome-Proxy: bypass=59\n",
506 net::ProxyService::SHORT_BYPASS
,
508 { "HTTP/1.1 414 Request-URI Too Long\n",
509 net::ProxyService::MISSING_VIA_HEADER_4XX
,
511 { "HTTP/1.1 414 Request-URI Too Long\n"
512 "Via: 1.1 Chrome-Compression-Proxy\n",
513 net::ProxyService::BYPASS_EVENT_TYPE_MAX
,
515 { "HTTP/1.1 407 Proxy Authentication Required\n",
516 net::ProxyService::MALFORMED_407
,
518 { "HTTP/1.1 407 Proxy Authentication Required\n"
519 "Proxy-Authenticate: Basic\n"
520 "Via: 1.1 Chrome-Compression-Proxy\n",
521 net::ProxyService::BYPASS_EVENT_TYPE_MAX
,
524 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
525 std::string
headers(tests
[i
].headers
);
526 HeadersToRaw(&headers
);
527 scoped_refptr
<net::HttpResponseHeaders
> parsed(
528 new net::HttpResponseHeaders(headers
));
529 DataReductionProxyInfo chrome_proxy_info
;
530 EXPECT_EQ(tests
[i
].expected_result
,
531 GetDataReductionProxyBypassType(parsed
, &chrome_proxy_info
));
535 TEST_F(DataReductionProxyHeadersTest
,
536 GetDataReductionProxyActionFingerprintChromeProxy
) {
540 bool expected_fingerprint_exist
;
541 std::string expected_fingerprint
;
543 { "fingerprint doesn't exist",
545 "Chrome-Proxy: bypass=0\n",
549 { "fingerprint occurs once",
551 "Chrome-Proxy: bypass=1, fcp=fp\n",
555 { "fingerprint occurs twice",
557 "Chrome-Proxy: bypass=2, fcp=fp1, fcp=fp2\n",
562 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
563 std::string
headers(tests
[i
].headers
);
564 HeadersToRaw(&headers
);
565 scoped_refptr
<net::HttpResponseHeaders
> parsed(
566 new net::HttpResponseHeaders(headers
));
568 std::string fingerprint
;
569 bool fingerprint_exist
= GetDataReductionProxyActionFingerprintChromeProxy(
570 parsed
, &fingerprint
);
571 EXPECT_EQ(tests
[i
].expected_fingerprint_exist
, fingerprint_exist
)
574 if (fingerprint_exist
)
575 EXPECT_EQ(tests
[i
].expected_fingerprint
, fingerprint
) << tests
[i
].label
;
579 TEST_F(DataReductionProxyHeadersTest
,
580 GetDataReductionProxyActionFingerprintVia
) {
584 bool expected_fingerprint_exist
;
585 std::string expected_fingerprint
;
587 { "fingerprint doesn't exist",
589 "Chrome-Proxy: bypass=0\n",
593 { "fingerprint occurs once",
595 "Chrome-Proxy: bypass=1, fvia=fvia\n",
599 { "fingerprint occurs twice",
601 "Chrome-Proxy: bypass=2, fvia=fvia1, fvia=fvia2\n",
606 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
607 std::string
headers(tests
[i
].headers
);
608 HeadersToRaw(&headers
);
609 scoped_refptr
<net::HttpResponseHeaders
> parsed(
610 new net::HttpResponseHeaders(headers
));
612 std::string fingerprint
;
613 bool fingerprint_exist
=
614 GetDataReductionProxyActionFingerprintVia(parsed
, &fingerprint
);
615 EXPECT_EQ(tests
[i
].expected_fingerprint_exist
, fingerprint_exist
)
618 if (fingerprint_exist
)
619 EXPECT_EQ(tests
[i
].expected_fingerprint
, fingerprint
) << tests
[i
].label
;
623 TEST_F(DataReductionProxyHeadersTest
,
624 GetDataReductionProxyActionFingerprintOtherHeaders
) {
628 bool expected_fingerprint_exist
;
629 std::string expected_fingerprint
;
631 { "fingerprint doesn't exist",
633 "Chrome-Proxy: bypass=0\n",
637 { "fingerprint occurs once",
639 "Chrome-Proxy: bypass=1, foh=foh\n",
643 { "fingerprint occurs twice",
645 "Chrome-Proxy: bypass=2, foh=foh1, foh=foh2\n",
650 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
651 std::string
headers(tests
[i
].headers
);
652 HeadersToRaw(&headers
);
653 scoped_refptr
<net::HttpResponseHeaders
> parsed(
654 new net::HttpResponseHeaders(headers
));
656 std::string fingerprint
;
657 bool fingerprint_exist
=
658 GetDataReductionProxyActionFingerprintOtherHeaders(
659 parsed
, &fingerprint
);
660 EXPECT_EQ(tests
[i
].expected_fingerprint_exist
, fingerprint_exist
)
663 if (fingerprint_exist
)
664 EXPECT_EQ(tests
[i
].expected_fingerprint
, fingerprint
) << tests
[i
].label
;
668 TEST_F(DataReductionProxyHeadersTest
,
669 GetDataReductionProxyActionFingerprintContentLength
) {
673 bool expected_fingerprint_exist
;
674 std::string expected_fingerprint
;
676 { "fingerprint doesn't exist",
678 "Chrome-Proxy: bypass=0\n",
682 { "fingerprint occurs once",
684 "Chrome-Proxy: bypass=1, fcl=fcl\n",
688 { "fingerprint occurs twice",
690 "Chrome-Proxy: bypass=2, fcl=fcl1, fcl=fcl2\n",
695 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
696 std::string
headers(tests
[i
].headers
);
697 HeadersToRaw(&headers
);
698 scoped_refptr
<net::HttpResponseHeaders
> parsed(
699 new net::HttpResponseHeaders(headers
));
701 std::string fingerprint
;
702 bool fingerprint_exist
=
703 GetDataReductionProxyActionFingerprintContentLength(
704 parsed
, &fingerprint
);
705 EXPECT_EQ(tests
[i
].expected_fingerprint_exist
, fingerprint_exist
)
708 if (fingerprint_exist
)
709 EXPECT_EQ(tests
[i
].expected_fingerprint
, fingerprint
) << tests
[i
].label
;
713 TEST_F(DataReductionProxyHeadersTest
,
714 GetDataReductionProxyHeaderWithFingerprintRemoved
) {
718 std::string expected_output_values_string
;
721 "Checks the case that there is no Chrome-Proxy header's fingerprint.",
723 "Chrome-Proxy: 1,2,3,5\n",
727 "Checks the case that there is Chrome-Proxy header's fingerprint.",
729 "Chrome-Proxy: 1,2,3,fcp=4,5\n",
733 "Checks the case that there is Chrome-Proxy header's fingerprint, and it"
734 "occurs at the end.",
736 "Chrome-Proxy: 1,2,3,fcp=4,",
740 "Checks the case that there is Chrome-Proxy header's fingerprint, and it"
741 "occurs at the beginning.",
743 "Chrome-Proxy: fcp=1,2,3,",
747 "Checks the case that value is longer than prefix.",
749 "Chrome-Proxy: fcp=1,fcp!=1,fcp!=2,fcpfcp=3",
750 "fcp!=1,fcp!=2,fcpfcp=3,",
753 "Checks the case that value is shorter than prefix but similar.",
755 "Chrome-Proxy: fcp=1,fcp,fcp=",
760 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test
); ++i
) {
761 std::string
headers(test
[i
].headers
);
762 HeadersToRaw(&headers
);
763 scoped_refptr
<net::HttpResponseHeaders
> parsed(
764 new net::HttpResponseHeaders(headers
));
766 std::vector
<std::string
> output_values
;
767 GetDataReductionProxyHeaderWithFingerprintRemoved(parsed
, &output_values
);
769 std::string output_values_string
;
770 for (size_t j
= 0; j
< output_values
.size(); ++j
)
771 output_values_string
+= output_values
[j
] + ",";
773 EXPECT_EQ(test
[i
].expected_output_values_string
, output_values_string
)
778 } // namespace data_reduction_proxy