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