Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(183)

Side by Side Diff: components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detect_unittest.cc

Issue 338483002: Chrome Participated Tamper Detect (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/browser/data_reduction_proxy_tamper_de tect.h"
6
7 #include <string.h>
8 #include <algorithm>
9 #include <map>
10 #include <vector>
11
12 #include "base/base64.h"
13 #include "base/md5.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_split.h"
16 #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
17 #include "net/android/network_library.h"
18 #include "net/http/http_response_headers.h"
19 #include "net/http/http_util.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace {
23
24 void HeadersToRaw(std::string* headers) {
25 std::replace(headers->begin(), headers->end(), '\n', '\0');
26 if (!headers->empty())
27 *headers += '\0';
28 }
29
30 // Calcuates MD5 hash value for a string and then base64 encode it.
31 static std::string GetEncoded(const std::string& input) {
32 base::MD5Digest digest;
33 base::MD5Sum(input.c_str(), input.size(), &digest);
34 std::string base64encoded;
35 base::Base64Encode(std::string((char*)digest.a,
36 ARRAYSIZE_UNSAFE(digest.a)), &base64encoded);
37 return base64encoded;
38 }
39
40 // Replaces all contents within "[]" by corresponding base64 encoded MD5 value.
41 void ReplaceWithEncodedString(std::string* input)
42 {
43 size_t start, end;
44 while (true) {
45 start = input->find("[");
46 if (start == std::string::npos) break;
47 end = input->find("]", start);
48 std::string need_to_encode = input->substr(start + 1, end - start - 1);
49 *input = input->substr(0, start) + GetEncoded(need_to_encode) +
50 input->substr(end + 1);
51 }
52 }
53
54 // Testcase for fingerprint checking functions. |received_fingerprint| is
55 // fingerprint received from the data reduction proxy. |expected_tampered| is
56 // expected tampered or not result.
57 struct TestCaseCheckingFingerprint {
58 std::string raw_header;
59 std::string received_fingerprint;
60 bool expected_tampered;
61 };
62
63 } // namespace
64
65 namespace data_reduction_proxy {
66
67 class DataReductionProxyTamperDetectionTest : public testing::Test {
68 public:
69 static void TestFingerprintCommon(const TestCaseCheckingFingerprint& test,
70 DataReductionProxyTamperDetection::FingerprintCode fingerprint);
71 };
72
73 // Common function for testing fingerprint checking functions. For a given
74 // header string |test.raw_header|, generates HttpResponseHeaders |headers| and
75 // checks specified fingerprint checking function returns expected result or
76 // not.
77 void DataReductionProxyTamperDetectionTest::TestFingerprintCommon(
78 const TestCaseCheckingFingerprint& test,
79 DataReductionProxyTamperDetection::FingerprintCode fingerprint) {
80 std::string raw_headers(test.raw_header);
81 HeadersToRaw(&raw_headers);
82 scoped_refptr<net::HttpResponseHeaders> headers(
83 new net::HttpResponseHeaders(raw_headers));
84
85 // Removes Chrome-Proxy header's fingerprint from Chrome-Proxy header.
86 std::vector<std::string> chrome_proxy_header_values =
87 DataReductionProxyTamperDetection::
88 GetHeaderValues(headers, "Chrome-Proxy");
89
90 DataReductionProxyTamperDetection::RemoveChromeProxyFingerprint(
91 &chrome_proxy_header_values);
92
93 DataReductionProxyTamperDetection tamper_detection(
94 headers, true, 0, &chrome_proxy_header_values);
95
96 bool tampered;
97 switch (fingerprint) {
98 case DataReductionProxyTamperDetection::CHROMEPROXY:
99 tampered = tamper_detection.IsChromeProxyHeaderTampered(
100 test.received_fingerprint);
101 break;
102 case DataReductionProxyTamperDetection::VIA:
103 tampered = tamper_detection.IsViaHeaderTampered(
104 test.received_fingerprint);
105 break;
106 case DataReductionProxyTamperDetection::OTHERHEADERS:
107 tampered = tamper_detection.AreOtherHeadersTampered(
108 test.received_fingerprint);
109 break;
110 case DataReductionProxyTamperDetection::CONTENTLENGTH:
111 tampered = tamper_detection.IsContentLengthHeaderTampered(
112 test.received_fingerprint);
113 break;
114 case DataReductionProxyTamperDetection::NONEXIST:
115 break;
116 }
117
118 EXPECT_EQ(test.expected_tampered, tampered);
119 }
120
121 // Checks function IsChromeProxyHeaderTampered.
122 TEST_F(DataReductionProxyTamperDetectionTest, ChromeProxy) {
123 TestCaseCheckingFingerprint test[] = {
124 // Checks sorting values and decoding.
125 {
126 "HTTP/1.1 200 OK \n"
127 "Chrome-Proxy: aut=aauutthh,"
128 "fp=123,bbbypas=0,aaxxx=xxx,bbbloc=1\n",
129 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,fp=123,",
130 false,
131 },
132
133 // Checks Chrome-Proxy's fingerprint removing.
134 {
135 "HTTP/1.1 200 OK \n"
136 "Chrome-Proxy: a,b,c,d,e,3,2,1," +
137 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
138 "=1231\n",
139 "1,2,3,a,b,c,d,e,",
140 false,
141 },
142
143 // Checks no Chrome-Proxy header case (should not happen).
144 {
145 "HTTP/1.1 200 OK \n"
146 "Content-Length: 12345\n",
147 "",
148 false,
149 },
150
151 // Checks empty Chrome-Proxy header case (should not happen).
152 {
153 "HTTP/1.1 200 OK \n"
154 "Chrome-Proxy: \n",
155 ",",
156 false,
157 },
158
159 // Checks Chrome-Proxy header with its fingerprint only case.
160 {
161 "HTTP/1.1 200 OK \n"
162 "Chrome-Proxy: " +
163 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
164 "=xyz\n",
165 "",
166 false,
167 },
168
169 // Checks empty Chrome-Proxy header case, with extra ","
170 {
171 "HTTP/1.1 200 OK \n"
172 "Chrome-Proxy: " +
173 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
174 "=abcde , \n",
175 "",
176 false,
177 },
178
179 // Checks empty Chrome-Proxy header, different to fingerprint.
180 {
181 "HTTP/1.1 200 OK \n"
182 "Chrome-Proxy: " +
183 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
184 "=xyz\n",
185 ",",
186 true,
187 },
188
189 // Chrome-Proxy header different to its fingerprint.
190 {
191 "HTTP/1.1 200 OK \n"
192 "Chrome-Proxy: aut=aauutthh,bbbypas=2,aaxxx=xxx,bbbloc=1\n",
193 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,",
194 true,
195 },
196
197 // Chrome-Proxy header different to its fingerprint.
198 {
199 "HTTP/1.1 200 OK \n"
200 "Chrome-Proxy: a,aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n",
201 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,",
202 true,
203 },
204
205 // Chrome-Proxy header different to its fingerprint in order.
206 {
207 "HTTP/1.1 200 OK \n"
208 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n",
209 "aaxxx=xxx,aut=aauutthh,bbbypas=0,bbbloc=1,",
210 true,
211 },
212
213 // Checks Chrome-Proxy header with extra " ".
214 {
215 "HTTP/1.1 200 OK \n"
216 "Chrome-Proxy: aut=aauutthh , bbbypas=0 , aaxxx=xxx"
217 " ,bbbloc=1 \n",
218 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,",
219 false
220 },
221
222 // Check Chrome-Proxy header, with extra lines and " ".
223 {
224 "HTTP/1.1 200 OK \n"
225 "Chrome-Proxy: aut=aauutthh , bbbypas=0 , bbbloc=1 \n"
226 "Chrome-Proxy: aaxxx=xxx \n",
227 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,",
228 false
229 },
230
231 // Checks Chrome-Proxy header with multiple lines.
232 {
233 "HTTP/1.1 200 OK \n"
234 "Chrome-Proxy: aaxxx=xxx \n"
235 "Chrome-Proxy: aut=aauutthh\n"
236 "Chrome-Proxy: bbbypas=0\n"
237 "Chrome-Proxy:bbbloc=1 \n",
238 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,",
239 false
240 },
241
242 // Checks Chrome-Proxy header with multiple lines, at different positions
243 // of the entire header.
244 {
245 "HTTP/1.1 200 OK \n"
246 "Chrome-Proxy: aaxxx=xxx \n"
247 "Chrome-Proxy: aut=aauutthh\n"
248 "Content-Type: 1\n"
249 "Cache-Control: 2\n"
250 "ETag: 3\n"
251 "Chrome-Proxy: bbbypas=0\n"
252 "Connection: 4\n"
253 "Expires: 5\n"
254 "Chrome-Proxy: bbbloc=1\n"
255 "Via: \n"
256 "Content-Length: 12345\n"
257 "fp=123 \n",
258 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,",
259 false
260 },
261
262 // Checks Chrome-Proxy header with multiple same values.
263 {
264 "HTTP/1.1 200 OK \n"
265 "Chrome-Proxy: aaxxx=xxx \n"
266 "Chrome-Proxy: aut=aauutthh\n"
267 "Content-Type: 1\n"
268 "Cache-Control: 2\n"
269 "ETag: 3\n"
270 "Chrome-Proxy: bbbypas=0\n"
271 "Connection: 4\n"
272 "Expires: 5\n"
273 "Chrome-Proxy: bbbloc=1, fp=123 \n"
274 "Chrome-Proxy: aaxxx=xxx \n"
275 "Via: \n"
276 "Content-Length: 12345\n",
277 "aaxxx=xxx,aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,fp=123,",
278 false
279 },
280
281 // Checks Chrome-Proxy header with multiple same values.
282 {
283 "HTTP/1.1 200 OK \n"
284 "Chrome-Proxy: aaxxx=xxx \n"
285 "Chrome-Proxy: aut=aauutthh\n"
286 "Content-Type: 1\n"
287 "Cache-Control: 2\n"
288 "ETag: 3\n"
289 "Chrome-Proxy: bbbypas=0\n"
290 "Connection: 4\n"
291 "Expires: 5\n"
292 "Chrome-Proxy: bbbloc=1, fp=123 \n" +
293 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
294 "xyn \n" +
295 "Chrome-Proxy: aaxxx=xxx \n"
296 "Via: \n"
297 "Content-Length: 12345\n",
298 "aaxxx=xxx,aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,fp=123,",
299 false
300 },
301
302 // Checks Chrome-Proxy header with multiple same values, but different to
303 // fingerprint.
304 {
305 "HTTP/1.1 200 OK \n"
306 "Chrome-Proxy: aaxxx=xxx \n"
307 "Chrome-Proxy: aaxxx=xxx \n"
308 "Chrome-Proxy: aut=aauutthh\n"
309 "Content-Type: 1\n"
310 "Cache-Control: 2\n"
311 "ETag: 3\n"
312 "Chrome-Proxy: bbbypas=0\n"
313 "Connection: 4\n"
314 "Expires: 5\n"
315 "Chrome-Proxy: bbbloc=1\n"
316 "Chrome-Proxy: aaxxx=xxx \n"
317 "Via: \n"
318 "Content-Length: 12345\n",
319 "aaxxx=xxx,aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,",
320 true,
321 },
322
323 // Check Chrome-Proxy header with multiple same values, but different to
324 // fingerprint.
325 {
326 "HTTP/1.1 200 OK \n"
327 "Chrome-Proxy: aaxxx=xxx \n"
328 "Chrome-Proxy: aaxxx=xxx \n"
329 "Chrome-Proxy: aut=aauutthh\n"
330 "Content-Type: 1\n"
331 "Cache-Control: 2\n"
332 "ETag: 3\n"
333 "Chrome-Proxy: bbbypas=0\n"
334 "Connection: 4\n"
335 "Expires: 5\n" +
336 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
337 "xyn \n" +
338 "Chrome-Proxy: bbbloc=1\n"
339 "Chrome-Proxy: aaxxx=xxx \n"
340 "Via: \n"
341 "Content-Length: 12345\n",
342 "aaxxx=xxx,aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,",
343 true,
344 },
345
346 // Check Chrome-Proxy header with multiple lines, but different to
347 // fingerprint.
348 {
349 "HTTP/1.1 200 OK \n"
350 "Content-Type: 1\n"
351 "Cache-Control: 2\n"
352 "ETag: 3\n"
353 "Chrome-Proxy: bbbypas=0\n"
354 "Connection: 4\n"
355 "Expires: 5\n"
356 "Chrome-Proxy: bbbloc=1\n"
357 "Chrome-Proxy: aaxxx=xxx \n"
358 "Via: \n"
359 "Content-Length: 12345\n",
360 "aaxxx=xxx,aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,",
361 true,
362 },
363
364 // Checks case whose received fingerprint is empty.
365 {
366 "HTTP/1.1 200 OK \n"
367 "Chrome-Proxy: aaxxx=xxx \n"
368 "Chrome-Proxy: aaxxx=xxx \n"
369 "Chrome-Proxy: aut=aauutthh\n"
370 "Content-Type: 1\n"
371 "Cache-Control: 2\n"
372 "ETag: 3\n"
373 "Chrome-Proxy: bbbypas=0\n"
374 "Connection: 4\n"
375 "Expires: 5\n"
376 "Chrome-Proxy: bbbloc=1\n"
377 "Chrome-Proxy: aaxxx=xxx \n"
378 "Via: \n"
379 "Content-Length: 12345\n",
380 "",
381 true,
382 },
383
384 };
385
386 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) {
387 test[i].received_fingerprint =
388 GetEncoded(test[i].received_fingerprint);
389
390 DataReductionProxyTamperDetectionTest::TestFingerprintCommon(test[i],
391 DataReductionProxyTamperDetection::CHROMEPROXY);
392 }
393 }
394
395 // Check function IsViaHeaderTampered.
396 TEST_F(DataReductionProxyTamperDetectionTest, Via) {
397 TestCaseCheckingFingerprint test[] = {
398 // Checks the case that Chrome-Compression-Proxy occurs at the last.
399 {
400 "HTTP/1.1 200 OK \n"
401 "Via: a, b, c, 1.1 Chrome-Compression-Proxy\n",
402 "0",
403 false
404 },
405
406 // Checks when there is intermediary between the data reduction proxy and
407 // the Chromium client.
408 {
409 "HTTP/1.1 200 OK \n"
410 "Via: a, b, c, 1.1 Chrome-Compression-Proxy, xyz\n",
411 "0",
412 true,
413 },
414
415 // Checks the case of empty Via header.
416 {
417 "HTTP/1.1 200 OK \n"
418 "Via: \n",
419 "0",
420 false,
421 },
422
423 // Checks the case that only the data reduction proxy's Via header occurs.
424 {
425 "HTTP/1.1 200 OK \n"
426 "Via: 1.1 Chrome-Compression-Proxy \n",
427 "0",
428 false
429 },
430
431 // Checks the case that there are " ", i.e., empty value after the data
432 // reduction proxy's Via header.
433 {
434 "HTTP/1.1 200 OK \n"
435 "Via: 1.1 Chrome-Compression-Proxy , , \n",
436 "0",
437 false
438 },
439
440 // Checks the case when there is no Via header
441 {
442 "HTTP/1.1 200 OK \n",
443 "0",
444 false
445 },
446
447 // Same to above test cases, but with deprecated data reduciton proxy Via
448 // header.
449 {
450 "HTTP/1.1 200 OK \n"
451 "Via: a, b, c, 1.1 Chrome Compression Proxy\n",
452 "0",
453 false
454 },
455
456 {
457 "HTTP/1.1 200 OK \n"
458 "Via: a, b, c, 1.1 Chrome Compression Proxy, xyz\n",
459 "0",
460 true,
461 },
462
463 {
464 "HTTP/1.1 200 OK \n"
465 "Via: \n",
466 "0",
467 false,
468 },
469
470 {
471 "HTTP/1.1 200 OK \n"
472 "Via: 1.1 Chrome Compression Proxy \n",
473 "0",
474 false
475 },
476
477 {
478 "HTTP/1.1 200 OK \n"
479 "Via: 1.1 Chrome Compression Proxy , , \n",
480 "0",
481 false
482 },
483
484 {
485 "HTTP/1.1 200 OK \n",
486 "0",
487 false
488 },
489 };
490
491 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) {
492 DataReductionProxyTamperDetectionTest::TestFingerprintCommon(test[i],
493 DataReductionProxyTamperDetection::VIA);
494 }
495 }
496
497 // Checks function AreOtherHeadersTampered.
498 TEST_F(DataReductionProxyTamperDetectionTest, OtherHeaders) {
499 // For following testcases, |received_fingerprint| is not the actual
500 // fingerprint from data reduction proxy, instead, the base64 encoded field
501 // is in plain text (within "[]") and needs to be encoded first. For example,
502 // "[12345;]:content-length" needs to be encoded to
503 // "Base64Encoded(MD5(12345;)):content-length" before calling the checking
504 // function.
505 TestCaseCheckingFingerprint test[] = {
506 // Checks the case of correct fingerprint.
507 {
508 "HTTP/1.1 200 OK \n"
509 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n"
510 "Content-Type: 1\n"
511 "Cache-Control: 2\n"
512 "ETag: 3\n"
513 "Connection: 4\n"
514 "Expires: 5\n"
515 "Via: \n" +
516 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
517 "abcde \n"
518 "Content-Length: 12345\n",
519 "[1,;2,;3,;4,;5,;]:content-type:cache-control:etag:connection:expires",
520 false
521 },
522
523 // Checks the case of correct fingerprint.
524 {
525 "HTTP/1.1 200 OK \n"
526 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n"
527 "Content-Type: aaa1\n"
528 "Cache-Control: aaa2\n" +
529 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
530 "abcde \n" +
531 "ETag: aaa3\n"
532 "Connection: aaa4\n"
533 "Expires: aaa5\n"
534 "Via: \n"
535 "Content-Length: 12345\n",
536 "[aaa1,;aaa2,;aaa3,;aaa4,;aaa5,;]:content-type:cache-control:"
537 "etag:connection:expires",
538 false
539 },
540
541 // Checks the case that one header has multiple values.
542 {
543 "HTTP/1.1 200 OK \n"
544 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" +
545 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
546 "abcde \n" +
547 "Content-Type: aaa1, bbb1, ccc1\n"
548 "Cache-Control: aaa2\n"
549 "ETag: aaa3\n"
550 "Connection: aaa4\n"
551 "Expires: aaa5\n"
552 "Via: \n"
553 "Content-Length: 12345\n",
554 "[aaa1,bbb1,ccc1,;aaa2,;aaa3,;aaa4,;aaa5,;]:"
555 "content-type:cache-control:etag:connection:expires",
556 false
557 },
558
559 // Checks the case that one header has multiple lines.
560 {
561 "HTTP/1.1 200 OK \n"
562 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n"
563 "Content-Type: aaa1, ccc1\n"
564 "Content-Type: xxx1, bbb1, ccc1\n"
565 "Cache-Control: aaa2\n"
566 "ETag: aaa3\n"
567 "Connection: aaa4\n"
568 "Expires: aaa5\n"
569 "Via: \n" +
570 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
571 "abcde \n" +
572 "Content-Length: 12345\n",
573 "[aaa1,bbb1,ccc1,ccc1,xxx1,;aaa2,;aaa3,;aaa4,;aaa5,;]:"
574 "content-type:cache-control:etag:connection:expires",
575 false
576 },
577
578 // Checks the case that one header has multiple values, and such multiple
579 // lines occur at different positions.
580 {
581 "HTTP/1.1 200 OK \n" +
582 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
583 "abcde \n" +
584 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n"
585 "Content-Type: aaa1, ccc1\n"
586 "Cache-Control: aaa2\n"
587 "ETag: aaa3\n"
588 "Content-Type: xxx1, bbb1, ccc1\n"
589 "Connection: aaa4\n"
590 "Expires: aaa5\n"
591 "Via: \n"
592 "Content-Length: 12345\n",
593 "[aaa1,bbb1,ccc1,ccc1,xxx1,;aaa2,;aaa3,;aaa4,;aaa5,;]"
594 ":content-type:cache-control:etag:connection:expires",
595 false
596 },
597
598 // Checks the case that more than one headers have multiple values.
599 {
600 "HTTP/1.1 200 OK \n"
601 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n"
602 "Content-Type: aaa1, ccc1\n"
603 "Cache-Control: ccc2 , bbb2\n"
604 "ETag: aaa3\n"
605 "Content-Type: xxx1, bbb1, ccc1\n"
606 "Connection: aaa4\n"
607 "Cache-Control: aaa2 \n"
608 "Expires: aaa5\n" +
609 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
610 "abcde \n" +
611 "Via: \n"
612 "Content-Length: 12345\n",
613 "[aaa1,bbb1,ccc1,ccc1,xxx1,;aaa2,bbb2,ccc2,;aaa3,;aaa4,;aaa5,;]:"
614 "content-type:cache-control:etag:connection:expires",
615 false
616 },
617
618 // Checks the case that one of the requested headers is missing (Expires).
619 {
620 "HTTP/1.1 200 OK \n"
621 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n"
622 "Content-Type: aaa1, ccc1\n"
623 "Cache-Control: ccc2 , bbb2\n"
624 "ETag: aaa3\n"
625 "Content-Type: xxx1, bbb1, ccc1\n"
626 "Connection: aaa4\n"
627 "Cache-Control: aaa2 \n"
628 "Via: \n"
629 "Content-Length: 12345\n" +
630 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
631 "abcde \n",
632 "[aaa1,bbb1,ccc1,ccc1,xxx1,;aaa2,bbb2,ccc2,;aaa3,;aaa4,;;]:"
633 "content-type:cache-control:etag:connection:expires",
634 false
635 },
636
637 // Checks the case that more than one of the requested headers are missing.
638 // (Content-Type, Expires).
639 {
640 "HTTP/1.1 200 OK \n" +
641 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
642 "abcde \n" +
643 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n"
644 "Cache-Control: ccc2 , bbb2\n"
645 "ETag: aaa3\n"
646 "Connection: aaa4\n"
647 "Cache-Control: aaa2 \n"
648 "Via: \n"
649 "Content-Length: 12345\n",
650 "[;aaa2,bbb2,ccc2,;aaa3,;aaa4,;;]:content-type:cache-control:"
651 "etag:connection:expires",
652 false
653 },
654
655 // Checks the case that all the requested headers are missing.
656 {
657 "HTTP/1.1 200 OK \n"
658 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n"
659 "Via: \n"
660 "Content-Length: 12345\n" +
661 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
662 "abcde \n",
663 "[;;;;;]:content-type:cache-control:etag:connection:expires",
664 false
665 },
666
667 // Checks the case that only one header is requested.
668 {
669 "HTTP/1.1 200 OK \n"
670 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n"
671 "Via: \n"
672 "Content-Length: 12345\n" +
673 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
674 "abcde \n",
675 "[12345,;]:content-length",
676 false
677 },
678
679 // Checks the case that fingerprint is different to received one.
680 {
681 "HTTP/1.1 200 OK \n"
682 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n"
683 "Content-Type: aaa1, ccc1\n"
684 "Cache-Control: ccc2 , bbb2\n"
685 "ETag: etag\n"
686 "Content-Type: xxx1, bbb1, ccc1\n"
687 "Connection: aaa4\n"
688 "Cache-Control: aaa2 \n"
689 "Via: \n"
690 "Content-Length: 12345\n",
691 "[aaa1,bbb1,ccc1,ccc1,xxx1,;aaa2,bbb2,ccc2,;aaa3,;aaa4,;;]:"
692 "content-type:cache-control:etag:connection:expires",
693 true
694 },
695
696 // Checks the case that some of the requested headers have empty value
697 // (different to above header-missing case).
698 {
699 "HTTP/1.1 200 OK \n"
700 "Content-Type: \n"
701 "Cache-Control: \n"
702 "ETag: \n"
703 "Connection: \n"
704 "Expires: 5\n" +
705 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
706 "abcde \n" +
707 "Via: \n"
708 "Content-Length: 12345\n",
709 "[,;,;,;,;5,;]:content-type:cache-control:etag:connection:expires",
710 false
711 },
712
713 // Checks the case that some headers are missing, some of them are of
714 // empty values (whether delimiter "," and ";" work correctly).
715 {
716 "HTTP/1.1 200 OK \n"
717 "Cache-Control: \n"
718 "Connection: \n"
719 "Expires: 5\n"
720 "Via: \n"
721 "Content-Length: 12345\n" +
722 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
723 "abcde \n",
724 "[;,;;,;5,;]:content-type:cache-control:etag:connection:expires",
725 false
726 },
727
728 // Checks the case there is no requested header (header list is empty).
729 {
730 "HTTP/1.1 200 OK \n"
731 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n"
732 "Content-Type: 1\n"
733 "Cache-Control: 2\n"
734 "ETag: 3\n"
735 "Connection: 4\n" +
736 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
737 "abcde \n" +
738 "Expires: 5\n"
739 "Via: \n"
740 "Content-Length: 12345\n",
741 "[]",
742 false
743 },
744
745 // Checks the case that there is only one requested header and it does not
746 // exist.
747 {
748 "HTTP/1.1 200 OK \n"
749 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n"
750 "Content-Type: 1\n"
751 "Cache-Control: 2\n"
752 "ETag: 3\n"
753 "Connection: 4\n"
754 "Expires: 5\n"
755 "Via: \n" +
756 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
757 "abcde \n" +
758 "Content-Length: 12345\n",
759 "[;]:non_exist_header",
760 false
761 },
762
763 // Checks the case that there is only one requested header.
764 {
765 "HTTP/1.1 200 OK \n"
766 "Cache-Control: \n"
767 "Connection: \n"
768 "Expires: 5\n"
769 "Via: \n"
770 "Content-Length: 12345\n" +
771 std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy) +
772 "abcde \n",
773 "[;]:content-type",
774 false
775 },
776
777 /* Lead to NOTREACHED() */
778 /*
779 // special case, if base64 decoding fails
780 {
781 "HTTP/1.1 200 OK \n"
782 "Cache-Control: \n"
783 "Connection: \n"
784 "Expires: 5\n"
785 "Via: \n"
786 "Content-Length: 12345\n",
787 ";:content-type",
788 true
789 },
790
791 // special case, if base64 decoding fails
792 {
793 "HTTP/1.1 200 OK \n"
794 "Cache-Control: \n"
795 "Connection: \n"
796 "Expires: 5\n"
797 "Via: \n"
798 "Content-Length: 12345\n",
799 "abcde:content-type:cache-control:etag:connection:expires",
800 true
801 },
802 */
803 };
804
805 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) {
806 ReplaceWithEncodedString(&(test[i].received_fingerprint));
807 DataReductionProxyTamperDetectionTest::TestFingerprintCommon(test[i],
808 DataReductionProxyTamperDetection::OTHERHEADERS);
809 }
810 }
811
812 // Checks function IsContentLengthTampered.
813 TEST_F(DataReductionProxyTamperDetectionTest, ContentLength) {
814 TestCaseCheckingFingerprint test[] = {
815 // Checks the case fingerprint matches received response.
816 {
817 "HTTP/1.1 200 OK \n"
818 "Content-Type: 1\n"
819 "Content-Length: 12345\n",
820 "12345",
821 false,
822 },
823
824 // Checks the case that fingerprint does not match received response.
825 {
826 "HTTP/1.1 200 OK \n"
827 "Content-Type: text/html; charset=ISO-8859-4\n"
828 "Content-Length: 12345\n",
829 "125",
830 true,
831 },
832
833 // Checks the case that the data reduction proxy has not sent
834 // Content-Length header.
835 {
836 "HTTP/1.1 200 OK \n"
837 "Content-Type: text/javascript\n"
838 "Content-Length: 12345\n",
839 "",
840 false,
841 },
842
843 // Checks the case that the data reduction proxy sends invalid
844 // Content-Length header.
845 {
846 "HTTP/1.1 200 OK \n"
847 "Content-Type: text/javascript\n"
848 "Content-Length: 12345\n",
849 "aaa",
850 false,
851 },
852
853 // Checks the case that the data reduction proxy sends invalid
854 // Content-Length header.
855 {
856 "HTTP/1.1 200 OK \n"
857 "Content-Type: text/javascript\n"
858 "Content-Length: aaa\n",
859 "aaa",
860 false,
861 },
862
863 // Checks the case that Content-Length header are missing at both end.
864 {
865 "HTTP/1.1 200 OK \n"
866 "Content-Type: 1\n",
867 "",
868 false,
869 },
870
871 // Checks the case that Content-Length is 0.
872 {
873 "HTTP/1.1 200 OK \n"
874 "Content-Type: application/x-javascript\n"
875 "Content-Length: 0\n",
876 "0",
877 false,
878 },
879
880 // Checks the case that Content-Length is empty at the data reduction proxy
881 // side.
882 {
883 "HTTP/1.1 200 OK \n"
884 "Content-Type: application/x-javascript\n"
885 "Content-Length: 123\n",
886 ",",
887 false,
888 },
889
890 // Checks the case that Content-Length header is missing at the Chromium
891 // client side.
892 {
893 "HTTP/1.1 200 OK \n"
894 "Content-Type: application/javascript \n",
895 "123",
896 false,
897 },
898 };
899
900 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) {
901 DataReductionProxyTamperDetectionTest::TestFingerprintCommon(test[i],
902 DataReductionProxyTamperDetection::CONTENTLENGTH);
903 }
904 }
905
906 // Testcase for RemoveChromeProxyFingerprint function.
907 TEST_F(DataReductionProxyTamperDetectionTest, HeaderRemoving) {
908 struct {
909 std::string input_values[10];
910 std::string expected_output_values[10];
911 } test[] = {
912 // Checks the case that there is no Chrome-Proxy header's fingerprint.
913 {
914 {"1", "2", "3", "5",},
915 {"1", "2", "3", "5",},
916 },
917 // Checks the case that there is Chrome-Proxy header's fingerprint.
918 {
919 {"1", "2", "3",
920 std::string(tamper_detection_fingerprint_names::
921 kFingerprintChromeProxy) + "=4", "5",},
922 {"1", "2", "3", "5",},
923 },
924 // Checks the case that there is Chrome-Proxy header's fingerprint, and it
925 // occurs at the end.
926 {
927 {"1", "2", "3",
928 std::string(tamper_detection_fingerprint_names::
929 kFingerprintChromeProxy) + "=4",},
930 {"1", "2", "3",},
931 },
932 // Checks the case that there is Chrome-Proxy header's fingerprint, and it
933 // occurs at the beginning.
934 {
935 {std::string(tamper_detection_fingerprint_names::kFingerprintChromeProxy)
936 + "=1", "2", "3",},
937 {"2", "3",},
938 },
939 };
940
941 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) {
942 std::vector<std::string> input_values, output_values;
943 for (size_t j=0; j<ARRAYSIZE_UNSAFE(test[i].input_values); ++j) {
944 if (test[i].input_values[j].size())
945 input_values.push_back(test[i].input_values[j]);
946 }
947 for (size_t j=0; j<ARRAYSIZE_UNSAFE(test[i].expected_output_values); ++j) {
948 if (test[i].expected_output_values[j].size())
949 output_values.push_back(test[i].expected_output_values[j]);
950 }
951
952 DataReductionProxyTamperDetection::RemoveChromeProxyFingerprint(
953 &input_values);
954
955 EXPECT_EQ(input_values, output_values);
956 }
957 }
958
959 // Testcase for ValuesToSortedString function.
960 TEST_F(DataReductionProxyTamperDetectionTest, ValuesToSortedString) {
961 struct {
962 std::string input_values[10];
963 std::string expected_output_string;
964 } test[] = {
965 // Checks the correctness of sorting.
966 {
967 {"1", "2", "3",},
968 "1,2,3,",
969 },
970 // Checks the case that there is an empty input vector.
971 {
972 {},
973 "",
974 },
975 // Checks the case that there is an empty string in the input vector.
976 {
977 {" ",},
978 ",",
979 },
980 };
981
982 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) {
983 std::vector<std::string> input_values;
984 for (size_t j=0; j<ARRAYSIZE_UNSAFE(test[i].input_values); ++j) {
985 if (test[i].input_values[j].size()) {
986 if (test[i].input_values[j] == " ")
987 input_values.push_back("");
988 else
989 input_values.push_back(test[i].input_values[j]);
990 }
991 }
992
993 std::string output_string = DataReductionProxyTamperDetection::
994 ValuesToSortedString(&input_values);
995
996 EXPECT_EQ(output_string, test[i].expected_output_string);
997 }
998 }
999
1000 // Testcase for GetHeaderValues function.
1001 TEST_F(DataReductionProxyTamperDetectionTest, GetHeaderValues) {
1002 struct {
1003 std::string raw_header;
1004 std::string header_name;
1005 std::string expected_output_values[10];
1006 } test[] = {
1007 // Checks the correctness of getting single line header.
1008 {
1009 "HTTP/1.1 200 OK \n"
1010 "test: 1, 2, 3\n",
1011 "test",
1012 {"1", "2", "3"},
1013 },
1014 // Checks the correctness of getting multiple lines header.
1015 {
1016 "HTTP/1.1 200 OK \n"
1017 "test: 1, 2, 3\n"
1018 "test: 4, 5, 6\n"
1019 "test: 7, 8, 9\n",
1020 "test",
1021 {"1", "2", "3", "4", "5", "6", "7", "8", "9"},
1022 },
1023 // Checks the correctness of getting missing header.
1024 {
1025 "HTTP/1.1 200 OK \n",
1026 "test",
1027 {},
1028 },
1029 // Checks the correctness of getting empty header.
1030 {
1031 "HTTP/1.1 200 OK \n"
1032 "test: \n",
1033 "test",
1034 {" "},
1035 },
1036 };
1037
1038 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) {
1039 std::string raw_headers(test[i].raw_header);
1040 HeadersToRaw(&raw_headers);
1041 scoped_refptr<net::HttpResponseHeaders> headers =
1042 new net::HttpResponseHeaders(raw_headers);
1043
1044 std::vector<std::string> expected_output_values;
1045 for (size_t j=0; j<ARRAYSIZE_UNSAFE(test[i].expected_output_values); ++j) {
1046 if ((test[i].expected_output_values[j]).size()) {
1047 if (test[i].expected_output_values[j] == " ")
1048 expected_output_values.push_back("");
1049 else
1050 expected_output_values.push_back(test[i].expected_output_values[j]);
1051 }
1052 }
1053
1054 std::vector<std::string> output_values =
1055 DataReductionProxyTamperDetection::GetHeaderValues(
1056 headers, test[i].header_name);
1057 EXPECT_EQ(expected_output_values, output_values);
1058 }
1059 }
1060
1061 // Testcase for main function CheckResponseFingerprint. First generate
1062 // simulated response from the data reduction proxy, by replacing fingerprint
1063 // with its base64 encoded MD5 value and appending it to Chrome-Proxy header.
1064 // Then runs through function CheckResponseFingerprint.
1065 TEST_F(DataReductionProxyTamperDetectionTest, Completed) {
1066 struct {
1067 std::string raw_header;
1068 std::string chrome_header;
1069 bool expected_contain_tamper_detect_fingerprints;
1070 bool expected_tampered_chrome_proxy;
1071 bool expected_tampered_via;
1072 bool expected_tampered_other_headers;
1073 bool expected_tampered_content_length;
1074 } test[] = {
1075 // Check normal case, Chrome-Proxy fingerprint doesn't exist
1076 {
1077 "HTTP/1.1 200 OK \n"
1078 "Via: a1, b2, 1.1 Chrome-Compression-Proxy\n"
1079 "Content-Length: 12345\n"
1080 "header1: header_1\n"
1081 "header2: header_2\n"
1082 "header3: header_3\n",
1083 "a,b,c,d,e," +
1084 std::string(tamper_detection_fingerprint_names::
1085 kFingerprintContentLength) + "=12345," +
1086 std::string(tamper_detection_fingerprint_names::
1087 kFingerprintOtherHeaders) +
1088 "=[header_1,;header_2,;header_3,;]:header1:header2:header3," +
1089 std::string(tamper_detection_fingerprint_names::kFingerprintVia) + "=0,",
1090 true,
1091 false,
1092 false,
1093 false,
1094 false,
1095 },
1096 };
1097
1098 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) {
1099 // Replace fingerprint with base64 encoded MD5 value.
1100 ReplaceWithEncodedString(&(test[i].chrome_header));
1101 // Generate fingerprint for Chrome-Proxy header.
1102 std::string chrome_header_fingerprint = GetEncoded(test[i].chrome_header);
1103 // Append Chrome-Proxy header to response headers.
1104 test[i].raw_header += "Chrome-Proxy: " + test[i].chrome_header +
1105 std::string(tamper_detection_fingerprint_names::
1106 kFingerprintChromeProxy) + "=" + chrome_header_fingerprint + "\n";
1107
1108 std::string raw_headers(test[i].raw_header);
1109 HeadersToRaw(&raw_headers);
1110 scoped_refptr<net::HttpResponseHeaders> headers =
1111 new net::HttpResponseHeaders(raw_headers);
1112
1113 // Below copying codes from CheckResponseFingerprint, with checking points
1114 // added.
1115 std::string chrome_proxy_fingerprint;
1116 bool contain_chrome_proxy_fingerprint = GetDataReductionProxyActionValue(
1117 headers,
1118 tamper_detection_fingerprint_names::kFingerprintChromeProxy,
1119 &chrome_proxy_fingerprint);
1120
1121
1122 EXPECT_EQ(test[i].expected_contain_tamper_detect_fingerprints,
1123 contain_chrome_proxy_fingerprint);
1124 if (!contain_chrome_proxy_fingerprint)
1125 return;
1126 std::vector<std::string> chrome_proxy_header_values =
1127 DataReductionProxyTamperDetection::
1128 GetHeaderValues(headers, "Chrome-Proxy");
1129
1130 DataReductionProxyTamperDetection::
1131 RemoveChromeProxyFingerprint(&chrome_proxy_header_values);
1132
1133 DataReductionProxyTamperDetection tamper_detection(
1134 headers,
1135 true,
1136 0,
1137 &chrome_proxy_header_values);
1138
1139 bool tampered_chrome_proxy =
1140 tamper_detection.IsChromeProxyHeaderTampered(chrome_proxy_fingerprint);
1141 EXPECT_EQ(test[i].expected_tampered_chrome_proxy, tampered_chrome_proxy);
1142 if (tampered_chrome_proxy)
1143 return;
1144
1145 // Checks other fingerprints.
1146 const char* fingerprint_names[] = {
1147 data_reduction_proxy::tamper_detection_fingerprint_names::
1148 kFingerprintVia,
1149 data_reduction_proxy::tamper_detection_fingerprint_names::
1150 kFingerprintOtherHeaders,
1151 data_reduction_proxy::tamper_detection_fingerprint_names::
1152 kFingerprintContentLength
1153 };
1154
1155 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(fingerprint_names); ++j) {
1156 std::string fingerprint;
1157 if (!GetDataReductionProxyActionValue(
1158 headers, fingerprint_names[j], &fingerprint)) {
1159 continue;
1160 }
1161
1162 bool tampered = false;
1163 DataReductionProxyTamperDetection::FingerprintCode fingerprint_code =
1164 tamper_detection.GetFingerprintCode(fingerprint_names[i]);
1165 switch (fingerprint_code) {
1166 case DataReductionProxyTamperDetection::VIA:
1167 tampered = tamper_detection.IsViaHeaderTampered(fingerprint);
1168 EXPECT_EQ(test[i].expected_tampered_via, tampered);
1169 break;
1170 case DataReductionProxyTamperDetection::OTHERHEADERS:
1171 tampered = tamper_detection.AreOtherHeadersTampered(fingerprint);
1172 EXPECT_EQ(test[i].expected_tampered_other_headers, tampered);
1173 break;
1174 case DataReductionProxyTamperDetection::CONTENTLENGTH:
1175 tampered = tamper_detection.IsContentLengthHeaderTampered(fingerprint);
1176 EXPECT_EQ(test[i].expected_tampered_content_length, tampered);
1177 break;
1178 default:
1179 NOTREACHED();
1180 break;
1181 }
1182 }
1183 return;
1184 }
1185 }
1186
1187 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698