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.
4
5#include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
6
7#include <vector>
8
9#include "components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.h"
10#include "net/http/http_response_headers.h"
11#include "net/proxy/proxy_service.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14namespace data_reduction_proxy {
15
16class DataReductionProxyHeadersTest : public testing::Test {};
17
18TEST_F(DataReductionProxyHeadersTest, GetDataReductionProxyActionValue) {
19  const struct {
20     const char* headers;
21     std::string action_key;
22     bool expected_result;
23     std::string expected_action_value;
24  } tests[] = {
25    { "HTTP/1.1 200 OK\n"
26      "Content-Length: 999\n",
27      "a",
28      false,
29      "",
30    },
31    { "HTTP/1.1 200 OK\n"
32      "connection: keep-alive\n"
33      "Content-Length: 999\n",
34      "a",
35      false,
36      "",
37    },
38    { "HTTP/1.1 200 OK\n"
39      "connection: keep-alive\n"
40      "Chrome-Proxy: bypass=86400\n"
41      "Content-Length: 999\n",
42      "bypass",
43      true,
44      "86400",
45    },
46    { "HTTP/1.1 200 OK\n"
47      "connection: keep-alive\n"
48      "Chrome-Proxy: bypass86400\n"
49      "Content-Length: 999\n",
50      "bypass",
51      false,
52      "",
53    },
54    { "HTTP/1.1 200 OK\n"
55      "connection: keep-alive\n"
56      "Chrome-Proxy: bypass=0\n"
57      "Content-Length: 999\n",
58      "bypass",
59      true,
60      "0",
61    },
62    { "HTTP/1.1 200 OK\n"
63      "connection: keep-alive\n"
64      "Chrome-Proxy: bypass=1500\n"
65      "Chrome-Proxy: bypass=86400\n"
66      "Content-Length: 999\n",
67      "bypass",
68      true,
69      "1500",
70    },
71    { "HTTP/1.1 200 OK\n"
72      "connection: keep-alive\n"
73      "Chrome-Proxy: block=1500, block=3600\n"
74      "Content-Length: 999\n",
75      "block",
76      true,
77      "1500",
78    },
79    { "HTTP/1.1 200 OK\n"
80      "connection: proxy-bypass\n"
81      "Chrome-Proxy:    key=123   \n"
82      "Content-Length: 999\n",
83      "key",
84      true,
85      "123",
86    },
87    { "HTTP/1.1 200 OK\n"
88      "connection: proxy-bypass\n"
89      "Chrome-Proxy: block-once\n"
90      "Content-Length: 999\n",
91      "block-once",
92      false,
93      "",
94    },
95  };
96  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
97    std::string headers(tests[i].headers);
98    HeadersToRaw(&headers);
99    scoped_refptr<net::HttpResponseHeaders> parsed(
100        new net::HttpResponseHeaders(headers));
101
102    std::string action_value;
103    bool has_action_key = GetDataReductionProxyActionValue(
104        parsed.get(), tests[i].action_key, &action_value);
105    EXPECT_EQ(tests[i].expected_result, has_action_key);
106    if (has_action_key) {
107      EXPECT_EQ(tests[i].expected_action_value, action_value);
108    }
109  }
110}
111
112TEST_F(DataReductionProxyHeadersTest, GetProxyBypassInfo) {
113  const struct {
114     const char* headers;
115     bool expected_result;
116     int64 expected_retry_delay;
117     bool expected_bypass_all;
118     bool expected_mark_proxies_as_bad;
119  } tests[] = {
120    { "HTTP/1.1 200 OK\n"
121      "Content-Length: 999\n",
122      false,
123      0,
124      false,
125      false,
126    },
127    { "HTTP/1.1 200 OK\n"
128      "connection: keep-alive\n"
129      "Content-Length: 999\n",
130      false,
131      0,
132      false,
133      false,
134    },
135    { "HTTP/1.1 200 OK\n"
136      "connection: keep-alive\n"
137      "Chrome-Proxy: bypass=86400\n"
138      "Content-Length: 999\n",
139      true,
140      86400,
141      false,
142      true,
143    },
144    { "HTTP/1.1 200 OK\n"
145      "connection: keep-alive\n"
146      "Chrome-Proxy: bypass=-1\n"
147      "Content-Length: 999\n",
148      false,
149      0,
150      false,
151      false,
152    },
153    { "HTTP/1.1 200 OK\n"
154      "connection: keep-alive\n"
155      "Chrome-Proxy: bypass=xyz\n"
156      "Content-Length: 999\n",
157      false,
158      0,
159      false,
160      false,
161    },
162    { "HTTP/1.1 200 OK\n"
163      "connection: keep-alive\n"
164      "Chrome-Proxy: bypass\n"
165      "Content-Length: 999\n",
166      false,
167      0,
168      false,
169      false,
170    },
171    { "HTTP/1.1 200 OK\n"
172      "connection: keep-alive\n"
173      "Chrome-Proxy: foo=abc, bypass=86400\n"
174      "Content-Length: 999\n",
175      true,
176      86400,
177      false,
178      true,
179    },
180    { "HTTP/1.1 200 OK\n"
181      "connection: keep-alive\n"
182      "Chrome-Proxy: bypass=86400, bar=abc\n"
183      "Content-Length: 999\n",
184      true,
185      86400,
186      false,
187      true,
188    },
189    { "HTTP/1.1 200 OK\n"
190      "connection: keep-alive\n"
191      "Chrome-Proxy: bypass=3600\n"
192      "Chrome-Proxy: bypass=86400\n"
193      "Content-Length: 999\n",
194      true,
195      3600,
196      false,
197      true,
198    },
199    { "HTTP/1.1 200 OK\n"
200      "connection: keep-alive\n"
201      "Chrome-Proxy: bypass=3600, bypass=86400\n"
202      "Content-Length: 999\n",
203      true,
204      3600,
205      false,
206      true,
207    },
208    { "HTTP/1.1 200 OK\n"
209      "connection: keep-alive\n"
210      "Chrome-Proxy: bypass=, bypass=86400\n"
211      "Content-Length: 999\n",
212      true,
213      86400,
214      false,
215      true,
216    },
217    { "HTTP/1.1 200 OK\n"
218      "connection: keep-alive\n"
219      "Chrome-Proxy: bypass\n"
220      "Chrome-Proxy: bypass=86400\n"
221      "Content-Length: 999\n",
222      true,
223      86400,
224      false,
225      true,
226    },
227    { "HTTP/1.1 200 OK\n"
228      "connection: keep-alive\n"
229      "Chrome-Proxy: block=, block=3600\n"
230      "Content-Length: 999\n",
231      true,
232      3600,
233      true,
234      true,
235    },
236    { "HTTP/1.1 200 OK\n"
237      "connection: keep-alive\n"
238      "Chrome-Proxy: bypass=86400, block=3600\n"
239      "Content-Length: 999\n",
240      true,
241      3600,
242      true,
243      true,
244    },
245    { "HTTP/1.1 200 OK\n"
246      "connection: proxy-bypass\n"
247      "Chrome-Proxy: block=, bypass=86400\n"
248      "Content-Length: 999\n",
249      true,
250      86400,
251      false,
252      true,
253    },
254    { "HTTP/1.1 200 OK\n"
255      "connection: proxy-bypass\n"
256      "Chrome-Proxy: block=-1\n"
257      "Content-Length: 999\n",
258      false,
259      0,
260      false,
261      false,
262    },
263    { "HTTP/1.1 200 OK\n"
264      "connection: proxy-bypass\n"
265      "Chrome-Proxy: block=99999999999999999999\n"
266      "Content-Length: 999\n",
267      false,
268      0,
269      false,
270      false,
271    },
272    { "HTTP/1.1 200 OK\n"
273      "connection: keep-alive\n"
274      "Chrome-Proxy: block-once\n"
275      "Content-Length: 999\n",
276      true,
277      0,
278      true,
279      false,
280    },
281    { "HTTP/1.1 200 OK\n"
282      "connection: keep-alive\n"
283      "Chrome-Proxy: block-once=\n"
284      "Content-Length: 999\n",
285      false,
286      0,
287      false,
288      false,
289    },
290    { "HTTP/1.1 200 OK\n"
291      "connection: keep-alive\n"
292      "Chrome-Proxy: block-once=10\n"
293      "Content-Length: 999\n",
294      false,
295      0,
296      false,
297      false,
298    },
299    { "HTTP/1.1 200 OK\n"
300      "connection: keep-alive\n"
301      "Chrome-Proxy: block-once, bypass=86400, block=3600\n"
302      "Content-Length: 999\n",
303      true,
304      3600,
305      true,
306      true,
307    },
308    { "HTTP/1.1 200 OK\n"
309      "connection: keep-alive\n"
310      "Chrome-Proxy: block-once\n"
311      "Chrome-Proxy: bypass=86400, block=3600\n"
312      "Content-Length: 999\n",
313      true,
314      3600,
315      true,
316      true,
317    },
318    { "HTTP/1.1 200 OK\n"
319      "connection: keep-alive\n"
320      "Chrome-Proxy: block-once, bypass=86400\n"
321      "Content-Length: 999\n",
322      true,
323      86400,
324      false,
325      true,
326    },
327    { "HTTP/1.1 200 OK\n"
328      "connection: keep-alive\n"
329      "Chrome-Proxy: block-once, block=3600\n"
330      "Content-Length: 999\n",
331      true,
332      3600,
333      true,
334      true,
335    },
336    { "HTTP/1.1 200 OK\n"
337      "connection: keep-alive\n"
338      "Chrome-Proxy: bypass=, block=, block-once\n"
339      "Content-Length: 999\n",
340      true,
341      0,
342      true,
343      false,
344    },
345  };
346  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
347    std::string headers(tests[i].headers);
348    HeadersToRaw(&headers);
349    scoped_refptr<net::HttpResponseHeaders> parsed(
350        new net::HttpResponseHeaders(headers));
351
352    DataReductionProxyInfo data_reduction_proxy_info;
353    EXPECT_EQ(
354        tests[i].expected_result,
355        ParseHeadersAndSetProxyInfo(parsed.get(), &data_reduction_proxy_info));
356    EXPECT_EQ(tests[i].expected_retry_delay,
357              data_reduction_proxy_info.bypass_duration.InSeconds());
358    EXPECT_EQ(tests[i].expected_bypass_all,
359              data_reduction_proxy_info.bypass_all);
360    EXPECT_EQ(tests[i].expected_mark_proxies_as_bad,
361              data_reduction_proxy_info.mark_proxies_as_bad);
362  }
363}
364
365TEST_F(DataReductionProxyHeadersTest, ParseHeadersAndSetProxyInfo) {
366  std::string headers =
367      "HTTP/1.1 200 OK\n"
368      "connection: keep-alive\n"
369      "Chrome-Proxy: bypass=0\n"
370      "Content-Length: 999\n";
371  HeadersToRaw(&headers);
372  scoped_refptr<net::HttpResponseHeaders> parsed(
373      new net::HttpResponseHeaders(headers));
374
375  DataReductionProxyInfo data_reduction_proxy_info;
376  EXPECT_TRUE(
377      ParseHeadersAndSetProxyInfo(parsed.get(), &data_reduction_proxy_info));
378  EXPECT_LE(60, data_reduction_proxy_info.bypass_duration.InSeconds());
379  EXPECT_GE(5 * 60, data_reduction_proxy_info.bypass_duration.InSeconds());
380  EXPECT_FALSE(data_reduction_proxy_info.bypass_all);
381}
382
383TEST_F(DataReductionProxyHeadersTest, HasDataReductionProxyViaHeader) {
384  const struct {
385    const char* headers;
386    bool expected_result;
387    bool expected_has_intermediary;
388    bool ignore_intermediary;
389  } tests[] = {
390    { "HTTP/1.1 200 OK\n"
391      "Via: 1.1 Chrome-Proxy\n",
392      false,
393      false,
394      false,
395    },
396    { "HTTP/1.1 200 OK\n"
397      "Via: 1\n",
398      false,
399      false,
400      false,
401    },
402    { "HTTP/1.1 200 OK\n"
403      "Via: 1.1 Chrome-Compression-Proxy\n",
404      true,
405      true,
406      false,
407    },
408    { "HTTP/1.1 200 OK\n"
409      "Via: 1.0 Chrome-Compression-Proxy\n",
410      true,
411      true,
412      false,
413    },
414    { "HTTP/1.1 200 OK\n"
415      "Via: 1.1 Foo-Bar, 1.1 Chrome-Compression-Proxy\n",
416      true,
417      true,
418      false,
419    },
420    { "HTTP/1.1 200 OK\n"
421      "Via: 1.1 Chrome-Compression-Proxy, 1.1 Bar-Foo\n",
422      true,
423      false,
424      false,
425    },
426    { "HTTP/1.1 200 OK\n"
427      "Via: 1.1 chrome-compression-proxy\n",
428      false,
429      false,
430      false,
431    },
432    { "HTTP/1.1 200 OK\n"
433      "Via: 1.1 Foo-Bar\n"
434      "Via: 1.1 Chrome-Compression-Proxy\n",
435      true,
436      true,
437      false,
438    },
439    { "HTTP/1.1 200 OK\n"
440      "Via: 1.1 Chrome-Compression-Proxy\n"
441      "Via: 1.1 Foo-Bar\n",
442      true,
443      false,
444      false,
445    },
446    { "HTTP/1.1 200 OK\n"
447      "Via: 1.1 Chrome-Proxy\n",
448      false,
449      false,
450      false,
451    },
452    { "HTTP/1.1 200 OK\n"
453      "Via: 1.1 Chrome Compression Proxy\n",
454      true,
455      true,
456      false,
457    },
458    { "HTTP/1.1 200 OK\n"
459      "Via: 1.1 Foo-Bar, 1.1 Chrome Compression Proxy\n",
460      true,
461      true,
462      false,
463    },
464    { "HTTP/1.1 200 OK\n"
465      "Via: 1.1 Chrome Compression Proxy, 1.1 Bar-Foo\n",
466      true,
467      false,
468      false,
469    },
470    { "HTTP/1.1 200 OK\n"
471      "Via: 1.1 chrome compression proxy\n",
472      false,
473      false,
474      false,
475    },
476    { "HTTP/1.1 200 OK\n"
477      "Via: 1.1 Foo-Bar\n"
478      "Via: 1.1 Chrome Compression Proxy\n",
479      true,
480      true,
481      false,
482    },
483    { "HTTP/1.1 200 OK\n"
484      "Via: 1.1 Chrome Compression Proxy\n"
485      "Via: 1.1 Foo-Bar\n",
486      true,
487      false,
488      false,
489    },
490    { "HTTP/1.1 200 OK\n"
491      "Via: 1.1 Chrome Compression Proxy\n"
492      "Via: 1.1 Foo-Bar\n",
493      true,
494      false,
495      true,
496    },
497  };
498  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
499    std::string headers(tests[i].headers);
500    HeadersToRaw(&headers);
501    scoped_refptr<net::HttpResponseHeaders> parsed(
502        new net::HttpResponseHeaders(headers));
503
504    bool has_chrome_proxy_via_header, has_intermediary;
505    if (tests[i].ignore_intermediary) {
506      has_chrome_proxy_via_header =
507          HasDataReductionProxyViaHeader(parsed.get(), NULL);
508    }
509    else {
510      has_chrome_proxy_via_header =
511          HasDataReductionProxyViaHeader(parsed.get(), &has_intermediary);
512    }
513    EXPECT_EQ(tests[i].expected_result, has_chrome_proxy_via_header);
514    if (has_chrome_proxy_via_header && !tests[i].ignore_intermediary) {
515      EXPECT_EQ(tests[i].expected_has_intermediary, has_intermediary);
516    }
517  }
518}
519
520TEST_F(DataReductionProxyHeadersTest, GetDataReductionProxyBypassEventType) {
521  const struct {
522     const char* headers;
523     DataReductionProxyBypassType expected_result;
524  } tests[] = {
525    { "HTTP/1.1 200 OK\n"
526      "Chrome-Proxy: bypass=0\n"
527      "Via: 1.1 Chrome-Compression-Proxy\n",
528      BYPASS_EVENT_TYPE_MEDIUM,
529    },
530    { "HTTP/1.1 200 OK\n"
531      "Chrome-Proxy: bypass=1\n"
532      "Via: 1.1 Chrome-Compression-Proxy\n",
533      BYPASS_EVENT_TYPE_SHORT,
534    },
535    { "HTTP/1.1 200 OK\n"
536      "Chrome-Proxy: bypass=59\n"
537      "Via: 1.1 Chrome-Compression-Proxy\n",
538      BYPASS_EVENT_TYPE_SHORT,
539    },
540    { "HTTP/1.1 200 OK\n"
541      "Chrome-Proxy: bypass=60\n"
542      "Via: 1.1 Chrome-Compression-Proxy\n",
543      BYPASS_EVENT_TYPE_MEDIUM,
544    },
545    { "HTTP/1.1 200 OK\n"
546      "Chrome-Proxy: bypass=300\n"
547      "Via: 1.1 Chrome-Compression-Proxy\n",
548      BYPASS_EVENT_TYPE_MEDIUM,
549    },
550    { "HTTP/1.1 200 OK\n"
551      "Chrome-Proxy: bypass=301\n"
552      "Via: 1.1 Chrome-Compression-Proxy\n",
553      BYPASS_EVENT_TYPE_LONG,
554    },
555    { "HTTP/1.1 200 OK\n"
556      "Chrome-Proxy: block-once\n"
557      "Via: 1.1 Chrome-Compression-Proxy\n",
558      BYPASS_EVENT_TYPE_CURRENT,
559    },
560    { "HTTP/1.1 500 Internal Server Error\n"
561      "Via: 1.1 Chrome-Compression-Proxy\n",
562      BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR,
563    },
564    { "HTTP/1.1 501 Not Implemented\n"
565      "Via: 1.1 Chrome-Compression-Proxy\n",
566      BYPASS_EVENT_TYPE_MAX,
567    },
568    { "HTTP/1.1 502 Bad Gateway\n"
569      "Via: 1.1 Chrome-Compression-Proxy\n",
570      BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY,
571    },
572    { "HTTP/1.1 503 Service Unavailable\n"
573      "Via: 1.1 Chrome-Compression-Proxy\n",
574      BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE,
575    },
576    { "HTTP/1.1 504 Gateway Timeout\n"
577      "Via: 1.1 Chrome-Compression-Proxy\n",
578      BYPASS_EVENT_TYPE_MAX,
579    },
580    { "HTTP/1.1 505 HTTP Version Not Supported\n"
581      "Via: 1.1 Chrome-Compression-Proxy\n",
582      BYPASS_EVENT_TYPE_MAX,
583    },
584    { "HTTP/1.1 304 Not Modified\n",
585        BYPASS_EVENT_TYPE_MAX,
586    },
587    { "HTTP/1.1 200 OK\n",
588        BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER,
589    },
590    { "HTTP/1.1 200 OK\n"
591      "Chrome-Proxy: bypass=59\n",
592      BYPASS_EVENT_TYPE_SHORT,
593    },
594    { "HTTP/1.1 502 Bad Gateway\n",
595        BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY,
596    },
597    { "HTTP/1.1 502 Bad Gateway\n"
598      "Chrome-Proxy: bypass=59\n",
599      BYPASS_EVENT_TYPE_SHORT,
600    },
601    { "HTTP/1.1 502 Bad Gateway\n"
602      "Chrome-Proxy: bypass=59\n",
603      BYPASS_EVENT_TYPE_SHORT,
604    },
605    { "HTTP/1.1 414 Request-URI Too Long\n",
606        BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX,
607    },
608    { "HTTP/1.1 414 Request-URI Too Long\n"
609      "Via: 1.1 Chrome-Compression-Proxy\n",
610      BYPASS_EVENT_TYPE_MAX,
611    },
612    { "HTTP/1.1 407 Proxy Authentication Required\n",
613        BYPASS_EVENT_TYPE_MALFORMED_407,
614    },
615    { "HTTP/1.1 407 Proxy Authentication Required\n"
616      "Proxy-Authenticate: Basic\n"
617      "Via: 1.1 Chrome-Compression-Proxy\n",
618      BYPASS_EVENT_TYPE_MAX,
619    }
620  };
621  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
622    std::string headers(tests[i].headers);
623    HeadersToRaw(&headers);
624    scoped_refptr<net::HttpResponseHeaders> parsed(
625        new net::HttpResponseHeaders(headers));
626    DataReductionProxyInfo chrome_proxy_info;
627    EXPECT_EQ(
628        tests[i].expected_result,
629        GetDataReductionProxyBypassType(parsed.get(), &chrome_proxy_info));
630  }
631}
632
633TEST_F(DataReductionProxyHeadersTest,
634       GetDataReductionProxyActionFingerprintChromeProxy) {
635  const struct {
636     std::string label;
637     const char* headers;
638     bool expected_fingerprint_exist;
639     std::string expected_fingerprint;
640  } tests[] = {
641    { "fingerprint doesn't exist",
642      "HTTP/1.1 200 OK\n"
643      "Chrome-Proxy: bypass=0\n",
644      false,
645      "",
646    },
647    { "fingerprint occurs once",
648      "HTTP/1.1 200 OK\n"
649      "Chrome-Proxy: bypass=1, fcp=fp\n",
650      true,
651      "fp",
652    },
653    { "fingerprint occurs twice",
654      "HTTP/1.1 200 OK\n"
655      "Chrome-Proxy: bypass=2, fcp=fp1, fcp=fp2\n",
656      true,
657      "fp1",
658    },
659  };
660  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
661    std::string headers(tests[i].headers);
662    HeadersToRaw(&headers);
663    scoped_refptr<net::HttpResponseHeaders> parsed(
664        new net::HttpResponseHeaders(headers));
665
666    std::string fingerprint;
667    bool fingerprint_exist = GetDataReductionProxyActionFingerprintChromeProxy(
668        parsed.get(), &fingerprint);
669    EXPECT_EQ(tests[i].expected_fingerprint_exist, fingerprint_exist)
670        << tests[i].label;
671
672    if (fingerprint_exist)
673      EXPECT_EQ(tests[i].expected_fingerprint, fingerprint) << tests[i].label;
674  }
675}
676
677TEST_F(DataReductionProxyHeadersTest,
678       GetDataReductionProxyActionFingerprintVia) {
679  const struct {
680     std::string label;
681     const char* headers;
682     bool expected_fingerprint_exist;
683     std::string expected_fingerprint;
684  } tests[] = {
685    { "fingerprint doesn't exist",
686      "HTTP/1.1 200 OK\n"
687      "Chrome-Proxy: bypass=0\n",
688      false,
689      "",
690    },
691    { "fingerprint occurs once",
692      "HTTP/1.1 200 OK\n"
693      "Chrome-Proxy: bypass=1, fvia=fvia\n",
694      true,
695      "fvia",
696    },
697    { "fingerprint occurs twice",
698      "HTTP/1.1 200 OK\n"
699      "Chrome-Proxy: bypass=2, fvia=fvia1, fvia=fvia2\n",
700      true,
701      "fvia1",
702    },
703  };
704  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
705    std::string headers(tests[i].headers);
706    HeadersToRaw(&headers);
707    scoped_refptr<net::HttpResponseHeaders> parsed(
708        new net::HttpResponseHeaders(headers));
709
710    std::string fingerprint;
711    bool fingerprint_exist =
712        GetDataReductionProxyActionFingerprintVia(parsed.get(), &fingerprint);
713    EXPECT_EQ(tests[i].expected_fingerprint_exist, fingerprint_exist)
714        << tests[i].label;
715
716    if (fingerprint_exist)
717      EXPECT_EQ(tests[i].expected_fingerprint, fingerprint) << tests[i].label;
718  }
719}
720
721TEST_F(DataReductionProxyHeadersTest,
722       GetDataReductionProxyActionFingerprintOtherHeaders) {
723  const struct {
724     std::string label;
725     const char* headers;
726     bool expected_fingerprint_exist;
727     std::string expected_fingerprint;
728  } tests[] = {
729    { "fingerprint doesn't exist",
730      "HTTP/1.1 200 OK\n"
731      "Chrome-Proxy: bypass=0\n",
732      false,
733      "",
734    },
735    { "fingerprint occurs once",
736      "HTTP/1.1 200 OK\n"
737      "Chrome-Proxy: bypass=1, foh=foh\n",
738      true,
739      "foh",
740    },
741    { "fingerprint occurs twice",
742      "HTTP/1.1 200 OK\n"
743      "Chrome-Proxy: bypass=2, foh=foh1, foh=foh2\n",
744      true,
745      "foh1",
746    },
747  };
748  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
749    std::string headers(tests[i].headers);
750    HeadersToRaw(&headers);
751    scoped_refptr<net::HttpResponseHeaders> parsed(
752        new net::HttpResponseHeaders(headers));
753
754    std::string fingerprint;
755    bool fingerprint_exist = GetDataReductionProxyActionFingerprintOtherHeaders(
756        parsed.get(), &fingerprint);
757    EXPECT_EQ(tests[i].expected_fingerprint_exist, fingerprint_exist)
758        << tests[i].label;
759
760    if (fingerprint_exist)
761      EXPECT_EQ(tests[i].expected_fingerprint, fingerprint) << tests[i].label;
762  }
763}
764
765TEST_F(DataReductionProxyHeadersTest,
766       GetDataReductionProxyActionFingerprintContentLength) {
767  const struct {
768     std::string label;
769     const char* headers;
770     bool expected_fingerprint_exist;
771     std::string expected_fingerprint;
772  } tests[] = {
773    { "fingerprint doesn't exist",
774      "HTTP/1.1 200 OK\n"
775      "Chrome-Proxy: bypass=0\n",
776      false,
777      "",
778    },
779    { "fingerprint occurs once",
780      "HTTP/1.1 200 OK\n"
781      "Chrome-Proxy: bypass=1, fcl=fcl\n",
782      true,
783      "fcl",
784    },
785    { "fingerprint occurs twice",
786      "HTTP/1.1 200 OK\n"
787      "Chrome-Proxy: bypass=2, fcl=fcl1, fcl=fcl2\n",
788      true,
789      "fcl1",
790    },
791  };
792  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
793    std::string headers(tests[i].headers);
794    HeadersToRaw(&headers);
795    scoped_refptr<net::HttpResponseHeaders> parsed(
796        new net::HttpResponseHeaders(headers));
797
798    std::string fingerprint;
799    bool fingerprint_exist =
800        GetDataReductionProxyActionFingerprintContentLength(parsed.get(),
801                                                            &fingerprint);
802    EXPECT_EQ(tests[i].expected_fingerprint_exist, fingerprint_exist)
803        << tests[i].label;
804
805    if (fingerprint_exist)
806      EXPECT_EQ(tests[i].expected_fingerprint, fingerprint) << tests[i].label;
807  }
808}
809
810TEST_F(DataReductionProxyHeadersTest,
811       GetDataReductionProxyHeaderWithFingerprintRemoved) {
812  const struct {
813    std::string label;
814    const char* headers;
815    std::string expected_output_values_string;
816  } test[] = {
817    {
818      "Checks the case that there is no Chrome-Proxy header's fingerprint.",
819      "HTTP/1.1 200 OK\n"
820      "Chrome-Proxy: 1,2,3,5\n",
821      "1,2,3,5,",
822    },
823    {
824      "Checks the case that there is Chrome-Proxy header's fingerprint.",
825      "HTTP/1.1 200 OK\n"
826      "Chrome-Proxy: 1,2,3,fcp=4,5\n",
827      "1,2,3,5,",
828    },
829    {
830      "Checks the case that there is Chrome-Proxy header's fingerprint, and it"
831      "occurs at the end.",
832      "HTTP/1.1 200 OK\n"
833      "Chrome-Proxy: 1,2,3,fcp=4,",
834      "1,2,3,",
835    },
836    {
837      "Checks the case that there is Chrome-Proxy header's fingerprint, and it"
838      "occurs at the beginning.",
839      "HTTP/1.1 200 OK\n"
840      "Chrome-Proxy: fcp=1,2,3,",
841      "2,3,",
842    },
843    {
844      "Checks the case that value is longer than prefix.",
845      "HTTP/1.1 200 OK\n"
846      "Chrome-Proxy: fcp=1,fcp!=1,fcp!=2,fcpfcp=3",
847      "fcp!=1,fcp!=2,fcpfcp=3,",
848    },
849    {
850      "Checks the case that value is shorter than prefix but similar.",
851      "HTTP/1.1 200 OK\n"
852      "Chrome-Proxy: fcp=1,fcp,fcp=",
853      "fcp,fcp=,",
854    },
855  };
856
857  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test); ++i) {
858    std::string headers(test[i].headers);
859    HeadersToRaw(&headers);
860    scoped_refptr<net::HttpResponseHeaders> parsed(
861        new net::HttpResponseHeaders(headers));
862
863    std::vector<std::string> output_values;
864    GetDataReductionProxyHeaderWithFingerprintRemoved(parsed.get(),
865                                                      &output_values);
866
867    std::string output_values_string;
868    for (size_t j = 0; j < output_values.size(); ++j)
869      output_values_string += output_values[j] + ",";
870
871    EXPECT_EQ(test[i].expected_output_values_string, output_values_string)
872        << test[i].label;
873  }
874}
875
876}  // namespace data_reduction_proxy
877