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

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: Move modification on _headers.h/cc to another CL. 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 <map>
8 #include <vector>
9
10 #include "base/base64.h"
11 #include "base/md5.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_split.h"
14 #include "components/data_reduction_proxy/browser/data_reduction_proxy_tamper_de tect.h"
15 #include "net/android/network_library.h"
16 #include "net/http/http_request_headers.h"
17 #include "net/http/http_util.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20
21 namespace {
22
23 const char kTamperDetectFingerprints[] = "fp=";
24 const char kTamperDetectFingerprintChromeProxy[] = "cp=";
25 const char kTamperDetectFingerprintVia[] = "via";
26 const char kTamperDetectFingerprintOther[] = "oh";
27 const char kTamperDetectFingerprintContengLength[] = "cl";
28
29 void HeadersToRaw(std::string* headers) {
30 std::replace(headers->begin(), headers->end(), '\n', '\0');
31 if (!headers->empty())
32 *headers += '\0';
33 }
34
35 // Utility function. Calcuate MD5 hash value for a string and base64 encode it.
36 static std::string GetEncoded(const std::string& input) {
37 base::MD5Digest digest;
38 base::MD5Sum(input.c_str(), input.size(), &digest);
39 std::string base64encoded;
40 base::Base64Encode(std::string((char*)digest.a,
41 ARRAYSIZE_UNSAFE(digest.a)), &base64encoded);
42 return base64encoded;
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| and
81 // then check corresponding fingerprint checking function matches expected
82 // 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::GetTamperDetectionFingerprints(
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(kTamperDetectFingerprints) +
133 "123,bbbypas=0,aaxxx=xxx,bbbloc=1\n",
134 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0," +
135 std::string(kTamperDetectFingerprints) + "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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) + "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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) + "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 from data reduction proxy, instead, the base64 encoded field
500 // is in plain text (within "[]") and needs to be encoded first. For example,
501 // "[12345;]:content-length" needs to be encoded to
502 // "Base64Encoded(MD5(12345;)):content-length" before calling the 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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
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(kTamperDetectFingerprints) +
803 "abcde \n",
804 "[;]:content-type",
805 false
806 },
807
808 /* Lead to NOTREACHED() */
809 /*
810 // special case, if base64 decoding fails
811 {
812 "HTTP/1.1 200 OK \n"
813 "Cache-Control: \n"
814 "Connection: \n"
815 "Expires: 5\n"
816 "Via: \n"
817 "Content-Length: 12345\n",
818 ";:content-type",
819 true
820 },
821
822 // special case, if base64 decoding fails
823 {
824 "HTTP/1.1 200 OK \n"
825 "Cache-Control: \n"
826 "Connection: \n"
827 "Expires: 5\n"
828 "Via: \n"
829 "Content-Length: 12345\n",
830 "abcde:content-type:cache-control:etag:connection:expires",
831 true
832 },
833 */
834 };
835
836 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) {
837 ReplaceWithEncodedString(&(test[i].received_fingerprint));
838 DataReductionProxyTamperDetectTest::TestFingerprintCommon(test[i],
839 DataReductionProxyTamperDetect::OTHERHEADERS);
840 }
841 }
842
843 // Check function IsContentLengthTampered.
844 TEST_F(DataReductionProxyTamperDetectTest, ContentLength) {
845 TestCaseCheckingFingerprint test[] = {
846 // regular case, content-length is the same
847 {
848 "HTTP/1.1 200 OK \n"
849 "Content-Type: 1\n"
850 "Content-Length: 12345\n",
851 "12345",
852 false,
853 },
854
855 // regular case, content-length is not the same
856 // also check if retrieved content-type is correct
857 {
858 "HTTP/1.1 200 OK \n"
859 "Content-Type: text/html; charset=ISO-8859-4\n"
860 "Content-Length: 12345\n",
861 "125",
862 true,
863 },
864
865 // special case, data reduction proxy does not sent content-length
866 // i.e., content-length at data reduction proxy side is missing
867 {
868 "HTTP/1.1 200 OK \n"
869 "Content-Type: text/javascript\n"
870 "Content-Length: 12345\n",
871 "",
872 false,
873 },
874
875 {
876 "HTTP/1.1 200 OK \n"
877 "Content-Type: text/javascript\n"
878 "Content-Length: 12345\n",
879 "aaa",
880 false,
881 },
882
883 {
884 "HTTP/1.1 200 OK \n"
885 "Content-Type: text/javascript\n"
886 "Content-Length: aaa\n",
887 "aaa",
888 false,
889 },
890
891 // special case, content-length are missing at both end
892 // i.e., both data reduction proxy and chrome
893 {
894 "HTTP/1.1 200 OK \n"
895 "Content-Type: 1\n",
896 "",
897 false,
898 },
899
900 // special case, check when content-length is 0
901 {
902 "HTTP/1.1 200 OK \n"
903 "Content-Type: application/x-javascript\n"
904 "Content-Length: 0\n",
905 "0",
906 false,
907 },
908
909 // special case, check when data reduction proxy side's
910 // content-length is empty (header exist, but value is empty)
911 {
912 "HTTP/1.1 200 OK \n"
913 "Content-Type: application/x-javascript\n"
914 "Content-Length: 123\n",
915 ",",
916 false,
917 },
918
919 // when content-length is different, check whether it recognizes image.
920 {
921 "HTTP/1.1 200 OK \n"
922 "Content-Type: image/gif \n"
923 "Content-Length: 123\n",
924 "0",
925 true,
926 },
927
928 // when content-length is different, check whether it recognizes JS
929 {
930 "HTTP/1.1 200 OK \n"
931 "Content-Type: application/x-javascript \n"
932 "Content-Length: 0\n",
933 "120",
934 true,
935 },
936
937 // when content-length is different, check whether it recognizes JS
938 {
939 "HTTP/1.1 200 OK \n"
940 "Content-Type: text/javascript \n"
941 "Content-Length: 123\n",
942 "0",
943 true,
944 },
945
946 // when content-length is different, check whether it recognizes CSS
947 {
948 "HTTP/1.1 200 OK \n"
949 "Content-Type: text/css\n"
950 "Content-Length: 111\n",
951 "0",
952 true,
953 },
954
955 // when content-length is different (chrome side is missing),
956 // check whether it recognizes JS.
957 // (if phone side's content-length has been removed, shall we report?
958 // current implementation: not reporting.)
959 {
960 "HTTP/1.1 200 OK \n"
961 "Content-Type: application/javascript \n",
962 "123",
963 false,
964 },
965 };
966
967 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) {
968 DataReductionProxyTamperDetectTest::TestFingerprintCommon(test[i],
969 DataReductionProxyTamperDetect::CONTENTLENGTH);
970 }
971 }
972
973 // Testcase for ContainsTamperDetectFingerprints function.
974 TEST_F(DataReductionProxyTamperDetectTest, Parsing) {
975 struct {
976 std::string raw_header;
977 std::string expected_chrome_proxy_fingerprint;
978 std::string expected_other_fingerprints;
979 bool expected_contain_tamper_detect_fingerprints;
980 } test[] = {
981 // Check normal case, Chrome-Proxy fingerprint doesn't exist
982 {
983 "HTTP/1.1 200 OK \n"
984 "Chrome-Proxy: f1:f1&f2:f2&f3:f3&f4:f4\n",
985 "",
986 "",
987 false
988 },
989 // Check normal case, Chrome-Proxy fingerprint exist,
990 // but other headers' fingerprint is not there.
991 {
992 "HTTP/1.1 200 OK \n"
993 "Chrome-Proxy: f1, " +
994 std::string(kTamperDetectFingerprintChromeProxy)
995 + "abc \n",
996 "abc",
997 "",
998 true
999 },
1000
1001 // Check normal case, both Chrome-Proxy fingerprint
1002 // and other headers' fingerprint exist,
1003 // but with different values and occur at different position.
1004 {
1005 "HTTP/1.1 200 OK \n"
1006 "Chrome-Proxy: f1, " +
1007 std::string(kTamperDetectFingerprintChromeProxy)
1008 + "abc \n"
1009 "Chrome-Proxy: " +
1010 std::string(kTamperDetectFingerprints) + "def\n",
1011 "abc",
1012 "def",
1013 true
1014 },
1015
1016 {
1017 "HTTP/1.1 200 OK \n"
1018 "Chrome-Proxy: f1, " +
1019 std::string(kTamperDetectFingerprintChromeProxy)
1020 + "abc," +
1021 std::string(kTamperDetectFingerprints) + "def \n",
1022 "abc",
1023 "def",
1024 true
1025 },
1026
1027 {
1028 "HTTP/1.1 200 OK \n"
1029 "Chrome-Proxy: f1, " +
1030 std::string(kTamperDetectFingerprintChromeProxy)
1031 + "def," +
1032 std::string(kTamperDetectFingerprints) + "abc \n",
1033 "def",
1034 "abc",
1035 true
1036 },
1037
1038 {
1039 "HTTP/1.1 200 OK \n"
1040 "Chrome-Proxy: f1, " +
1041 std::string(kTamperDetectFingerprints) + "abc," +
1042 std::string(kTamperDetectFingerprintChromeProxy) + "def \n",
1043 "def",
1044 "abc",
1045 true
1046 },
1047
1048 {
1049 "HTTP/1.1 200 OK \n"
1050 "Chrome-Proxy: f1, " +
1051 std::string(kTamperDetectFingerprints) + "def," +
1052 std::string(kTamperDetectFingerprintChromeProxy) + "abc \n",
1053 "abc",
1054 "def",
1055 true
1056 },
1057 };
1058
1059 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) {
1060 std::string raw_headers(test[i].raw_header);
1061 HeadersToRaw(&raw_headers);
1062 scoped_refptr<net::HttpResponseHeaders> headers(
1063 new net::HttpResponseHeaders(raw_headers));
1064
1065 std::vector<std::string> values = DataReductionProxyTamperDetect::
1066 GetHeaderValues(headers, "Chrome-Proxy");
1067
1068 std::string chrome_proxy_fingerprint, other_fingerprints;
1069 bool contain_tamper_detect_fingerprints = DataReductionProxyTamperDetect::
1070 GetTamperDetectionFingerprints(&values,
1071 &chrome_proxy_fingerprint,
1072 &other_fingerprints);
1073
1074 EXPECT_EQ(test[i].expected_contain_tamper_detect_fingerprints,
1075 contain_tamper_detect_fingerprints);
1076
1077 if (contain_tamper_detect_fingerprints) {
1078 EXPECT_EQ(test[i].expected_chrome_proxy_fingerprint,
1079 chrome_proxy_fingerprint);
1080
1081 EXPECT_EQ(test[i].expected_other_fingerprints,
1082 other_fingerprints);
1083 }
1084 }
1085 }
1086
1087 // Testcase for main function CheckResponseFingerprint. First generate
1088 // simulated response from data reduction proxy, by replacing fingerprint with
1089 // its base64 encoded MD5 value and appending it to Chrome-Proxy header. Then
1090 // run through function CheckResponseFingerprint. Individual functions have been
1091 // tested above, here focuses on the correctness of parsing (separating)
1092 // fingerprints and the entire process.
1093 TEST_F(DataReductionProxyTamperDetectTest, Completed) {
1094 struct {
1095 std::string raw_header;
1096 std::string chrome_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 std::string expected_fingerprint_tags;
1103 std::string expected_fingerprints;
1104 } test[] = {
1105 // Check normal case, Chrome-Proxy fingerprint doesn't exist
1106 {
1107 "HTTP/1.1 200 OK \n"
1108 "Via: a1, b2, Chrome-Compression-Proxy\n"
1109 "Content-Length: 12345\n"
1110 "header1: header_1\n"
1111 "header2: header_2\n"
1112 "header3: header_3\n",
1113 "a,b,c,d,e," +
1114 std::string(kTamperDetectFingerprints) +
1115 "via=0|oh=[header_1,;header_2,;header_3,;]:header1:header2:header3|"
1116 "cl=12345,",
1117 true,
1118 false,
1119 false,
1120 false,
1121 false,
1122 "via|cl|oh",
1123 "0|12345|[header_1,;header_2,;header_3,;]:header1:header2:header3"
1124 },
1125 };
1126
1127 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) {
1128 // Replace fingerprint with base64 encoded MD5 value.
1129 ReplaceWithEncodedString(&(test[i].chrome_header));
1130 // Generate fingerprint for Chrome-Proxy header.
1131 std::string chrome_header_fingerprint = GetEncoded(test[i].chrome_header);
1132 // Append Chrome-Proxy header to response headers.
1133 test[i].raw_header += "Chrome-Proxy: " + test[i].chrome_header +
1134 std::string(kTamperDetectFingerprintChromeProxy) +
1135 chrome_header_fingerprint + "\n";
1136
1137 std::string raw_headers(test[i].raw_header);
1138 HeadersToRaw(&raw_headers);
1139 scoped_refptr<net::HttpResponseHeaders> headers =
1140 new net::HttpResponseHeaders(raw_headers);
1141
1142 std::vector<std::string> expected_fingerprint_tags;
1143 std::vector<std::string> expected_fingerprints;
1144 base::SplitString(test[i].expected_fingerprint_tags, '|',
1145 &expected_fingerprint_tags);
1146 base::SplitString(test[i].expected_fingerprints, '|',
1147 &expected_fingerprints);
1148
1149 // Below copying codes from CheckResponseFingerprint, with checking point
1150 // added.
1151 std::vector<std::string> values = DataReductionProxyTamperDetect::
1152 GetHeaderValues(headers, "Chrome-Proxy");
1153
1154 std::string chrome_proxy_fingerprint, other_fingerprints;
1155
1156 bool contain_tamper_detect_fingerprints = DataReductionProxyTamperDetect::
1157 GetTamperDetectionFingerprints(&values,
1158 &chrome_proxy_fingerprint,
1159 &other_fingerprints);
1160
1161 EXPECT_EQ(test[i].expected_contain_tamper_detect_fingerprints,
1162 contain_tamper_detect_fingerprints);
1163 if (!contain_tamper_detect_fingerprints)
1164 return;
1165
1166 DataReductionProxyTamperDetect tamper_detect(headers, true, 0, &values);
1167
1168 bool tampered_chrome_proxy =
1169 tamper_detect.IsChromeProxyHeaderTampered(chrome_proxy_fingerprint);
1170 EXPECT_EQ(test[i].expected_tampered_chrome_proxy, tampered_chrome_proxy);
1171 if (tampered_chrome_proxy)
1172 return;
1173
1174 net::HttpUtil::ValuesIterator it(other_fingerprints.begin(),
1175 other_fingerprints.end(), '|');
1176
1177 size_t delimiter_pos = std::string::npos;
1178 while (it.GetNext()) {
1179
1180 delimiter_pos = it.value().find("=");
1181 if (delimiter_pos == std::string::npos)
1182 continue;
1183 std::string key = it.value().substr(0, delimiter_pos);
1184 std::string value = it.value().substr(delimiter_pos + 1);
1185
1186 for (size_t j = 0; j < expected_fingerprint_tags.size(); ++j) {
1187 if (expected_fingerprint_tags[j] == key) {
1188 std::string expected_value = expected_fingerprints[j];
1189 ReplaceWithEncodedString(&expected_value);
1190 EXPECT_EQ(expected_value, value);
1191 break;
1192 }
1193 }
1194
1195 DataReductionProxyTamperDetect::FingerprintCode fingerprint_code =
1196 tamper_detect.GetFingerprintCode(key);
1197 bool tampered = false;
1198 switch (fingerprint_code) {
1199 case DataReductionProxyTamperDetect::VIA:
1200 tampered = tamper_detect.IsViaHeaderTampered(value);
1201 EXPECT_EQ(test[i].expected_tampered_via, tampered);
1202 break;
1203 case DataReductionProxyTamperDetect::OTHERHEADERS:
1204 tampered = tamper_detect.AreOtherHeadersTampered(value);
1205 EXPECT_EQ(test[i].expected_tampered_other_headers, tampered);
1206 break;
1207 case DataReductionProxyTamperDetect::CONTENTLENGTH:
1208 tampered = tamper_detect.IsContentLengthHeaderTampered(value);
1209 EXPECT_EQ(test[i].expected_tampered_content_length, tampered);
1210 break;
1211 case DataReductionProxyTamperDetect::CHROMEPROXY:
1212 case DataReductionProxyTamperDetect::NONEXIST:
1213 break;
1214 }
1215 }
1216 }
1217 }
1218
1219 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698