1 // Copyright (c) 2012 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 "extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.h" 6 7 #include "base/basictypes.h" 8 #include "base/files/file_path.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/values.h" 12 #include "content/public/browser/resource_request_info.h" 13 #include "extensions/browser/api/declarative_webrequest/webrequest_condition.h" 14 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h" 15 #include "net/base/request_priority.h" 16 #include "net/test/embedded_test_server/embedded_test_server.h" 17 #include "net/url_request/url_request.h" 18 #include "net/url_request/url_request_test_util.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 using base::DictionaryValue; 22 using base::FundamentalValue; 23 using base::ListValue; 24 using base::StringValue; 25 using base::Value; 26 using content::ResourceType; 27 28 namespace extensions { 29 30 namespace keys = declarative_webrequest_constants; 31 32 namespace { 33 const char kUnknownConditionName[] = "unknownType"; 34 35 base::FilePath TestDataPath(base::StringPiece relative_to_src) { 36 base::FilePath src_dir; 37 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)); 38 return src_dir.AppendASCII(relative_to_src); 39 } 40 41 TEST(WebRequestConditionAttributeTest, CreateConditionAttribute) { 42 // Necessary for TestURLRequest. 43 base::MessageLoopForIO message_loop; 44 45 std::string error; 46 scoped_refptr<const WebRequestConditionAttribute> result; 47 base::StringValue string_value("main_frame"); 48 base::ListValue resource_types; 49 resource_types.Append(new base::StringValue("main_frame")); 50 51 // Test wrong condition name passed. 52 error.clear(); 53 result = WebRequestConditionAttribute::Create( 54 kUnknownConditionName, &resource_types, &error); 55 EXPECT_FALSE(error.empty()); 56 EXPECT_FALSE(result.get()); 57 58 // Test wrong data type passed 59 error.clear(); 60 result = WebRequestConditionAttribute::Create( 61 keys::kResourceTypeKey, &string_value, &error); 62 EXPECT_FALSE(error.empty()); 63 EXPECT_FALSE(result.get()); 64 65 error.clear(); 66 result = WebRequestConditionAttribute::Create( 67 keys::kContentTypeKey, &string_value, &error); 68 EXPECT_FALSE(error.empty()); 69 EXPECT_FALSE(result.get()); 70 71 // Test success 72 error.clear(); 73 result = WebRequestConditionAttribute::Create( 74 keys::kResourceTypeKey, &resource_types, &error); 75 EXPECT_EQ("", error); 76 ASSERT_TRUE(result.get()); 77 EXPECT_EQ(WebRequestConditionAttribute::CONDITION_RESOURCE_TYPE, 78 result->GetType()); 79 EXPECT_EQ(std::string(keys::kResourceTypeKey), result->GetName()); 80 } 81 82 TEST(WebRequestConditionAttributeTest, ResourceType) { 83 // Necessary for TestURLRequest. 84 base::MessageLoopForIO message_loop; 85 86 std::string error; 87 base::ListValue resource_types; 88 // The 'sub_frame' value is chosen arbitrarily, so as the corresponding 89 // content::ResourceType is not 0, the default value. 90 resource_types.Append(new base::StringValue("sub_frame")); 91 92 scoped_refptr<const WebRequestConditionAttribute> attribute = 93 WebRequestConditionAttribute::Create( 94 keys::kResourceTypeKey, &resource_types, &error); 95 EXPECT_EQ("", error); 96 ASSERT_TRUE(attribute.get()); 97 EXPECT_EQ(std::string(keys::kResourceTypeKey), attribute->GetName()); 98 99 net::TestURLRequestContext context; 100 scoped_ptr<net::URLRequest> url_request_ok(context.CreateRequest( 101 GURL("http://www.example.com"), net::DEFAULT_PRIORITY, NULL, NULL)); 102 content::ResourceRequestInfo::AllocateForTesting( 103 url_request_ok.get(), 104 content::RESOURCE_TYPE_SUB_FRAME, 105 NULL, 106 -1, 107 -1, 108 -1, 109 false); 110 EXPECT_TRUE(attribute->IsFulfilled(WebRequestData(url_request_ok.get(), 111 ON_BEFORE_REQUEST))); 112 113 scoped_ptr<net::URLRequest> url_request_fail(context.CreateRequest( 114 GURL("http://www.example.com"), net::DEFAULT_PRIORITY, NULL, NULL)); 115 content::ResourceRequestInfo::AllocateForTesting( 116 url_request_fail.get(), 117 content::RESOURCE_TYPE_MAIN_FRAME, 118 NULL, 119 -1, 120 -1, 121 -1, 122 false); 123 EXPECT_FALSE(attribute->IsFulfilled(WebRequestData(url_request_fail.get(), 124 ON_BEFORE_REQUEST))); 125 } 126 127 TEST(WebRequestConditionAttributeTest, ContentType) { 128 // Necessary for TestURLRequest. 129 base::MessageLoopForIO message_loop; 130 131 std::string error; 132 scoped_refptr<const WebRequestConditionAttribute> result; 133 134 net::test_server::EmbeddedTestServer test_server; 135 test_server.ServeFilesFromDirectory(TestDataPath( 136 "chrome/test/data/extensions/api_test/webrequest/declarative")); 137 ASSERT_TRUE(test_server.InitializeAndWaitUntilReady()); 138 139 net::TestURLRequestContext context; 140 net::TestDelegate delegate; 141 scoped_ptr<net::URLRequest> url_request( 142 context.CreateRequest(test_server.GetURL("/headers.html"), 143 net::DEFAULT_PRIORITY, 144 &delegate, 145 NULL)); 146 url_request->Start(); 147 base::MessageLoop::current()->Run(); 148 149 base::ListValue content_types; 150 content_types.Append(new base::StringValue("text/plain")); 151 scoped_refptr<const WebRequestConditionAttribute> attribute_include = 152 WebRequestConditionAttribute::Create( 153 keys::kContentTypeKey, &content_types, &error); 154 EXPECT_EQ("", error); 155 ASSERT_TRUE(attribute_include.get()); 156 EXPECT_FALSE(attribute_include->IsFulfilled( 157 WebRequestData(url_request.get(), ON_BEFORE_REQUEST, 158 url_request->response_headers()))); 159 EXPECT_TRUE(attribute_include->IsFulfilled( 160 WebRequestData(url_request.get(), ON_HEADERS_RECEIVED, 161 url_request->response_headers()))); 162 EXPECT_EQ(std::string(keys::kContentTypeKey), attribute_include->GetName()); 163 164 scoped_refptr<const WebRequestConditionAttribute> attribute_exclude = 165 WebRequestConditionAttribute::Create( 166 keys::kExcludeContentTypeKey, &content_types, &error); 167 EXPECT_EQ("", error); 168 ASSERT_TRUE(attribute_exclude.get()); 169 EXPECT_FALSE(attribute_exclude->IsFulfilled( 170 WebRequestData(url_request.get(), ON_HEADERS_RECEIVED, 171 url_request->response_headers()))); 172 173 content_types.Clear(); 174 content_types.Append(new base::StringValue("something/invalid")); 175 scoped_refptr<const WebRequestConditionAttribute> attribute_unincluded = 176 WebRequestConditionAttribute::Create( 177 keys::kContentTypeKey, &content_types, &error); 178 EXPECT_EQ("", error); 179 ASSERT_TRUE(attribute_unincluded.get()); 180 EXPECT_FALSE(attribute_unincluded->IsFulfilled( 181 WebRequestData(url_request.get(), ON_HEADERS_RECEIVED, 182 url_request->response_headers()))); 183 184 scoped_refptr<const WebRequestConditionAttribute> attribute_unexcluded = 185 WebRequestConditionAttribute::Create( 186 keys::kExcludeContentTypeKey, &content_types, &error); 187 EXPECT_EQ("", error); 188 ASSERT_TRUE(attribute_unexcluded.get()); 189 EXPECT_TRUE(attribute_unexcluded->IsFulfilled( 190 WebRequestData(url_request.get(), ON_HEADERS_RECEIVED, 191 url_request->response_headers()))); 192 EXPECT_EQ(std::string(keys::kExcludeContentTypeKey), 193 attribute_unexcluded->GetName()); 194 } 195 196 // Testing WebRequestConditionAttributeThirdParty. 197 TEST(WebRequestConditionAttributeTest, ThirdParty) { 198 // Necessary for TestURLRequest. 199 base::MessageLoopForIO message_loop; 200 201 std::string error; 202 const FundamentalValue value_true(true); 203 // This attribute matches only third party requests. 204 scoped_refptr<const WebRequestConditionAttribute> third_party_attribute = 205 WebRequestConditionAttribute::Create(keys::kThirdPartyKey, 206 &value_true, 207 &error); 208 ASSERT_EQ("", error); 209 ASSERT_TRUE(third_party_attribute.get()); 210 EXPECT_EQ(std::string(keys::kThirdPartyKey), 211 third_party_attribute->GetName()); 212 const FundamentalValue value_false(false); 213 // This attribute matches only first party requests. 214 scoped_refptr<const WebRequestConditionAttribute> first_party_attribute = 215 WebRequestConditionAttribute::Create(keys::kThirdPartyKey, 216 &value_false, 217 &error); 218 ASSERT_EQ("", error); 219 ASSERT_TRUE(first_party_attribute.get()); 220 EXPECT_EQ(std::string(keys::kThirdPartyKey), 221 first_party_attribute->GetName()); 222 223 const GURL url_empty; 224 const GURL url_a("http://a.com"); 225 const GURL url_b("http://b.com"); 226 net::TestURLRequestContext context; 227 net::TestDelegate delegate; 228 scoped_ptr<net::URLRequest> url_request( 229 context.CreateRequest(url_a, net::DEFAULT_PRIORITY, &delegate, NULL)); 230 231 for (unsigned int i = 1; i <= kLastActiveStage; i <<= 1) { 232 if (!(kActiveStages & i)) 233 continue; 234 const RequestStage stage = static_cast<RequestStage>(i); 235 url_request->set_first_party_for_cookies(url_empty); 236 EXPECT_FALSE(third_party_attribute->IsFulfilled( 237 WebRequestData(url_request.get(), stage))); 238 EXPECT_TRUE(first_party_attribute->IsFulfilled( 239 WebRequestData(url_request.get(), stage))); 240 241 url_request->set_first_party_for_cookies(url_b); 242 EXPECT_TRUE(third_party_attribute->IsFulfilled( 243 WebRequestData(url_request.get(), stage))); 244 EXPECT_FALSE(first_party_attribute->IsFulfilled( 245 WebRequestData(url_request.get(), stage))); 246 247 url_request->set_first_party_for_cookies(url_a); 248 EXPECT_FALSE(third_party_attribute->IsFulfilled( 249 WebRequestData(url_request.get(), stage))); 250 EXPECT_TRUE(first_party_attribute->IsFulfilled( 251 WebRequestData(url_request.get(), stage))); 252 } 253 } 254 255 // Testing WebRequestConditionAttributeStages. This iterates over all stages, 256 // and tests a couple of "stage" attributes -- one created with an empty set of 257 // applicable stages, one for each stage applicable for that stage, and one 258 // applicable in all stages. 259 TEST(WebRequestConditionAttributeTest, Stages) { 260 // Necessary for TestURLRequest. 261 base::MessageLoopForIO message_loop; 262 263 typedef std::pair<RequestStage, const char*> StageNamePair; 264 static const StageNamePair active_stages[] = { 265 StageNamePair(ON_BEFORE_REQUEST, keys::kOnBeforeRequestEnum), 266 StageNamePair(ON_BEFORE_SEND_HEADERS, keys::kOnBeforeSendHeadersEnum), 267 StageNamePair(ON_HEADERS_RECEIVED, keys::kOnHeadersReceivedEnum), 268 StageNamePair(ON_AUTH_REQUIRED, keys::kOnAuthRequiredEnum) 269 }; 270 271 // Check that exactly all active stages are considered in this test. 272 unsigned int covered_stages = 0; 273 for (size_t i = 0; i < arraysize(active_stages); ++i) 274 covered_stages |= active_stages[i].first; 275 EXPECT_EQ(kActiveStages, covered_stages); 276 277 std::string error; 278 279 // Create an attribute with an empty set of applicable stages. 280 base::ListValue empty_list; 281 scoped_refptr<const WebRequestConditionAttribute> empty_attribute = 282 WebRequestConditionAttribute::Create(keys::kStagesKey, 283 &empty_list, 284 &error); 285 EXPECT_EQ("", error); 286 ASSERT_TRUE(empty_attribute.get()); 287 EXPECT_EQ(std::string(keys::kStagesKey), empty_attribute->GetName()); 288 289 // Create an attribute with all possible applicable stages. 290 base::ListValue all_stages; 291 for (size_t i = 0; i < arraysize(active_stages); ++i) 292 all_stages.AppendString(active_stages[i].second); 293 scoped_refptr<const WebRequestConditionAttribute> attribute_with_all = 294 WebRequestConditionAttribute::Create(keys::kStagesKey, 295 &all_stages, 296 &error); 297 EXPECT_EQ("", error); 298 ASSERT_TRUE(attribute_with_all.get()); 299 EXPECT_EQ(std::string(keys::kStagesKey), attribute_with_all->GetName()); 300 301 // Create one attribute for each single stage, to be applicable in that stage. 302 std::vector<scoped_refptr<const WebRequestConditionAttribute> > 303 one_stage_attributes; 304 305 for (size_t i = 0; i < arraysize(active_stages); ++i) { 306 base::ListValue single_stage_list; 307 single_stage_list.AppendString(active_stages[i].second); 308 one_stage_attributes.push_back( 309 WebRequestConditionAttribute::Create(keys::kStagesKey, 310 &single_stage_list, 311 &error)); 312 EXPECT_EQ("", error); 313 ASSERT_TRUE(one_stage_attributes.back().get() != NULL); 314 } 315 316 const GURL url_empty; 317 net::TestURLRequestContext context; 318 net::TestDelegate delegate; 319 scoped_ptr<net::URLRequest> url_request( 320 context.CreateRequest(url_empty, net::DEFAULT_PRIORITY, &delegate, NULL)); 321 322 for (size_t i = 0; i < arraysize(active_stages); ++i) { 323 EXPECT_FALSE(empty_attribute->IsFulfilled( 324 WebRequestData(url_request.get(), active_stages[i].first))); 325 326 for (size_t j = 0; j < one_stage_attributes.size(); ++j) { 327 EXPECT_EQ(i == j, 328 one_stage_attributes[j]->IsFulfilled( 329 WebRequestData(url_request.get(), active_stages[i].first))); 330 } 331 332 EXPECT_TRUE(attribute_with_all->IsFulfilled( 333 WebRequestData(url_request.get(), active_stages[i].first))); 334 } 335 } 336 337 namespace { 338 339 // Builds a vector of vectors of string pointers from an array of strings. 340 // |array| is in fact a sequence of arrays. The array |sizes| captures the sizes 341 // of all parts of |array|, and |size| is the length of |sizes| itself. 342 // Example (this is pseudo-code, not C++): 343 // array = { "a", "b", "c", "d", "e", "f" } 344 // sizes = { 2, 0, 4 } 345 // size = 3 346 // results in out == { {&"a", &"b"}, {}, {&"c", &"d", &"e", &"f"} } 347 void GetArrayAsVector(const std::string array[], 348 const size_t sizes[], 349 const size_t size, 350 std::vector< std::vector<const std::string*> >* out) { 351 out->clear(); 352 size_t next = 0; 353 for (size_t i = 0; i < size; ++i) { 354 out->push_back(std::vector<const std::string*>()); 355 for (size_t j = next; j < next + sizes[i]; ++j) { 356 out->back().push_back(&(array[j])); 357 } 358 next += sizes[i]; 359 } 360 } 361 362 // Builds a DictionaryValue from an array of the form {name1, value1, name2, 363 // value2, ...}. Values for the same key are grouped in a ListValue. 364 scoped_ptr<base::DictionaryValue> GetDictionaryFromArray( 365 const std::vector<const std::string*>& array) { 366 const size_t length = array.size(); 367 CHECK(length % 2 == 0); 368 369 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue); 370 for (size_t i = 0; i < length; i += 2) { 371 const std::string* name = array[i]; 372 const std::string* value = array[i+1]; 373 if (dictionary->HasKey(*name)) { 374 base::Value* entry = NULL; 375 scoped_ptr<base::Value> entry_owned; 376 base::ListValue* list = NULL; 377 if (!dictionary->GetWithoutPathExpansion(*name, &entry)) 378 return scoped_ptr<base::DictionaryValue>(); 379 switch (entry->GetType()) { 380 case base::Value::TYPE_STRING: 381 // Replace the present string with a list. 382 list = new base::ListValue; 383 // Ignoring return value, we already verified the entry is there. 384 dictionary->RemoveWithoutPathExpansion(*name, &entry_owned); 385 list->Append(entry_owned.release()); 386 list->Append(new base::StringValue(*value)); 387 dictionary->SetWithoutPathExpansion(*name, list); 388 break; 389 case base::Value::TYPE_LIST: // Just append to the list. 390 CHECK(entry->GetAsList(&list)); 391 list->Append(new base::StringValue(*value)); 392 break; 393 default: 394 NOTREACHED(); // We never put other Values here. 395 return scoped_ptr<base::DictionaryValue>(); 396 } 397 } else { 398 dictionary->SetString(*name, *value); 399 } 400 } 401 return dictionary.Pass(); 402 } 403 404 // Returns whether the response headers from |url_request| satisfy the match 405 // criteria given in |tests|. For at least one |i| all tests from |tests[i]| 406 // must pass. If |positive_test| is true, the dictionary is interpreted as the 407 // containsHeaders property of a RequestMatcher, otherwise as 408 // doesNotContainHeaders. 409 void MatchAndCheck(const std::vector< std::vector<const std::string*> >& tests, 410 const std::string& key, 411 RequestStage stage, 412 net::URLRequest* url_request, 413 bool* result) { 414 base::ListValue contains_headers; 415 for (size_t i = 0; i < tests.size(); ++i) { 416 scoped_ptr<base::DictionaryValue> temp(GetDictionaryFromArray(tests[i])); 417 ASSERT_TRUE(temp.get()); 418 contains_headers.Append(temp.release()); 419 } 420 421 std::string error; 422 scoped_refptr<const WebRequestConditionAttribute> attribute = 423 WebRequestConditionAttribute::Create(key, &contains_headers, &error); 424 ASSERT_EQ("", error); 425 ASSERT_TRUE(attribute.get()); 426 EXPECT_EQ(key, attribute->GetName()); 427 428 *result = attribute->IsFulfilled(WebRequestData( 429 url_request, stage, url_request->response_headers())); 430 } 431 432 } // namespace 433 434 // Here we test WebRequestConditionAttributeRequestHeaders for matching 435 // correctly against request headers. This test is not as extensive as 436 // "ResponseHeaders" (below), because the header-matching code is shared 437 // by both types of condition attributes, so it is enough to test it once. 438 TEST(WebRequestConditionAttributeTest, RequestHeaders) { 439 // Necessary for TestURLRequest. 440 base::MessageLoopForIO message_loop; 441 442 net::TestURLRequestContext context; 443 net::TestDelegate delegate; 444 scoped_ptr<net::URLRequest> url_request( 445 context.CreateRequest(GURL("http://example.com"), // Dummy URL. 446 net::DEFAULT_PRIORITY, 447 &delegate, 448 NULL)); 449 url_request->SetExtraRequestHeaderByName( 450 "Custom-header", "custom/value", true /* overwrite */); 451 url_request->Start(); 452 base::MessageLoop::current()->Run(); 453 454 std::vector<std::vector<const std::string*> > tests; 455 bool result = false; 456 457 const RequestStage stage = ON_BEFORE_SEND_HEADERS; 458 459 // First set of test data -- passing conjunction. 460 const std::string kPassingCondition[] = { 461 keys::kNameContainsKey, "CuStOm", // Header names are case insensitive. 462 keys::kNameEqualsKey, "custom-header", 463 keys::kValueSuffixKey, "alue", 464 keys::kValuePrefixKey, "custom/value" 465 }; 466 const size_t kPassingConditionSizes[] = { arraysize(kPassingCondition) }; 467 GetArrayAsVector(kPassingCondition, kPassingConditionSizes, 1u, &tests); 468 // Positive filter, passing (conjunction of tests). 469 MatchAndCheck( 470 tests, keys::kRequestHeadersKey, stage, url_request.get(), &result); 471 EXPECT_TRUE(result); 472 // Negative filter, failing (conjunction of tests). 473 MatchAndCheck(tests, keys::kExcludeRequestHeadersKey, stage, 474 url_request.get(), &result); 475 EXPECT_FALSE(result); 476 477 // Second set of test data -- failing disjunction. 478 const std::string kFailCondition[] = { 479 keys::kNameSuffixKey, "Custom", // Test 1. 480 keys::kNameEqualsKey, "ustom-valu", // Test 2. 481 keys::kValuePrefixKey, "custom ", // Test 3. 482 keys::kValueContainsKey, " value" // Test 4. 483 }; 484 const size_t kFailConditionSizes[] = { 2u, 2u, 2u, 2u }; 485 GetArrayAsVector(kFailCondition, kFailConditionSizes, 4u, &tests); 486 // Positive filter, failing (disjunction of tests). 487 MatchAndCheck(tests, keys::kRequestHeadersKey, stage, url_request.get(), 488 &result); 489 EXPECT_FALSE(result); 490 // Negative filter, passing (disjunction of tests). 491 MatchAndCheck(tests, keys::kExcludeRequestHeadersKey, stage, 492 url_request.get(), &result); 493 EXPECT_TRUE(result); 494 495 // Third set of test data, corner case -- empty disjunction. 496 GetArrayAsVector(NULL, NULL, 0u, &tests); 497 // Positive filter, failing (no test to pass). 498 MatchAndCheck(tests, keys::kRequestHeadersKey, stage, url_request.get(), 499 &result); 500 EXPECT_FALSE(result); 501 // Negative filter, passing (no test to fail). 502 MatchAndCheck(tests, keys::kExcludeRequestHeadersKey, stage, 503 url_request.get(), &result); 504 EXPECT_TRUE(result); 505 506 // Fourth set of test data, corner case -- empty conjunction. 507 const size_t kEmptyConjunctionSizes[] = { 0u }; 508 GetArrayAsVector(NULL, kEmptyConjunctionSizes, 1u, &tests); 509 // Positive filter, passing (trivial test). 510 MatchAndCheck(tests, keys::kRequestHeadersKey, stage, url_request.get(), 511 &result); 512 EXPECT_TRUE(result); 513 // Negative filter, failing. 514 MatchAndCheck(tests, keys::kExcludeRequestHeadersKey, stage, 515 url_request.get(), &result); 516 EXPECT_FALSE(result); 517 } 518 519 // Here we test WebRequestConditionAttributeResponseHeaders for: 520 // 1. Correct implementation of prefix/suffix/contains/equals matching. 521 // 2. Performing logical disjunction (||) between multiple specifications. 522 // 3. Negating the match in case of 'doesNotContainHeaders'. 523 TEST(WebRequestConditionAttributeTest, ResponseHeaders) { 524 // Necessary for TestURLRequest. 525 base::MessageLoopForIO message_loop; 526 527 net::test_server::EmbeddedTestServer test_server; 528 test_server.ServeFilesFromDirectory(TestDataPath( 529 "chrome/test/data/extensions/api_test/webrequest/declarative")); 530 ASSERT_TRUE(test_server.InitializeAndWaitUntilReady()); 531 532 net::TestURLRequestContext context; 533 net::TestDelegate delegate; 534 scoped_ptr<net::URLRequest> url_request( 535 context.CreateRequest(test_server.GetURL("/headers.html"), 536 net::DEFAULT_PRIORITY, 537 &delegate, 538 NULL)); 539 url_request->Start(); 540 base::MessageLoop::current()->Run(); 541 542 // In all the tests below we assume that the server includes the headers 543 // Custom-Header: custom/value 544 // Custom-Header-B: valueA 545 // Custom-Header-B: valueB 546 // Custom-Header-C: valueC, valueD 547 // Custom-Header-D: 548 // in the response, but does not include "Non-existing: void". 549 550 std::vector< std::vector<const std::string*> > tests; 551 bool result; 552 553 const RequestStage stage = ON_HEADERS_RECEIVED; 554 555 // 1.a. -- All these tests should pass. 556 const std::string kPassingCondition[] = { 557 keys::kNamePrefixKey, "Custom", 558 keys::kNameSuffixKey, "m-header", // Header names are case insensitive. 559 keys::kValueContainsKey, "alu", 560 keys::kValueEqualsKey, "custom/value" 561 }; 562 const size_t kPassingConditionSizes[] = { arraysize(kPassingCondition) }; 563 GetArrayAsVector(kPassingCondition, kPassingConditionSizes, 1u, &tests); 564 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), 565 &result); 566 EXPECT_TRUE(result); 567 568 // 1.b. -- None of the following tests in the discjunction should pass. 569 const std::string kFailCondition[] = { 570 keys::kNamePrefixKey, " Custom", // Test 1. 571 keys::kNameContainsKey, " -", // Test 2. 572 keys::kValueSuffixKey, "alu", // Test 3. 573 keys::kValueEqualsKey, "custom" // Test 4. 574 }; 575 const size_t kFailConditionSizes[] = { 2u, 2u, 2u, 2u }; 576 GetArrayAsVector(kFailCondition, kFailConditionSizes, 4u, &tests); 577 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), 578 &result); 579 EXPECT_FALSE(result); 580 581 // 1.c. -- This should fail (mixing name and value from different headers) 582 const std::string kMixingCondition[] = { 583 keys::kNameSuffixKey, "Header-B", 584 keys::kValueEqualsKey, "custom/value" 585 }; 586 const size_t kMixingConditionSizes[] = { arraysize(kMixingCondition) }; 587 GetArrayAsVector(kMixingCondition, kMixingConditionSizes, 1u, &tests); 588 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), 589 &result); 590 EXPECT_FALSE(result); 591 592 // 1.d. -- Test handling multiple values for one header (both should pass). 593 const std::string kMoreValues1[] = { 594 keys::kNameEqualsKey, "Custom-header-b", 595 keys::kValueEqualsKey, "valueA" 596 }; 597 const size_t kMoreValues1Sizes[] = { arraysize(kMoreValues1) }; 598 GetArrayAsVector(kMoreValues1, kMoreValues1Sizes, 1u, &tests); 599 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), 600 &result); 601 EXPECT_TRUE(result); 602 const std::string kMoreValues2[] = { 603 keys::kNameEqualsKey, "Custom-header-b", 604 keys::kValueEqualsKey, "valueB" 605 }; 606 const size_t kMoreValues2Sizes[] = { arraysize(kMoreValues2) }; 607 GetArrayAsVector(kMoreValues2, kMoreValues2Sizes, 1u, &tests); 608 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), 609 &result); 610 EXPECT_TRUE(result); 611 612 // 1.e. -- This should fail as conjunction but pass as disjunction. 613 const std::string kConflict[] = { 614 keys::kNameSuffixKey, "Header", // True for some header. 615 keys::kNameContainsKey, "Header-B" // True for a different header. 616 }; 617 // First disjunction, no conflict. 618 const size_t kNoConflictSizes[] = { 2u, 2u }; 619 GetArrayAsVector(kConflict, kNoConflictSizes, 2u, &tests); 620 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), 621 &result); 622 EXPECT_TRUE(result); 623 // Then conjunction, conflict. 624 const size_t kConflictSizes[] = { arraysize(kConflict) }; 625 GetArrayAsVector(kConflict, kConflictSizes, 1u, &tests); 626 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), 627 &result); 628 EXPECT_FALSE(result); 629 630 // 1.f. -- This should pass, checking for correct treatment of ',' in values. 631 const std::string kComma[] = { 632 keys::kNameSuffixKey, "Header-C", 633 keys::kValueEqualsKey, "valueC, valueD" 634 }; 635 const size_t kCommaSizes[] = { arraysize(kComma) }; 636 GetArrayAsVector(kComma, kCommaSizes, 1u, &tests); 637 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), 638 &result); 639 EXPECT_TRUE(result); 640 641 // 1.g. -- This should pass, empty values are values as well. 642 const std::string kEmpty[] = { 643 keys::kNameEqualsKey, "custom-header-d", 644 keys::kValueEqualsKey, "" 645 }; 646 const size_t kEmptySizes[] = { arraysize(kEmpty) }; 647 GetArrayAsVector(kEmpty, kEmptySizes, 1u, &tests); 648 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), 649 &result); 650 EXPECT_TRUE(result); 651 652 // 1.h. -- Values are case-sensitive, this should fail. 653 const std::string kLowercase[] = { 654 keys::kNameEqualsKey, "Custom-header-b", 655 keys::kValuePrefixKey, "valueb", // valueb != valueB 656 keys::kNameEqualsKey, "Custom-header-b", 657 keys::kValueSuffixKey, "valueb", 658 keys::kNameEqualsKey, "Custom-header-b", 659 keys::kValueContainsKey, "valueb", 660 keys::kNameEqualsKey, "Custom-header-b", 661 keys::kValueEqualsKey, "valueb" 662 }; 663 const size_t kLowercaseSizes[] = { 4u, 4u, 4u, 4u }; // As disjunction. 664 GetArrayAsVector(kLowercase, kLowercaseSizes, 4u, &tests); 665 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), 666 &result); 667 EXPECT_FALSE(result); 668 669 // 1.i. -- Names are case-insensitive, this should pass. 670 const std::string kUppercase[] = { 671 keys::kNamePrefixKey, "CUSTOM-HEADER-B", 672 keys::kNameSuffixKey, "CUSTOM-HEADER-B", 673 keys::kNameEqualsKey, "CUSTOM-HEADER-B", 674 keys::kNameContainsKey, "CUSTOM-HEADER-B" 675 }; 676 const size_t kUppercaseSizes[] = { arraysize(kUppercase) }; // Conjunction. 677 GetArrayAsVector(kUppercase, kUppercaseSizes, 1u, &tests); 678 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), 679 &result); 680 EXPECT_TRUE(result); 681 682 // 2.a. -- This should pass as disjunction, because one of the tests passes. 683 const std::string kDisjunction[] = { 684 keys::kNamePrefixKey, "Non-existing", // This one fails. 685 keys::kNameSuffixKey, "Non-existing", // This one fails. 686 keys::kValueEqualsKey, "void", // This one fails. 687 keys::kValueContainsKey, "alu" // This passes. 688 }; 689 const size_t kDisjunctionSizes[] = { 2u, 2u, 2u, 2u }; 690 GetArrayAsVector(kDisjunction, kDisjunctionSizes, 4u, &tests); 691 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), 692 &result); 693 EXPECT_TRUE(result); 694 695 // 3.a. -- This should pass. 696 const std::string kNonExistent[] = { 697 keys::kNameEqualsKey, "Non-existing", 698 keys::kValueEqualsKey, "void" 699 }; 700 const size_t kNonExistentSizes[] = { arraysize(kNonExistent) }; 701 GetArrayAsVector(kNonExistent, kNonExistentSizes, 1u, &tests); 702 MatchAndCheck(tests, keys::kExcludeResponseHeadersKey, stage, 703 url_request.get(), &result); 704 EXPECT_TRUE(result); 705 706 // 3.b. -- This should fail. 707 const std::string kExisting[] = { 708 keys::kNameEqualsKey, "custom-header-b", 709 keys::kValueEqualsKey, "valueB" 710 }; 711 const size_t kExistingSize[] = { arraysize(kExisting) }; 712 GetArrayAsVector(kExisting, kExistingSize, 1u, &tests); 713 MatchAndCheck(tests, keys::kExcludeResponseHeadersKey, stage, 714 url_request.get(), &result); 715 EXPECT_FALSE(result); 716 } 717 718 } // namespace 719 } // namespace extensions 720