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

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

Powered by Google App Engine
This is Rietveld 408576698