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 <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 |
OLD | NEW |