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

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

Powered by Google App Engine
This is Rietveld 408576698