OLD | NEW |
---|---|
(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 | |
12 #include "components/data_reduction_proxy/browser/data_reduction_proxy_tamper_de tect.h" | |
13 #include "testing/gtest/include/gtest/gtest.h" | |
14 | |
15 std::string GetEncoded(std::string& input) { | |
16 std::string ret; | |
17 base::Base64Encode(data_reduction_proxy::GetMD5(input), &ret); | |
18 return ret; | |
19 } | |
20 | |
21 namespace { | |
22 | |
23 void HeadersToRaw(std::string* headers) { | |
24 std::replace(headers->begin(), headers->end(), '\n', '\0'); | |
25 if (!headers->empty()) | |
26 *headers += '\0'; | |
27 } | |
28 | |
29 struct FingerprintTestCase { | |
30 std::string raw_header; | |
31 std::string received_fingerprint; | |
32 bool expected_tampered; | |
33 }; | |
34 | |
35 struct ParsingTestCase { | |
36 std::string raw_header; | |
37 std::string expected_chrome_proxy_fingerprint; | |
38 std::string expected_other_fingerprints; | |
39 bool expected_contain_tamper_detect_fingerprints; | |
40 }; | |
41 | |
42 class DataReductionProxyTamperDetectTest : public testing::Test { | |
43 }; | |
44 | |
45 enum Fingerprint { CHROMEPROXY, VIA, OTHERHEADERS, CONTENTLENGTH }; | |
46 | |
47 void TestFingerprintCommon(const FingerprintTestCase& test, | |
48 Fingerprint fingerprint) { | |
49 std::string raw_headers(test.raw_header); | |
50 HeadersToRaw(&raw_headers); | |
51 scoped_refptr<net::HttpResponseHeaders> headers( | |
52 new net::HttpResponseHeaders(raw_headers)); | |
53 | |
54 std::vector<std::string> values = data_reduction_proxy:: | |
55 GetHeaderValues(headers, "Chrome-Proxy"); | |
56 int chrome_proxy_fingerprint_index = -1; | |
57 for (size_t i=0; i<values.size(); ++i) | |
58 if (values[i].find( | |
59 data_reduction_proxy::kTamperDetectFingerprintChromeProxy) == 0) { | |
60 chrome_proxy_fingerprint_index = i; | |
61 break; | |
62 } | |
63 | |
64 // No fingerprint for Chrome-Proxy found. | |
65 if (chrome_proxy_fingerprint_index != -1) | |
66 values.erase(values.begin() + chrome_proxy_fingerprint_index); | |
67 data_reduction_proxy::DataReductionProxyTamperDetect | |
68 tamper_detect(headers, true, 0, &values); | |
69 | |
70 data_reduction_proxy::DataReductionProxyTamperDetect::CheckTamper checkFunc; | |
71 switch (fingerprint) { | |
72 case CHROMEPROXY: | |
73 checkFunc = &data_reduction_proxy::DataReductionProxyTamperDetect:: | |
74 CheckHeaderChromeProxy; | |
75 break; | |
76 case VIA: | |
77 checkFunc = &data_reduction_proxy::DataReductionProxyTamperDetect:: | |
78 CheckHeaderVia; | |
79 break; | |
80 case OTHERHEADERS: | |
81 checkFunc = &data_reduction_proxy::DataReductionProxyTamperDetect:: | |
82 CheckHeaderOtherHeaders; | |
83 break; | |
84 case CONTENTLENGTH: | |
85 checkFunc = &data_reduction_proxy::DataReductionProxyTamperDetect:: | |
86 CheckHeaderContentLength; | |
87 break; | |
88 } | |
89 | |
90 EXPECT_EQ(test.expected_tampered, | |
91 (tamper_detect.*checkFunc)(test.received_fingerprint)); | |
92 } | |
93 | |
94 void TestParsingCommon(const ParsingTestCase& test) { | |
95 std::string raw_headers(test.raw_header); | |
96 HeadersToRaw(&raw_headers); | |
97 scoped_refptr<net::HttpResponseHeaders> headers( | |
98 new net::HttpResponseHeaders(raw_headers)); | |
99 | |
100 std::vector<std::string> values = | |
101 data_reduction_proxy::GetHeaderValues(headers, "Chrome-Proxy"); | |
102 | |
103 std::string chrome_proxy_fingerprint, other_fingerprints; | |
104 bool contain_tamper_detect_fingerprints = data_reduction_proxy:: | |
105 ContainsTamperDetectFingerprints(values, | |
106 chrome_proxy_fingerprint, | |
107 other_fingerprints); | |
108 | |
109 EXPECT_EQ(test.expected_contain_tamper_detect_fingerprints, | |
110 contain_tamper_detect_fingerprints); | |
111 | |
112 if (contain_tamper_detect_fingerprints) { | |
113 EXPECT_EQ(test.expected_chrome_proxy_fingerprint, | |
114 chrome_proxy_fingerprint); | |
115 | |
116 EXPECT_EQ(test.expected_other_fingerprints, | |
117 other_fingerprints); | |
118 } | |
119 | |
120 } | |
121 | |
122 TEST(DataReductionProxyTamperDetectTest, ChromeProxy) { | |
123 FingerprintTestCase test[] = { | |
124 // check sorting values and decoding | |
125 { | |
126 "HTTP/1.1 200 OK \n" | |
bengr
2014/07/02 17:31:01
indent 2, not 4, here and below.
xingx
2014/07/06 03:18:20
Done.
| |
127 "Chrome-Proxy: aut=aauutthh," + | |
128 std::string(data_reduction_proxy::kTamperDetectFingerprint) + | |
129 "123,bbbypas=0,aaxxx=xxx,bbbloc=1\n", | |
130 | |
131 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0," + | |
132 std::string(data_reduction_proxy::kTamperDetectFingerprint) + "123,", | |
133 false, | |
134 }, | |
135 | |
136 // check sorting | |
137 { | |
138 "HTTP/1.1 200 OK \n" | |
139 "Chrome-Proxy: a,b,c,d,e,3,2,1," + | |
140 std::string(data_reduction_proxy::kTamperDetectFingerprintChromeProxy) | |
141 + "1231\n", | |
142 | |
143 "1,2,3,a,b,c,d,e,", | |
144 false, | |
145 }, | |
146 | |
147 // check no Chrome-Proxy header case (should not happen) | |
148 { | |
149 "HTTP/1.1 200 OK \n" | |
150 "Content-Length: 12345\n", | |
151 | |
152 "", | |
153 false, | |
154 }, | |
155 | |
156 // check empty Chrome-Proxy header case (should not happen) | |
157 { | |
158 "HTTP/1.1 200 OK \n" | |
159 "Chrome-Proxy: \n", | |
160 | |
161 ",", | |
162 false, | |
163 }, | |
164 | |
165 // check empty Chrome-Proxy header case | |
166 { | |
167 "HTTP/1.1 200 OK \n" | |
168 "Chrome-Proxy: " + | |
169 std::string(data_reduction_proxy::kTamperDetectFingerprintChromeProxy) | |
170 + "xyz\n", | |
171 | |
172 "", | |
173 false, | |
174 }, | |
175 | |
176 // check empty Chrome-Proxy header case, with extra "," | |
177 { | |
178 "HTTP/1.1 200 OK \n" | |
179 "Chrome-Proxy: " + | |
180 std::string(data_reduction_proxy::kTamperDetectFingerprintChromeProxy) | |
181 + "abcde , \n", | |
182 | |
183 "", | |
184 false, | |
185 }, | |
186 | |
187 // check empty Chrome-Proxy header, different fingerprint | |
188 { | |
189 "HTTP/1.1 200 OK \n" | |
190 "Chrome-Proxy: " + | |
191 std::string(data_reduction_proxy::kTamperDetectFingerprintChromeProxy) | |
192 + "xyz\n", | |
193 | |
194 ",", | |
195 true, | |
196 }, | |
197 | |
198 // check regular Chrome-Proxy header, different fingerprint | |
199 { | |
200 "HTTP/1.1 200 OK \n" | |
201 "Chrome-Proxy: aut=aauutthh,bbbypas=2,aaxxx=xxx,bbbloc=1\n", | |
202 | |
203 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,", | |
204 true, | |
205 }, | |
206 | |
207 // check regular Chrome-Proxy header, different fingerprint | |
208 { | |
209 "HTTP/1.1 200 OK \n" | |
210 "Chrome-Proxy: a,aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n", | |
211 | |
212 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,", | |
213 true, | |
214 }, | |
215 | |
216 // check regular Chrome-Proxy header, with extra " " | |
217 { | |
218 "HTTP/1.1 200 OK \n" | |
219 "Chrome-Proxy: aut=aauutthh , bbbypas=0 , aaxxx=xxx" | |
220 " ,bbbloc=1 \n", | |
221 | |
222 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,", | |
223 false | |
224 }, | |
225 | |
226 // check regular 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 | |
232 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,", | |
233 false | |
234 }, | |
235 | |
236 // check Chrome-Proxy header with multiple lines | |
237 { | |
238 "HTTP/1.1 200 OK \n" | |
239 "Chrome-Proxy: aaxxx=xxx \n" | |
240 "Chrome-Proxy: aut=aauutthh\n" | |
241 "Chrome-Proxy: bbbypas=0\n" | |
242 "Chrome-Proxy:bbbloc=1 \n", | |
243 | |
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 | |
264 "aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,", | |
265 false | |
266 }, | |
267 | |
268 // check Chrome-Proxy header with multiple same values | |
269 { | |
270 "HTTP/1.1 200 OK \n" | |
271 "Chrome-Proxy: aaxxx=xxx \n" | |
272 "Chrome-Proxy: aut=aauutthh\n" | |
273 "Content-Type: 1\n" | |
274 "Cache-Control: 2\n" | |
275 "ETag: 3\n" | |
276 "Chrome-Proxy: bbbypas=0\n" | |
277 "Connection: 4\n" | |
278 "Expires: 5\n" | |
279 "Chrome-Proxy: bbbloc=1, " + | |
280 std::string(data_reduction_proxy::kTamperDetectFingerprint) + | |
281 "123 \n" | |
282 "Chrome-Proxy: aaxxx=xxx \n" | |
283 "Via: \n" | |
284 "Content-Length: 12345\n", | |
285 | |
286 "aaxxx=xxx,aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0," + | |
287 std::string(data_reduction_proxy::kTamperDetectFingerprint) + "123,", | |
288 false | |
289 }, | |
290 | |
291 // check Chrome-Proxy header with multiple same values, | |
292 // but different fingerprint | |
293 { | |
294 "HTTP/1.1 200 OK \n" | |
295 "Chrome-Proxy: aaxxx=xxx \n" | |
296 "Chrome-Proxy: aaxxx=xxx \n" | |
297 "Chrome-Proxy: aut=aauutthh\n" | |
298 "Content-Type: 1\n" | |
299 "Cache-Control: 2\n" | |
300 "ETag: 3\n" | |
301 "Chrome-Proxy: bbbypas=0\n" | |
302 "Connection: 4\n" | |
303 "Expires: 5\n" | |
304 "Chrome-Proxy: bbbloc=1\n" | |
305 "Chrome-Proxy: aaxxx=xxx \n" | |
306 "Via: \n" | |
307 "Content-Length: 12345\n", | |
308 | |
309 "aaxxx=xxx,aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,", | |
310 true, | |
311 }, | |
312 | |
313 // check Chrome-Proxy header with multiple lines, | |
314 // but different fingerprint | |
315 { | |
316 "HTTP/1.1 200 OK \n" | |
317 "Content-Type: 1\n" | |
318 "Cache-Control: 2\n" | |
319 "ETag: 3\n" | |
320 "Chrome-Proxy: bbbypas=0\n" | |
321 "Connection: 4\n" | |
322 "Expires: 5\n" | |
323 "Chrome-Proxy: bbbloc=1\n" | |
324 "Chrome-Proxy: aaxxx=xxx \n" | |
325 "Via: \n" | |
326 "Content-Length: 12345\n", | |
327 | |
328 "aaxxx=xxx,aaxxx=xxx,aut=aauutthh,bbbloc=1,bbbypas=0,", | |
329 true, | |
330 }, | |
331 | |
332 // check regular Chrome-Proxy header, but received fingerprint is empty | |
333 { | |
334 "HTTP/1.1 200 OK \n" | |
335 "Chrome-Proxy: aaxxx=xxx \n" | |
336 "Chrome-Proxy: aaxxx=xxx \n" | |
337 "Chrome-Proxy: aut=aauutthh\n" | |
338 "Content-Type: 1\n" | |
339 "Cache-Control: 2\n" | |
340 "ETag: 3\n" | |
341 "Chrome-Proxy: bbbypas=0\n" | |
342 "Connection: 4\n" | |
343 "Expires: 5\n" | |
344 "Chrome-Proxy: bbbloc=1\n" | |
345 "Chrome-Proxy: aaxxx=xxx \n" | |
346 "Via: \n" | |
347 "Content-Length: 12345\n", | |
348 | |
349 "", | |
350 true, | |
351 }, | |
352 | |
353 }; | |
354 | |
355 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) { | |
356 test[i].received_fingerprint = | |
357 GetEncoded(test[i].received_fingerprint); | |
bengr
2014/07/02 17:31:01
move up a line.
xingx
2014/07/06 03:18:20
Done.
| |
358 TestFingerprintCommon(test[i], CHROMEPROXY); | |
359 } | |
360 } | |
361 | |
362 TEST(DataReductionProxyTamperDetectTest, Via) { | |
363 FingerprintTestCase test[] = { | |
364 // check regular case, where Chrome-Compression-Proxy occurs at the last | |
365 { | |
366 "HTTP/1.1 200 OK \n" | |
367 "Via: a, b, c, Chrome-Compression-Proxy\n", | |
368 | |
369 "0", | |
370 false | |
371 }, | |
372 | |
373 // check when there is extra middlebox | |
374 // between data-reduction-proxy and phone | |
375 { | |
376 "HTTP/1.1 200 OK \n" | |
377 "Via: a, b, c, Chrome-Compression-Proxy, xyz\n", | |
378 | |
379 "0", | |
380 true, | |
381 }, | |
382 | |
383 // emtpy Via header, even no Chrome-Compression-Proxy tag | |
384 { | |
385 "HTTP/1.1 200 OK \n" | |
386 "Via: \n", | |
387 | |
388 "0", | |
389 true, | |
390 }, | |
391 | |
392 // only Chrome-Compression-Proxy tag occurs in Via header | |
393 { | |
394 "HTTP/1.1 200 OK \n" | |
395 "Via: Chrome-Compression-Proxy \n", | |
396 | |
397 "0", | |
398 false | |
399 }, | |
400 | |
401 // there are " ", i.e., empty value after Chrome-Compression-Proxy tag | |
402 // should not count as extra middleboxes | |
403 { | |
404 "HTTP/1.1 200 OK \n" | |
405 "Via: Chrome-Compression-Proxy , , \n", | |
406 | |
407 "0", | |
408 false | |
409 }, | |
410 | |
411 // special case when there is no Via header | |
412 { | |
413 "HTTP/1.1 200 OK \n", | |
414 | |
bengr
2014/07/02 17:31:01
remove blank line here and in all other cases.
xingx
2014/07/06 03:18:20
Done.
| |
415 "0", | |
416 true | |
417 }, | |
418 }; | |
419 | |
420 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) { | |
421 TestFingerprintCommon(test[i], VIA); | |
422 } | |
423 } | |
424 | |
425 TEST(DataReductionProxyTamperDetectTest, OtherHeaders) { | |
426 FingerprintTestCase test[] = { | |
427 // regular case, with correct fingerprint | |
428 { | |
429 "HTTP/1.1 200 OK \n" | |
430 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" | |
431 "Content-Type: 1\n" | |
432 "Cache-Control: 2\n" | |
433 "ETag: 3\n" | |
434 "Connection: 4\n" | |
435 "Expires: 5\n" | |
436 "Via: \n" | |
437 "Content-Length: 12345\n", | |
438 | |
439 "1,;2,;3,;4,;5,;:content-type:cache-control:etag:connection:expires", | |
440 false | |
441 }, | |
442 | |
443 // regular case, with correct fingerprint | |
444 { | |
445 "HTTP/1.1 200 OK \n" | |
446 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" | |
447 "Content-Type: aaa1\n" | |
448 "Cache-Control: aaa2\n" | |
449 "ETag: aaa3\n" | |
450 "Connection: aaa4\n" | |
451 "Expires: aaa5\n" | |
452 "Via: \n" | |
453 "Content-Length: 12345\n", | |
454 | |
455 "aaa1,;aaa2,;aaa3,;aaa4,;aaa5,;:content-type:cache-control:" | |
456 "etag:connection:expires", | |
457 false | |
458 }, | |
459 | |
460 // regular case, one header is with multiple values | |
461 { | |
462 "HTTP/1.1 200 OK \n" | |
463 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" | |
464 "Content-Type: aaa1, bbb1, ccc1\n" | |
465 "Cache-Control: aaa2\n" | |
466 "ETag: aaa3\n" | |
467 "Connection: aaa4\n" | |
468 "Expires: aaa5\n" | |
469 "Via: \n" | |
470 "Content-Length: 12345\n", | |
471 | |
472 "aaa1,bbb1,ccc1,;aaa2,;aaa3,;aaa4,;aaa5,;:" | |
473 "content-type:cache-control:etag:connection:expires", | |
474 false | |
475 }, | |
476 | |
477 // regular case, one header has multiple lines | |
478 { | |
479 "HTTP/1.1 200 OK \n" | |
480 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" | |
481 "Content-Type: aaa1, ccc1\n" | |
482 "Content-Type: xxx1, bbb1, ccc1\n" | |
483 "Cache-Control: aaa2\n" | |
484 "ETag: aaa3\n" | |
485 "Connection: aaa4\n" | |
486 "Expires: aaa5\n" | |
487 "Via: \n" | |
488 "Content-Length: 12345\n", | |
489 | |
490 "aaa1,bbb1,ccc1,ccc1,xxx1,;aaa2,;aaa3,;aaa4,;aaa5,;:" | |
491 "content-type:cache-control:etag:connection:expires", | |
492 false | |
493 }, | |
494 | |
495 // regular case, one header has multiple lines, | |
496 // and such multiple lines occur at different positions | |
497 { | |
498 "HTTP/1.1 200 OK \n" | |
499 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" | |
500 "Content-Type: aaa1, ccc1\n" | |
501 "Cache-Control: aaa2\n" | |
502 "ETag: aaa3\n" | |
503 "Content-Type: xxx1, bbb1, ccc1\n" | |
504 "Connection: aaa4\n" | |
505 "Expires: aaa5\n" | |
506 "Via: \n" | |
507 "Content-Length: 12345\n", | |
508 | |
509 "aaa1,bbb1,ccc1,ccc1,xxx1,;aaa2,;aaa3,;aaa4,;aaa5,;" | |
510 ":content-type:cache-control:etag:connection:expires", | |
511 false | |
512 }, | |
513 | |
514 // regular case, more than one header have multiple lines, | |
515 // and such multiple lines occur at different positions | |
516 { | |
517 "HTTP/1.1 200 OK \n" | |
518 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" | |
519 "Content-Type: aaa1, ccc1\n" | |
520 "Cache-Control: ccc2 , bbb2\n" | |
521 "ETag: aaa3\n" | |
522 "Content-Type: xxx1, bbb1, ccc1\n" | |
523 "Connection: aaa4\n" | |
524 "Cache-Control: aaa2 \n" | |
525 "Expires: aaa5\n" | |
526 "Via: \n" | |
527 "Content-Length: 12345\n", | |
528 | |
529 "aaa1,bbb1,ccc1,ccc1,xxx1,;aaa2,bbb2,ccc2,;aaa3,;aaa4,;aaa5,;:" | |
530 "content-type:cache-control:etag:connection:expires", | |
531 false | |
532 }, | |
533 | |
534 // regular case, response header does not have one header we need | |
535 // for fingerprint (expires) | |
536 { | |
537 "HTTP/1.1 200 OK \n" | |
538 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" | |
539 "Content-Type: aaa1, ccc1\n" | |
540 "Cache-Control: ccc2 , bbb2\n" | |
541 "ETag: aaa3\n" | |
542 "Content-Type: xxx1, bbb1, ccc1\n" | |
543 "Connection: aaa4\n" | |
544 "Cache-Control: aaa2 \n" | |
545 "Via: \n" | |
546 "Content-Length: 12345\n", | |
547 | |
548 "aaa1,bbb1,ccc1,ccc1,xxx1,;aaa2,bbb2,ccc2,;aaa3,;aaa4,;;:" | |
549 "content-type:cache-control:etag:connection:expires", | |
550 false | |
551 }, | |
552 | |
553 // regular case, response header does not have more than one header | |
554 // we need for fingerprint (content-type, expires) | |
555 { | |
556 "HTTP/1.1 200 OK \n" | |
557 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" | |
558 "Cache-Control: ccc2 , bbb2\n" | |
559 "ETag: aaa3\n" | |
560 "Connection: aaa4\n" | |
561 "Cache-Control: aaa2 \n" | |
562 "Via: \n" | |
563 "Content-Length: 12345\n", | |
564 | |
565 ";aaa2,bbb2,ccc2,;aaa3,;aaa4,;;:content-type:cache-control:" | |
566 "etag:connection:expires", | |
567 false | |
568 }, | |
569 | |
570 // regular case, all the headers we need for fingerprint are missing | |
571 { | |
572 "HTTP/1.1 200 OK \n" | |
573 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" | |
574 "Via: \n" | |
575 "Content-Length: 12345\n", | |
576 | |
577 ";;;;;:content-type:cache-control:etag:connection:expires", | |
578 false | |
579 }, | |
580 | |
581 // regular case, but differ to received fingerprint | |
582 { | |
583 "HTTP/1.1 200 OK \n" | |
584 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" | |
585 "Content-Type: aaa1, ccc1\n" | |
586 "Cache-Control: ccc2 , bbb2\n" | |
587 "ETag: etag\n" | |
588 "Content-Type: xxx1, bbb1, ccc1\n" | |
589 "Connection: aaa4\n" | |
590 "Cache-Control: aaa2 \n" | |
591 "Via: \n" | |
592 "Content-Length: 12345\n", | |
593 | |
594 "aaa1,bbb1,ccc1,ccc1,xxx1,;aaa2,bbb2,ccc2,;aaa3,;aaa4,;;:" | |
595 "content-type:cache-control:etag:connection:expires", | |
596 true, | |
597 }, | |
598 | |
599 // special case, headers are not missing but some of them are empty | |
600 { | |
601 "HTTP/1.1 200 OK \n" | |
602 "Content-Type: \n" | |
603 "Cache-Control: \n" | |
604 "ETag: \n" | |
605 "Connection: \n" | |
606 "Expires: 5\n" | |
607 "Via: \n" | |
608 "Content-Length: 12345\n", | |
609 | |
610 ",;,;,;,;5,;:content-type:cache-control:etag:connection:expires", | |
611 false | |
612 }, | |
613 | |
614 // special case, some headers do not exist, some are of empty value. | |
615 // check delimiter "," and ";" work correctly. | |
616 { | |
617 "HTTP/1.1 200 OK \n" | |
618 "Cache-Control: \n" | |
619 "Connection: \n" | |
620 "Expires: 5\n" | |
621 "Via: \n" | |
622 "Content-Length: 12345\n", | |
623 | |
624 ";,;;,;5,;:content-type:cache-control:etag:connection:expires", | |
625 false | |
626 }, | |
627 | |
628 // special case, check if we don't check any header, i.e., | |
629 // header list is empty | |
630 { | |
631 "HTTP/1.1 200 OK \n" | |
632 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" | |
633 "Content-Type: 1\n" | |
634 "Cache-Control: 2\n" | |
635 "ETag: 3\n" | |
636 "Connection: 4\n" | |
637 "Expires: 5\n" | |
638 "Via: \n" | |
639 "Content-Length: 12345\n", | |
640 | |
641 "", | |
642 false | |
643 }, | |
644 | |
645 // special case, we only want to check one header, which does not | |
646 // exist in received header | |
647 { | |
648 "HTTP/1.1 200 OK \n" | |
649 "Chrome-Proxy: aut=aauutthh,bbbypas=0,aaxxx=xxx,bbbloc=1\n" | |
650 "Content-Type: 1\n" | |
651 "Cache-Control: 2\n" | |
652 "ETag: 3\n" | |
653 "Connection: 4\n" | |
654 "Expires: 5\n" | |
655 "Via: \n" | |
656 "Content-Length: 12345\n", | |
657 | |
658 ";:non_exist_header", | |
659 false | |
660 }, | |
661 | |
662 // there is only one header in our header list | |
663 { | |
664 "HTTP/1.1 200 OK \n" | |
665 "Cache-Control: \n" | |
666 "Connection: \n" | |
667 "Expires: 5\n" | |
668 "Via: \n" | |
669 "Content-Length: 12345\n", | |
670 | |
671 ";:content-type", | |
672 false | |
673 }, | |
674 | |
675 // special case, if base64 decoding fails | |
676 { | |
677 "HTTP/1.1 200 OK \n" | |
678 "Cache-Control: \n" | |
679 "Connection: \n" | |
680 "Expires: 5\n" | |
681 "Via: \n" | |
682 "Content-Length: 12345\n", | |
683 | |
684 ";:content-type", | |
685 false | |
686 }, | |
687 | |
688 // special case, if base64 decoding fails | |
689 { | |
690 "HTTP/1.1 200 OK \n" | |
691 "Cache-Control: \n" | |
692 "Connection: \n" | |
693 "Expires: 5\n" | |
694 "Via: \n" | |
695 "Content-Length: 12345\n", | |
696 | |
697 "abcde:content-type:cache-control:etag:connection:expires", | |
698 false | |
699 }, | |
700 }; | |
701 | |
702 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) { | |
703 if (i >= ARRAYSIZE_UNSAFE(test) - 2) | |
704 { | |
705 TestFingerprintCommon(test[i], OTHERHEADERS); | |
706 continue; | |
707 } | |
708 size_t delimiter_pos = test[i].received_fingerprint.find(":"); | |
709 std::string hash, rest; | |
710 if (delimiter_pos == std::string::npos) | |
711 { | |
712 delimiter_pos = test[i].received_fingerprint.size(); | |
713 rest = ""; | |
714 } | |
715 else | |
716 rest = test[i].received_fingerprint.substr( | |
717 delimiter_pos, | |
718 test[i].received_fingerprint.size() - delimiter_pos); | |
719 hash = test[i].received_fingerprint.substr(0, delimiter_pos); | |
720 test[i].received_fingerprint = GetEncoded(hash) + rest; | |
721 | |
722 TestFingerprintCommon(test[i], OTHERHEADERS); | |
723 } | |
724 } | |
725 | |
726 TEST(DataReductionProxyTamperDetectTest, ContentLength) { | |
727 FingerprintTestCase test[] = { | |
728 // regular case, content-length is the same | |
729 { | |
730 "HTTP/1.1 200 OK \n" | |
731 "Content-Type: 1\n" | |
732 "Content-Length: 12345\n", | |
733 | |
734 "12345", | |
735 false, | |
736 }, | |
737 | |
738 // regular case, content-length is not the same | |
739 // also check if retrieved content-type is correct | |
740 { | |
741 "HTTP/1.1 200 OK \n" | |
742 "Content-Type: text/html; charset=ISO-8859-4\n" | |
743 "Content-Length: 12345\n", | |
744 | |
745 "125", | |
746 true, | |
747 }, | |
748 | |
749 // special case, data reduction proxy does not sent content-length | |
750 // i.e., content-length at data reduction proxy side is missing | |
751 { | |
752 "HTTP/1.1 200 OK \n" | |
753 "Content-Type: text/javascript\n" | |
754 "Content-Length: 12345\n", | |
755 | |
756 "", | |
757 false, | |
758 }, | |
759 | |
760 { | |
761 "HTTP/1.1 200 OK \n" | |
762 "Content-Type: text/javascript\n" | |
763 "Content-Length: 12345\n", | |
764 | |
765 "aaa", | |
766 false, | |
767 }, | |
768 | |
769 { | |
770 "HTTP/1.1 200 OK \n" | |
771 "Content-Type: text/javascript\n" | |
772 "Content-Length: aaa\n", | |
773 | |
774 "aaa", | |
775 false, | |
776 }, | |
777 | |
778 // special case, content-length are missing at both end | |
779 // i.e., both data reduction proxy and chrome | |
780 { | |
781 "HTTP/1.1 200 OK \n" | |
782 "Content-Type: 1\n", | |
783 | |
784 "", | |
785 false, | |
786 }, | |
787 | |
788 // special case, check when content-length is 0 | |
789 { | |
790 "HTTP/1.1 200 OK \n" | |
791 "Content-Type: application/x-javascript\n" | |
792 "Content-Length: 0\n", | |
793 | |
794 "0", | |
795 false, | |
796 }, | |
797 | |
798 // special case, check when data reduction proxy side's | |
799 // content-length is empty (header exist, but value is empty) | |
800 { | |
801 "HTTP/1.1 200 OK \n" | |
802 "Content-Type: application/x-javascript\n" | |
803 "Content-Length: 123\n", | |
804 | |
805 ",", | |
806 false, | |
807 }, | |
808 | |
809 // when content-length is different, check whether it recognizes image. | |
810 { | |
811 "HTTP/1.1 200 OK \n" | |
812 "Content-Type: image/gif \n" | |
813 "Content-Length: 123\n", | |
814 | |
815 "0", | |
816 true, | |
817 }, | |
818 | |
819 // when content-length is different, check whether it recognizes JS | |
820 { | |
821 "HTTP/1.1 200 OK \n" | |
822 "Content-Type: application/x-javascript \n" | |
823 "Content-Length: 0\n", | |
824 | |
825 "120", | |
826 true, | |
827 }, | |
828 | |
829 // when content-length is different, check whether it recognizes JS | |
830 { | |
831 "HTTP/1.1 200 OK \n" | |
832 "Content-Type: text/javascript \n" | |
833 "Content-Length: 123\n", | |
834 | |
835 "0", | |
836 true, | |
837 }, | |
838 | |
839 // when content-length is different, check whether it recognizes CSS | |
840 { | |
841 "HTTP/1.1 200 OK \n" | |
842 "Content-Type: text/css\n" | |
843 "Content-Length: 111\n", | |
844 | |
845 "0", | |
846 true, | |
847 }, | |
848 | |
849 // when content-length is different (chrome side is missing), | |
850 // check whether it recognizes JS. | |
851 // (if phone side's content-length has been removed, shall we report? | |
852 // current implementation: not reporting.) | |
853 { | |
854 "HTTP/1.1 200 OK \n" | |
855 "Content-Type: application/javascript \n", | |
856 | |
857 "123", | |
858 false, | |
859 }, | |
860 | |
861 }; | |
862 | |
863 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) { | |
864 TestFingerprintCommon(test[i], CONTENTLENGTH); | |
865 } | |
866 } | |
867 | |
868 TEST(DataReductionProxyTamperDetectTest, Parsing) { | |
869 ParsingTestCase test[] = { | |
870 // Check normal case, Chrome-Proxy fingerprint doesn't exist | |
871 { | |
872 "HTTP/1.1 200 OK \n" | |
873 "Chrome-Proxy: f1:f1&f2:f2&f3:f3&f4:f4\n", | |
874 "", | |
875 "", | |
876 false | |
877 }, | |
878 // Check normal case, Chrome-Proxy fingerprint exist, | |
879 // but other headers' fingerprint is not there. | |
880 { | |
881 "HTTP/1.1 200 OK \n" | |
882 "Chrome-Proxy: f1, " + | |
883 std::string(data_reduction_proxy::kTamperDetectFingerprintChromeProxy) | |
884 + "abc \n", | |
885 "abc", | |
886 "", | |
887 true | |
888 }, | |
889 | |
890 // Check normal case, both Chrome-Proxy fingerprint | |
891 // and other headers' fingerprint exist, | |
892 // but with different values and occur at different position. | |
893 { | |
894 "HTTP/1.1 200 OK \n" | |
895 "Chrome-Proxy: f1, " + | |
896 std::string(data_reduction_proxy::kTamperDetectFingerprintChromeProxy) | |
897 + "abc \n" | |
898 "Chrome-Proxy: " + | |
899 std::string(data_reduction_proxy::kTamperDetectFingerprint) + "def\n", | |
900 "abc", | |
901 "def", | |
902 true | |
903 }, | |
904 | |
905 { | |
906 "HTTP/1.1 200 OK \n" | |
907 "Chrome-Proxy: f1, " + | |
908 std::string(data_reduction_proxy::kTamperDetectFingerprintChromeProxy) | |
909 + "abc," + | |
910 data_reduction_proxy::kTamperDetectFingerprint + "def \n", | |
911 "abc", | |
912 "def", | |
913 true | |
914 }, | |
915 | |
916 { | |
917 "HTTP/1.1 200 OK \n" | |
918 "Chrome-Proxy: f1, " + | |
919 std::string(data_reduction_proxy::kTamperDetectFingerprintChromeProxy) | |
920 + "def," + | |
921 data_reduction_proxy::kTamperDetectFingerprint + "abc \n", | |
922 "def", | |
923 "abc", | |
924 true | |
925 }, | |
926 | |
927 { | |
928 "HTTP/1.1 200 OK \n" | |
929 "Chrome-Proxy: f1, " + | |
930 std::string(data_reduction_proxy::kTamperDetectFingerprint) + "abc," + | |
931 data_reduction_proxy::kTamperDetectFingerprintChromeProxy + "def \n", | |
932 "def", | |
933 "abc", | |
934 true | |
935 }, | |
936 | |
937 { | |
938 "HTTP/1.1 200 OK \n" | |
939 "Chrome-Proxy: f1, " + | |
940 std::string(data_reduction_proxy::kTamperDetectFingerprint) + "def," + | |
941 data_reduction_proxy::kTamperDetectFingerprintChromeProxy + "abc \n", | |
942 "abc", | |
943 "def", | |
944 true | |
945 }, | |
946 | |
947 }; | |
948 | |
949 for (size_t i=0; i<ARRAYSIZE_UNSAFE(test); ++i) { | |
950 TestParsingCommon(test[i]); | |
951 } | |
952 } | |
953 | |
954 } // namespace | |
OLD | NEW |