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 "connection: proxy-bypass\n"
100 "Chrome-Proxy: block-once\n"
101 "Content-Length: 999\n",
107 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
108 std::string headers(tests[i].headers);
109 HeadersToRaw(&headers);
110 scoped_refptr<net::HttpResponseHeaders> parsed(
111 new net::HttpResponseHeaders(headers));
113 std::string action_value;
114 bool has_action_key = GetDataReductionProxyActionValue(
115 parsed, tests[i].action_key, &action_value);
116 EXPECT_EQ(tests[i].expected_result, has_action_key);
117 if (has_action_key) {
118 EXPECT_EQ(tests[i].expected_action_value, action_value);
123 TEST_F(DataReductionProxyHeadersTest, GetProxyBypassInfo) {
126 bool expected_result;
127 int64 expected_retry_delay;
128 bool expected_bypass_all;
129 bool expected_mark_proxies_as_bad;
131 { "HTTP/1.1 200 OK\n"
132 "Content-Length: 999\n",
138 { "HTTP/1.1 200 OK\n"
139 "connection: keep-alive\n"
140 "Content-Length: 999\n",
146 { "HTTP/1.1 200 OK\n"
147 "connection: keep-alive\n"
148 "Chrome-Proxy: bypass=86400\n"
149 "Content-Length: 999\n",
155 { "HTTP/1.1 200 OK\n"
156 "connection: keep-alive\n"
157 "Chrome-Proxy: bypass=-1\n"
158 "Content-Length: 999\n",
164 { "HTTP/1.1 200 OK\n"
165 "connection: keep-alive\n"
166 "Chrome-Proxy: bypass=xyz\n"
167 "Content-Length: 999\n",
173 { "HTTP/1.1 200 OK\n"
174 "connection: keep-alive\n"
175 "Chrome-Proxy: bypass\n"
176 "Content-Length: 999\n",
182 { "HTTP/1.1 200 OK\n"
183 "connection: keep-alive\n"
184 "Chrome-Proxy: foo=abc, bypass=86400\n"
185 "Content-Length: 999\n",
191 { "HTTP/1.1 200 OK\n"
192 "connection: keep-alive\n"
193 "Chrome-Proxy: bypass=86400, bar=abc\n"
194 "Content-Length: 999\n",
200 { "HTTP/1.1 200 OK\n"
201 "connection: keep-alive\n"
202 "Chrome-Proxy: bypass=3600\n"
203 "Chrome-Proxy: bypass=86400\n"
204 "Content-Length: 999\n",
210 { "HTTP/1.1 200 OK\n"
211 "connection: keep-alive\n"
212 "Chrome-Proxy: bypass=3600, bypass=86400\n"
213 "Content-Length: 999\n",
219 { "HTTP/1.1 200 OK\n"
220 "connection: keep-alive\n"
221 "Chrome-Proxy: bypass=, bypass=86400\n"
222 "Content-Length: 999\n",
228 { "HTTP/1.1 200 OK\n"
229 "connection: keep-alive\n"
230 "Chrome-Proxy: bypass\n"
231 "Chrome-Proxy: bypass=86400\n"
232 "Content-Length: 999\n",
238 { "HTTP/1.1 200 OK\n"
239 "connection: keep-alive\n"
240 "Chrome-Proxy: block=, block=3600\n"
241 "Content-Length: 999\n",
247 { "HTTP/1.1 200 OK\n"
248 "connection: keep-alive\n"
249 "Chrome-Proxy: bypass=86400, block=3600\n"
250 "Content-Length: 999\n",
256 { "HTTP/1.1 200 OK\n"
257 "connection: proxy-bypass\n"
258 "Chrome-Proxy: block=, bypass=86400\n"
259 "Content-Length: 999\n",
265 { "HTTP/1.1 200 OK\n"
266 "connection: proxy-bypass\n"
267 "Chrome-Proxy: block=-1\n"
268 "Content-Length: 999\n",
274 { "HTTP/1.1 200 OK\n"
275 "connection: proxy-bypass\n"
276 "Chrome-Proxy: block=99999999999999999999\n"
277 "Content-Length: 999\n",
283 { "HTTP/1.1 200 OK\n"
284 "connection: keep-alive\n"
285 "Chrome-Proxy: block-once\n"
286 "Content-Length: 999\n",
292 { "HTTP/1.1 200 OK\n"
293 "connection: keep-alive\n"
294 "Chrome-Proxy: block-once=\n"
295 "Content-Length: 999\n",
301 { "HTTP/1.1 200 OK\n"
302 "connection: keep-alive\n"
303 "Chrome-Proxy: block-once=10\n"
304 "Content-Length: 999\n",
310 { "HTTP/1.1 200 OK\n"
311 "connection: keep-alive\n"
312 "Chrome-Proxy: block-once, bypass=86400, block=3600\n"
313 "Content-Length: 999\n",
319 { "HTTP/1.1 200 OK\n"
320 "connection: keep-alive\n"
321 "Chrome-Proxy: block-once\n"
322 "Chrome-Proxy: bypass=86400, block=3600\n"
323 "Content-Length: 999\n",
329 { "HTTP/1.1 200 OK\n"
330 "connection: keep-alive\n"
331 "Chrome-Proxy: block-once, bypass=86400\n"
332 "Content-Length: 999\n",
338 { "HTTP/1.1 200 OK\n"
339 "connection: keep-alive\n"
340 "Chrome-Proxy: block-once, block=3600\n"
341 "Content-Length: 999\n",
347 { "HTTP/1.1 200 OK\n"
348 "connection: keep-alive\n"
349 "Chrome-Proxy: bypass=, block=, block-once\n"
350 "Content-Length: 999\n",
357 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
358 std::string headers(tests[i].headers);
359 HeadersToRaw(&headers);
360 scoped_refptr<net::HttpResponseHeaders> parsed(
361 new net::HttpResponseHeaders(headers));
363 DataReductionProxyInfo data_reduction_proxy_info;
364 EXPECT_EQ(tests[i].expected_result,
365 ParseHeadersAndSetProxyInfo(parsed, &data_reduction_proxy_info));
366 EXPECT_EQ(tests[i].expected_retry_delay,
367 data_reduction_proxy_info.bypass_duration.InSeconds());
368 EXPECT_EQ(tests[i].expected_bypass_all,
369 data_reduction_proxy_info.bypass_all);
370 EXPECT_EQ(tests[i].expected_mark_proxies_as_bad,
371 data_reduction_proxy_info.mark_proxies_as_bad);
375 TEST_F(DataReductionProxyHeadersTest, ParseHeadersAndSetProxyInfo) {
376 std::string headers =
378 "connection: keep-alive\n"
379 "Chrome-Proxy: bypass=0\n"
380 "Content-Length: 999\n";
381 HeadersToRaw(&headers);
382 scoped_refptr<net::HttpResponseHeaders> parsed(
383 new net::HttpResponseHeaders(headers));
385 DataReductionProxyInfo data_reduction_proxy_info;
386 EXPECT_TRUE(ParseHeadersAndSetProxyInfo(parsed, &data_reduction_proxy_info));
387 EXPECT_LE(60, data_reduction_proxy_info.bypass_duration.InSeconds());
388 EXPECT_GE(5 * 60, data_reduction_proxy_info.bypass_duration.InSeconds());
389 EXPECT_FALSE(data_reduction_proxy_info.bypass_all);
392 TEST_F(DataReductionProxyHeadersTest, HasDataReductionProxyViaHeader) {
395 bool expected_result;
396 bool expected_has_intermediary;
397 bool ignore_intermediary;
399 { "HTTP/1.1 200 OK\n"
400 "Via: 1.1 Chrome-Proxy\n",
405 { "HTTP/1.1 200 OK\n"
411 { "HTTP/1.1 200 OK\n"
412 "Via: 1.1 Chrome-Compression-Proxy\n",
417 { "HTTP/1.1 200 OK\n"
418 "Via: 1.0 Chrome-Compression-Proxy\n",
423 { "HTTP/1.1 200 OK\n"
424 "Via: 1.1 Foo-Bar, 1.1 Chrome-Compression-Proxy\n",
429 { "HTTP/1.1 200 OK\n"
430 "Via: 1.1 Chrome-Compression-Proxy, 1.1 Bar-Foo\n",
435 { "HTTP/1.1 200 OK\n"
436 "Via: 1.1 chrome-compression-proxy\n",
441 { "HTTP/1.1 200 OK\n"
443 "Via: 1.1 Chrome-Compression-Proxy\n",
448 { "HTTP/1.1 200 OK\n"
449 "Via: 1.1 Chrome-Compression-Proxy\n"
450 "Via: 1.1 Foo-Bar\n",
455 { "HTTP/1.1 200 OK\n"
456 "Via: 1.1 Chrome-Proxy\n",
461 { "HTTP/1.1 200 OK\n"
462 "Via: 1.1 Chrome Compression Proxy\n",
467 { "HTTP/1.1 200 OK\n"
468 "Via: 1.1 Foo-Bar, 1.1 Chrome Compression Proxy\n",
473 { "HTTP/1.1 200 OK\n"
474 "Via: 1.1 Chrome Compression Proxy, 1.1 Bar-Foo\n",
479 { "HTTP/1.1 200 OK\n"
480 "Via: 1.1 chrome compression proxy\n",
485 { "HTTP/1.1 200 OK\n"
487 "Via: 1.1 Chrome Compression Proxy\n",
492 { "HTTP/1.1 200 OK\n"
493 "Via: 1.1 Chrome Compression Proxy\n"
494 "Via: 1.1 Foo-Bar\n",
499 { "HTTP/1.1 200 OK\n"
500 "Via: 1.1 Chrome Compression Proxy\n"
501 "Via: 1.1 Foo-Bar\n",
507 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
508 std::string headers(tests[i].headers);
509 HeadersToRaw(&headers);
510 scoped_refptr<net::HttpResponseHeaders> parsed(
511 new net::HttpResponseHeaders(headers));
513 bool has_chrome_proxy_via_header, has_intermediary;
514 if (tests[i].ignore_intermediary) {
515 has_chrome_proxy_via_header =
516 HasDataReductionProxyViaHeader(parsed, NULL);
519 has_chrome_proxy_via_header =
520 HasDataReductionProxyViaHeader(parsed, &has_intermediary);
522 EXPECT_EQ(tests[i].expected_result, has_chrome_proxy_via_header);
523 if (has_chrome_proxy_via_header && !tests[i].ignore_intermediary) {
524 EXPECT_EQ(tests[i].expected_has_intermediary, has_intermediary);
529 TEST_F(DataReductionProxyHeadersTest, GetDataReductionProxyBypassEventType) {
532 DataReductionProxyBypassType expected_result;
534 { "HTTP/1.1 200 OK\n"
535 "Chrome-Proxy: bypass=0\n"
536 "Via: 1.1 Chrome-Compression-Proxy\n",
537 BYPASS_EVENT_TYPE_MEDIUM,
539 { "HTTP/1.1 200 OK\n"
540 "Chrome-Proxy: bypass=1\n"
541 "Via: 1.1 Chrome-Compression-Proxy\n",
542 BYPASS_EVENT_TYPE_SHORT,
544 { "HTTP/1.1 200 OK\n"
545 "Chrome-Proxy: bypass=59\n"
546 "Via: 1.1 Chrome-Compression-Proxy\n",
547 BYPASS_EVENT_TYPE_SHORT,
549 { "HTTP/1.1 200 OK\n"
550 "Chrome-Proxy: bypass=60\n"
551 "Via: 1.1 Chrome-Compression-Proxy\n",
552 BYPASS_EVENT_TYPE_MEDIUM,
554 { "HTTP/1.1 200 OK\n"
555 "Chrome-Proxy: bypass=300\n"
556 "Via: 1.1 Chrome-Compression-Proxy\n",
557 BYPASS_EVENT_TYPE_MEDIUM,
559 { "HTTP/1.1 200 OK\n"
560 "Chrome-Proxy: bypass=301\n"
561 "Via: 1.1 Chrome-Compression-Proxy\n",
562 BYPASS_EVENT_TYPE_LONG,
564 { "HTTP/1.1 200 OK\n"
565 "Chrome-Proxy: block-once\n"
566 "Via: 1.1 Chrome-Compression-Proxy\n",
567 BYPASS_EVENT_TYPE_CURRENT,
569 { "HTTP/1.1 500 Internal Server Error\n"
570 "Via: 1.1 Chrome-Compression-Proxy\n",
571 BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR,
573 { "HTTP/1.1 501 Not Implemented\n"
574 "Via: 1.1 Chrome-Compression-Proxy\n",
575 BYPASS_EVENT_TYPE_MAX,
577 { "HTTP/1.1 502 Bad Gateway\n"
578 "Via: 1.1 Chrome-Compression-Proxy\n",
579 BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY,
581 { "HTTP/1.1 503 Service Unavailable\n"
582 "Via: 1.1 Chrome-Compression-Proxy\n",
583 BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE,
585 { "HTTP/1.1 504 Gateway Timeout\n"
586 "Via: 1.1 Chrome-Compression-Proxy\n",
587 BYPASS_EVENT_TYPE_MAX,
589 { "HTTP/1.1 505 HTTP Version Not Supported\n"
590 "Via: 1.1 Chrome-Compression-Proxy\n",
591 BYPASS_EVENT_TYPE_MAX,
593 { "HTTP/1.1 304 Not Modified\n",
594 BYPASS_EVENT_TYPE_MAX,
596 { "HTTP/1.1 200 OK\n",
597 BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER,
599 { "HTTP/1.1 200 OK\n"
600 "Chrome-Proxy: bypass=59\n",
601 BYPASS_EVENT_TYPE_SHORT,
603 { "HTTP/1.1 502 Bad Gateway\n",
604 BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY,
606 { "HTTP/1.1 502 Bad Gateway\n"
607 "Chrome-Proxy: bypass=59\n",
608 BYPASS_EVENT_TYPE_SHORT,
610 { "HTTP/1.1 502 Bad Gateway\n"
611 "Chrome-Proxy: bypass=59\n",
612 BYPASS_EVENT_TYPE_SHORT,
614 { "HTTP/1.1 414 Request-URI Too Long\n",
615 BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX,
617 { "HTTP/1.1 414 Request-URI Too Long\n"
618 "Via: 1.1 Chrome-Compression-Proxy\n",
619 BYPASS_EVENT_TYPE_MAX,
621 { "HTTP/1.1 407 Proxy Authentication Required\n",
622 BYPASS_EVENT_TYPE_MALFORMED_407,
624 { "HTTP/1.1 407 Proxy Authentication Required\n"
625 "Proxy-Authenticate: Basic\n"
626 "Via: 1.1 Chrome-Compression-Proxy\n",
627 BYPASS_EVENT_TYPE_MAX,
630 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
631 std::string headers(tests[i].headers);
632 HeadersToRaw(&headers);
633 scoped_refptr<net::HttpResponseHeaders> parsed(
634 new net::HttpResponseHeaders(headers));
635 DataReductionProxyInfo chrome_proxy_info;
636 EXPECT_EQ(tests[i].expected_result,
637 GetDataReductionProxyBypassType(parsed, &chrome_proxy_info));
641 TEST_F(DataReductionProxyHeadersTest,
642 GetDataReductionProxyActionFingerprintChromeProxy) {
646 bool expected_fingerprint_exist;
647 std::string expected_fingerprint;
649 { "fingerprint doesn't exist",
651 "Chrome-Proxy: bypass=0\n",
655 { "fingerprint occurs once",
657 "Chrome-Proxy: bypass=1, fcp=fp\n",
661 { "fingerprint occurs twice",
663 "Chrome-Proxy: bypass=2, fcp=fp1, fcp=fp2\n",
668 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
669 std::string headers(tests[i].headers);
670 HeadersToRaw(&headers);
671 scoped_refptr<net::HttpResponseHeaders> parsed(
672 new net::HttpResponseHeaders(headers));
674 std::string fingerprint;
675 bool fingerprint_exist = GetDataReductionProxyActionFingerprintChromeProxy(
676 parsed, &fingerprint);
677 EXPECT_EQ(tests[i].expected_fingerprint_exist, fingerprint_exist)
680 if (fingerprint_exist)
681 EXPECT_EQ(tests[i].expected_fingerprint, fingerprint) << tests[i].label;
685 TEST_F(DataReductionProxyHeadersTest,
686 GetDataReductionProxyActionFingerprintVia) {
690 bool expected_fingerprint_exist;
691 std::string expected_fingerprint;
693 { "fingerprint doesn't exist",
695 "Chrome-Proxy: bypass=0\n",
699 { "fingerprint occurs once",
701 "Chrome-Proxy: bypass=1, fvia=fvia\n",
705 { "fingerprint occurs twice",
707 "Chrome-Proxy: bypass=2, fvia=fvia1, fvia=fvia2\n",
712 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
713 std::string headers(tests[i].headers);
714 HeadersToRaw(&headers);
715 scoped_refptr<net::HttpResponseHeaders> parsed(
716 new net::HttpResponseHeaders(headers));
718 std::string fingerprint;
719 bool fingerprint_exist =
720 GetDataReductionProxyActionFingerprintVia(parsed, &fingerprint);
721 EXPECT_EQ(tests[i].expected_fingerprint_exist, fingerprint_exist)
724 if (fingerprint_exist)
725 EXPECT_EQ(tests[i].expected_fingerprint, fingerprint) << tests[i].label;
729 TEST_F(DataReductionProxyHeadersTest,
730 GetDataReductionProxyActionFingerprintOtherHeaders) {
734 bool expected_fingerprint_exist;
735 std::string expected_fingerprint;
737 { "fingerprint doesn't exist",
739 "Chrome-Proxy: bypass=0\n",
743 { "fingerprint occurs once",
745 "Chrome-Proxy: bypass=1, foh=foh\n",
749 { "fingerprint occurs twice",
751 "Chrome-Proxy: bypass=2, foh=foh1, foh=foh2\n",
756 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
757 std::string headers(tests[i].headers);
758 HeadersToRaw(&headers);
759 scoped_refptr<net::HttpResponseHeaders> parsed(
760 new net::HttpResponseHeaders(headers));
762 std::string fingerprint;
763 bool fingerprint_exist =
764 GetDataReductionProxyActionFingerprintOtherHeaders(
765 parsed, &fingerprint);
766 EXPECT_EQ(tests[i].expected_fingerprint_exist, fingerprint_exist)
769 if (fingerprint_exist)
770 EXPECT_EQ(tests[i].expected_fingerprint, fingerprint) << tests[i].label;
774 TEST_F(DataReductionProxyHeadersTest,
775 GetDataReductionProxyActionFingerprintContentLength) {
779 bool expected_fingerprint_exist;
780 std::string expected_fingerprint;
782 { "fingerprint doesn't exist",
784 "Chrome-Proxy: bypass=0\n",
788 { "fingerprint occurs once",
790 "Chrome-Proxy: bypass=1, fcl=fcl\n",
794 { "fingerprint occurs twice",
796 "Chrome-Proxy: bypass=2, fcl=fcl1, fcl=fcl2\n",
801 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
802 std::string headers(tests[i].headers);
803 HeadersToRaw(&headers);
804 scoped_refptr<net::HttpResponseHeaders> parsed(
805 new net::HttpResponseHeaders(headers));
807 std::string fingerprint;
808 bool fingerprint_exist =
809 GetDataReductionProxyActionFingerprintContentLength(
810 parsed, &fingerprint);
811 EXPECT_EQ(tests[i].expected_fingerprint_exist, fingerprint_exist)
814 if (fingerprint_exist)
815 EXPECT_EQ(tests[i].expected_fingerprint, fingerprint) << tests[i].label;
819 TEST_F(DataReductionProxyHeadersTest,
820 GetDataReductionProxyHeaderWithFingerprintRemoved) {
824 std::string expected_output_values_string;
827 "Checks the case that there is no Chrome-Proxy header's fingerprint.",
829 "Chrome-Proxy: 1,2,3,5\n",
833 "Checks the case that there is Chrome-Proxy header's fingerprint.",
835 "Chrome-Proxy: 1,2,3,fcp=4,5\n",
839 "Checks the case that there is Chrome-Proxy header's fingerprint, and it"
840 "occurs at the end.",
842 "Chrome-Proxy: 1,2,3,fcp=4,",
846 "Checks the case that there is Chrome-Proxy header's fingerprint, and it"
847 "occurs at the beginning.",
849 "Chrome-Proxy: fcp=1,2,3,",
853 "Checks the case that value is longer than prefix.",
855 "Chrome-Proxy: fcp=1,fcp!=1,fcp!=2,fcpfcp=3",
856 "fcp!=1,fcp!=2,fcpfcp=3,",
859 "Checks the case that value is shorter than prefix but similar.",
861 "Chrome-Proxy: fcp=1,fcp,fcp=",
866 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test); ++i) {
867 std::string headers(test[i].headers);
868 HeadersToRaw(&headers);
869 scoped_refptr<net::HttpResponseHeaders> parsed(
870 new net::HttpResponseHeaders(headers));
872 std::vector<std::string> output_values;
873 GetDataReductionProxyHeaderWithFingerprintRemoved(parsed, &output_values);
875 std::string output_values_string;
876 for (size_t j = 0; j < output_values.size(); ++j)
877 output_values_string += output_values[j] + ",";
879 EXPECT_EQ(test[i].expected_output_values_string, output_values_string)
884 } // namespace data_reduction_proxy