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