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 "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h" 6 7 #include <algorithm> 8 9 #include "base/lazy_instance.h" 10 #include "base/logging.h" 11 #include "base/strings/string_util.h" 12 #include "base/strings/stringprintf.h" 13 #include "base/values.h" 14 #include "chrome/browser/extensions/api/declarative/deduping_factory.h" 15 #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h" 16 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h" 17 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" 18 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" 19 #include "content/public/browser/resource_request_info.h" 20 #include "extensions/common/error_utils.h" 21 #include "net/base/net_errors.h" 22 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 23 #include "net/base/static_cookie_policy.h" 24 #include "net/http/http_request_headers.h" 25 #include "net/http/http_util.h" 26 #include "net/url_request/url_request.h" 27 28 using base::CaseInsensitiveCompareASCII; 29 using base::DictionaryValue; 30 using base::ListValue; 31 using base::StringValue; 32 using base::Value; 33 34 namespace helpers = extension_web_request_api_helpers; 35 namespace keys = extensions::declarative_webrequest_constants; 36 37 namespace extensions { 38 39 namespace { 40 // Error messages. 41 const char kUnknownConditionAttribute[] = "Unknown matching condition: '*'"; 42 const char kInvalidValue[] = "Condition '*' has an invalid value"; 43 44 struct WebRequestConditionAttributeFactory { 45 DedupingFactory<WebRequestConditionAttribute> factory; 46 47 WebRequestConditionAttributeFactory() : factory(5) { 48 factory.RegisterFactoryMethod( 49 keys::kResourceTypeKey, 50 DedupingFactory<WebRequestConditionAttribute>::IS_PARAMETERIZED, 51 &WebRequestConditionAttributeResourceType::Create); 52 53 factory.RegisterFactoryMethod( 54 keys::kContentTypeKey, 55 DedupingFactory<WebRequestConditionAttribute>::IS_PARAMETERIZED, 56 &WebRequestConditionAttributeContentType::Create); 57 factory.RegisterFactoryMethod( 58 keys::kExcludeContentTypeKey, 59 DedupingFactory<WebRequestConditionAttribute>::IS_PARAMETERIZED, 60 &WebRequestConditionAttributeContentType::Create); 61 62 factory.RegisterFactoryMethod( 63 keys::kRequestHeadersKey, 64 DedupingFactory<WebRequestConditionAttribute>::IS_PARAMETERIZED, 65 &WebRequestConditionAttributeRequestHeaders::Create); 66 factory.RegisterFactoryMethod( 67 keys::kExcludeRequestHeadersKey, 68 DedupingFactory<WebRequestConditionAttribute>::IS_PARAMETERIZED, 69 &WebRequestConditionAttributeRequestHeaders::Create); 70 71 factory.RegisterFactoryMethod( 72 keys::kResponseHeadersKey, 73 DedupingFactory<WebRequestConditionAttribute>::IS_PARAMETERIZED, 74 &WebRequestConditionAttributeResponseHeaders::Create); 75 factory.RegisterFactoryMethod( 76 keys::kExcludeResponseHeadersKey, 77 DedupingFactory<WebRequestConditionAttribute>::IS_PARAMETERIZED, 78 &WebRequestConditionAttributeResponseHeaders::Create); 79 80 factory.RegisterFactoryMethod( 81 keys::kThirdPartyKey, 82 DedupingFactory<WebRequestConditionAttribute>::IS_PARAMETERIZED, 83 &WebRequestConditionAttributeThirdParty::Create); 84 85 factory.RegisterFactoryMethod( 86 keys::kStagesKey, 87 DedupingFactory<WebRequestConditionAttribute>::IS_PARAMETERIZED, 88 &WebRequestConditionAttributeStages::Create); 89 } 90 }; 91 92 base::LazyInstance<WebRequestConditionAttributeFactory>::Leaky 93 g_web_request_condition_attribute_factory = LAZY_INSTANCE_INITIALIZER; 94 95 } // namespace 96 97 // 98 // WebRequestConditionAttribute 99 // 100 101 WebRequestConditionAttribute::WebRequestConditionAttribute() {} 102 103 WebRequestConditionAttribute::~WebRequestConditionAttribute() {} 104 105 bool WebRequestConditionAttribute::Equals( 106 const WebRequestConditionAttribute* other) const { 107 return GetType() == other->GetType(); 108 } 109 110 // static 111 scoped_refptr<const WebRequestConditionAttribute> 112 WebRequestConditionAttribute::Create( 113 const std::string& name, 114 const base::Value* value, 115 std::string* error) { 116 CHECK(value != NULL && error != NULL); 117 bool bad_message = false; 118 return g_web_request_condition_attribute_factory.Get().factory.Instantiate( 119 name, value, error, &bad_message); 120 } 121 122 // 123 // WebRequestConditionAttributeResourceType 124 // 125 126 WebRequestConditionAttributeResourceType:: 127 WebRequestConditionAttributeResourceType( 128 const std::vector<ResourceType::Type>& types) 129 : types_(types) {} 130 131 WebRequestConditionAttributeResourceType:: 132 ~WebRequestConditionAttributeResourceType() {} 133 134 // static 135 scoped_refptr<const WebRequestConditionAttribute> 136 WebRequestConditionAttributeResourceType::Create( 137 const std::string& instance_type, 138 const base::Value* value, 139 std::string* error, 140 bool* bad_message) { 141 DCHECK(instance_type == keys::kResourceTypeKey); 142 const ListValue* value_as_list = NULL; 143 if (!value->GetAsList(&value_as_list)) { 144 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, 145 keys::kResourceTypeKey); 146 return scoped_refptr<const WebRequestConditionAttribute>(NULL); 147 } 148 149 size_t number_types = value_as_list->GetSize(); 150 151 std::vector<ResourceType::Type> passed_types; 152 passed_types.reserve(number_types); 153 for (size_t i = 0; i < number_types; ++i) { 154 std::string resource_type_string; 155 ResourceType::Type type = ResourceType::LAST_TYPE; 156 if (!value_as_list->GetString(i, &resource_type_string) || 157 !helpers::ParseResourceType(resource_type_string, &type)) { 158 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, 159 keys::kResourceTypeKey); 160 return scoped_refptr<const WebRequestConditionAttribute>(NULL); 161 } 162 passed_types.push_back(type); 163 } 164 165 return scoped_refptr<const WebRequestConditionAttribute>( 166 new WebRequestConditionAttributeResourceType(passed_types)); 167 } 168 169 int WebRequestConditionAttributeResourceType::GetStages() const { 170 return ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS | ON_SEND_HEADERS | 171 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED | ON_BEFORE_REDIRECT | 172 ON_RESPONSE_STARTED | ON_COMPLETED | ON_ERROR; 173 } 174 175 bool WebRequestConditionAttributeResourceType::IsFulfilled( 176 const WebRequestData& request_data) const { 177 if (!(request_data.stage & GetStages())) 178 return false; 179 const content::ResourceRequestInfo* info = 180 content::ResourceRequestInfo::ForRequest(request_data.request); 181 if (!info) 182 return false; 183 return std::find(types_.begin(), types_.end(), info->GetResourceType()) != 184 types_.end(); 185 } 186 187 WebRequestConditionAttribute::Type 188 WebRequestConditionAttributeResourceType::GetType() const { 189 return CONDITION_RESOURCE_TYPE; 190 } 191 192 std::string WebRequestConditionAttributeResourceType::GetName() const { 193 return keys::kResourceTypeKey; 194 } 195 196 bool WebRequestConditionAttributeResourceType::Equals( 197 const WebRequestConditionAttribute* other) const { 198 if (!WebRequestConditionAttribute::Equals(other)) 199 return false; 200 const WebRequestConditionAttributeResourceType* casted_other = 201 static_cast<const WebRequestConditionAttributeResourceType*>(other); 202 return types_ == casted_other->types_; 203 } 204 205 // 206 // WebRequestConditionAttributeContentType 207 // 208 209 WebRequestConditionAttributeContentType:: 210 WebRequestConditionAttributeContentType( 211 const std::vector<std::string>& content_types, 212 bool inclusive) 213 : content_types_(content_types), 214 inclusive_(inclusive) {} 215 216 WebRequestConditionAttributeContentType:: 217 ~WebRequestConditionAttributeContentType() {} 218 219 // static 220 scoped_refptr<const WebRequestConditionAttribute> 221 WebRequestConditionAttributeContentType::Create( 222 const std::string& name, 223 const base::Value* value, 224 std::string* error, 225 bool* bad_message) { 226 DCHECK(name == keys::kContentTypeKey || name == keys::kExcludeContentTypeKey); 227 228 const ListValue* value_as_list = NULL; 229 if (!value->GetAsList(&value_as_list)) { 230 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name); 231 return scoped_refptr<const WebRequestConditionAttribute>(NULL); 232 } 233 std::vector<std::string> content_types; 234 for (ListValue::const_iterator it = value_as_list->begin(); 235 it != value_as_list->end(); ++it) { 236 std::string content_type; 237 if (!(*it)->GetAsString(&content_type)) { 238 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name); 239 return scoped_refptr<const WebRequestConditionAttribute>(NULL); 240 } 241 content_types.push_back(content_type); 242 } 243 244 return scoped_refptr<const WebRequestConditionAttribute>( 245 new WebRequestConditionAttributeContentType( 246 content_types, name == keys::kContentTypeKey)); 247 } 248 249 int WebRequestConditionAttributeContentType::GetStages() const { 250 return ON_HEADERS_RECEIVED; 251 } 252 253 bool WebRequestConditionAttributeContentType::IsFulfilled( 254 const WebRequestData& request_data) const { 255 if (!(request_data.stage & GetStages())) 256 return false; 257 std::string content_type; 258 request_data.original_response_headers->GetNormalizedHeader( 259 net::HttpRequestHeaders::kContentType, &content_type); 260 std::string mime_type; 261 std::string charset; 262 bool had_charset = false; 263 net::HttpUtil::ParseContentType( 264 content_type, &mime_type, &charset, &had_charset, NULL); 265 266 if (inclusive_) { 267 return std::find(content_types_.begin(), content_types_.end(), 268 mime_type) != content_types_.end(); 269 } else { 270 return std::find(content_types_.begin(), content_types_.end(), 271 mime_type) == content_types_.end(); 272 } 273 } 274 275 WebRequestConditionAttribute::Type 276 WebRequestConditionAttributeContentType::GetType() const { 277 return CONDITION_CONTENT_TYPE; 278 } 279 280 std::string WebRequestConditionAttributeContentType::GetName() const { 281 return (inclusive_ ? keys::kContentTypeKey : keys::kExcludeContentTypeKey); 282 } 283 284 bool WebRequestConditionAttributeContentType::Equals( 285 const WebRequestConditionAttribute* other) const { 286 if (!WebRequestConditionAttribute::Equals(other)) 287 return false; 288 const WebRequestConditionAttributeContentType* casted_other = 289 static_cast<const WebRequestConditionAttributeContentType*>(other); 290 return content_types_ == casted_other->content_types_ && 291 inclusive_ == casted_other->inclusive_; 292 } 293 294 // Manages a set of tests to be applied to name-value pairs representing 295 // headers. This is a helper class to header-related condition attributes. 296 // It contains a set of test groups. A name-value pair satisfies the whole 297 // set of test groups iff it passes at least one test group. 298 class HeaderMatcher { 299 public: 300 ~HeaderMatcher(); 301 302 // Creates an instance based on a list |tests| of test groups, encoded as 303 // dictionaries of the type declarativeWebRequest.HeaderFilter (see 304 // declarative_web_request.json). 305 static scoped_ptr<const HeaderMatcher> Create(const base::ListValue* tests); 306 307 // Does |this| match the header "|name|: |value|"? 308 bool TestNameValue(const std::string& name, const std::string& value) const; 309 310 private: 311 // Represents a single string-matching test. 312 class StringMatchTest { 313 public: 314 enum MatchType { kPrefix, kSuffix, kEquals, kContains }; 315 316 // |data| is the pattern to be matched in the position given by |type|. 317 // Note that |data| must point to a StringValue object. 318 static scoped_ptr<StringMatchTest> Create(const Value* data, 319 MatchType type, 320 bool case_sensitive); 321 ~StringMatchTest(); 322 323 // Does |str| pass |this| StringMatchTest? 324 bool Matches(const std::string& str) const; 325 326 private: 327 StringMatchTest(const std::string& data, 328 MatchType type, 329 bool case_sensitive); 330 331 const std::string data_; 332 const MatchType type_; 333 const bool case_sensitive_; 334 DISALLOW_COPY_AND_ASSIGN(StringMatchTest); 335 }; 336 337 // Represents a test group -- a set of string matching tests to be applied to 338 // both the header name and value. 339 class HeaderMatchTest { 340 public: 341 ~HeaderMatchTest(); 342 343 // Gets the test group description in |tests| and creates the corresponding 344 // HeaderMatchTest. On failure returns NULL. 345 static scoped_ptr<const HeaderMatchTest> Create( 346 const base::DictionaryValue* tests); 347 348 // Does the header "|name|: |value|" match all tests in |this|? 349 bool Matches(const std::string& name, const std::string& value) const; 350 351 private: 352 // Takes ownership of the content of both |name_match| and |value_match|. 353 HeaderMatchTest(ScopedVector<const StringMatchTest>* name_match, 354 ScopedVector<const StringMatchTest>* value_match); 355 356 // Tests to be passed by a header's name. 357 const ScopedVector<const StringMatchTest> name_match_; 358 // Tests to be passed by a header's value. 359 const ScopedVector<const StringMatchTest> value_match_; 360 DISALLOW_COPY_AND_ASSIGN(HeaderMatchTest); 361 }; 362 363 explicit HeaderMatcher(ScopedVector<const HeaderMatchTest>* tests); 364 365 const ScopedVector<const HeaderMatchTest> tests_; 366 367 DISALLOW_COPY_AND_ASSIGN(HeaderMatcher); 368 }; 369 370 // HeaderMatcher implementation. 371 372 HeaderMatcher::~HeaderMatcher() {} 373 374 // static 375 scoped_ptr<const HeaderMatcher> HeaderMatcher::Create( 376 const base::ListValue* tests) { 377 ScopedVector<const HeaderMatchTest> header_tests; 378 for (ListValue::const_iterator it = tests->begin(); 379 it != tests->end(); ++it) { 380 const DictionaryValue* tests = NULL; 381 if (!(*it)->GetAsDictionary(&tests)) 382 return scoped_ptr<const HeaderMatcher>(); 383 384 scoped_ptr<const HeaderMatchTest> header_test( 385 HeaderMatchTest::Create(tests)); 386 if (header_test.get() == NULL) 387 return scoped_ptr<const HeaderMatcher>(); 388 header_tests.push_back(header_test.release()); 389 } 390 391 return scoped_ptr<const HeaderMatcher>(new HeaderMatcher(&header_tests)); 392 } 393 394 bool HeaderMatcher::TestNameValue(const std::string& name, 395 const std::string& value) const { 396 for (size_t i = 0; i < tests_.size(); ++i) { 397 if (tests_[i]->Matches(name, value)) 398 return true; 399 } 400 return false; 401 } 402 403 HeaderMatcher::HeaderMatcher(ScopedVector<const HeaderMatchTest>* tests) 404 : tests_(tests->Pass()) {} 405 406 // HeaderMatcher::StringMatchTest implementation. 407 408 // static 409 scoped_ptr<HeaderMatcher::StringMatchTest> 410 HeaderMatcher::StringMatchTest::Create(const Value* data, 411 MatchType type, 412 bool case_sensitive) { 413 std::string str; 414 CHECK(data->GetAsString(&str)); 415 return scoped_ptr<StringMatchTest>( 416 new StringMatchTest(str, type, case_sensitive)); 417 } 418 419 HeaderMatcher::StringMatchTest::~StringMatchTest() {} 420 421 bool HeaderMatcher::StringMatchTest::Matches( 422 const std::string& str) const { 423 switch (type_) { 424 case kPrefix: 425 return StartsWithASCII(str, data_, case_sensitive_); 426 case kSuffix: 427 return EndsWith(str, data_, case_sensitive_); 428 case kEquals: 429 return str.size() == data_.size() && 430 StartsWithASCII(str, data_, case_sensitive_); 431 case kContains: 432 if (!case_sensitive_) { 433 return std::search(str.begin(), str.end(), data_.begin(), data_.end(), 434 CaseInsensitiveCompareASCII<char>()) != str.end(); 435 } else { 436 return str.find(data_) != std::string::npos; 437 } 438 } 439 // We never get past the "switch", but the compiler worries about no return. 440 NOTREACHED(); 441 return false; 442 } 443 444 HeaderMatcher::StringMatchTest::StringMatchTest(const std::string& data, 445 MatchType type, 446 bool case_sensitive) 447 : data_(data), 448 type_(type), 449 case_sensitive_(case_sensitive) {} 450 451 // HeaderMatcher::HeaderMatchTest implementation. 452 453 HeaderMatcher::HeaderMatchTest::HeaderMatchTest( 454 ScopedVector<const StringMatchTest>* name_match, 455 ScopedVector<const StringMatchTest>* value_match) 456 : name_match_(name_match->Pass()), 457 value_match_(value_match->Pass()) {} 458 459 HeaderMatcher::HeaderMatchTest::~HeaderMatchTest() {} 460 461 // static 462 scoped_ptr<const HeaderMatcher::HeaderMatchTest> 463 HeaderMatcher::HeaderMatchTest::Create(const base::DictionaryValue* tests) { 464 ScopedVector<const StringMatchTest> name_match; 465 ScopedVector<const StringMatchTest> value_match; 466 467 for (DictionaryValue::Iterator it(*tests); !it.IsAtEnd(); it.Advance()) { 468 bool is_name = false; // Is this test for header name? 469 StringMatchTest::MatchType match_type; 470 if (it.key() == keys::kNamePrefixKey) { 471 is_name = true; 472 match_type = StringMatchTest::kPrefix; 473 } else if (it.key() == keys::kNameSuffixKey) { 474 is_name = true; 475 match_type = StringMatchTest::kSuffix; 476 } else if (it.key() == keys::kNameContainsKey) { 477 is_name = true; 478 match_type = StringMatchTest::kContains; 479 } else if (it.key() == keys::kNameEqualsKey) { 480 is_name = true; 481 match_type = StringMatchTest::kEquals; 482 } else if (it.key() == keys::kValuePrefixKey) { 483 match_type = StringMatchTest::kPrefix; 484 } else if (it.key() == keys::kValueSuffixKey) { 485 match_type = StringMatchTest::kSuffix; 486 } else if (it.key() == keys::kValueContainsKey) { 487 match_type = StringMatchTest::kContains; 488 } else if (it.key() == keys::kValueEqualsKey) { 489 match_type = StringMatchTest::kEquals; 490 } else { 491 NOTREACHED(); // JSON schema type checking should prevent this. 492 return scoped_ptr<const HeaderMatchTest>(); 493 } 494 const Value* content = &it.value(); 495 496 ScopedVector<const StringMatchTest>* tests = 497 is_name ? &name_match : &value_match; 498 switch (content->GetType()) { 499 case Value::TYPE_LIST: { 500 const ListValue* list = NULL; 501 CHECK(content->GetAsList(&list)); 502 for (ListValue::const_iterator it = list->begin(); 503 it != list->end(); ++it) { 504 tests->push_back( 505 StringMatchTest::Create(*it, match_type, !is_name).release()); 506 } 507 break; 508 } 509 case Value::TYPE_STRING: { 510 tests->push_back( 511 StringMatchTest::Create(content, match_type, !is_name).release()); 512 break; 513 } 514 default: { 515 NOTREACHED(); // JSON schema type checking should prevent this. 516 return scoped_ptr<const HeaderMatchTest>(); 517 } 518 } 519 } 520 521 return scoped_ptr<const HeaderMatchTest>( 522 new HeaderMatchTest(&name_match, &value_match)); 523 } 524 525 bool HeaderMatcher::HeaderMatchTest::Matches(const std::string& name, 526 const std::string& value) const { 527 for (size_t i = 0; i < name_match_.size(); ++i) { 528 if (!name_match_[i]->Matches(name)) 529 return false; 530 } 531 532 for (size_t i = 0; i < value_match_.size(); ++i) { 533 if (!value_match_[i]->Matches(value)) 534 return false; 535 } 536 537 return true; 538 } 539 540 // 541 // WebRequestConditionAttributeRequestHeaders 542 // 543 544 WebRequestConditionAttributeRequestHeaders:: 545 WebRequestConditionAttributeRequestHeaders( 546 scoped_ptr<const HeaderMatcher> header_matcher, 547 bool positive) 548 : header_matcher_(header_matcher.Pass()), 549 positive_(positive) {} 550 551 WebRequestConditionAttributeRequestHeaders:: 552 ~WebRequestConditionAttributeRequestHeaders() {} 553 554 namespace { 555 556 scoped_ptr<const HeaderMatcher> PrepareHeaderMatcher( 557 const std::string& name, 558 const base::Value* value, 559 std::string* error) { 560 const ListValue* value_as_list = NULL; 561 if (!value->GetAsList(&value_as_list)) { 562 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name); 563 return scoped_ptr<const HeaderMatcher>(); 564 } 565 566 scoped_ptr<const HeaderMatcher> header_matcher( 567 HeaderMatcher::Create(value_as_list)); 568 if (header_matcher.get() == NULL) 569 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name); 570 return header_matcher.Pass(); 571 } 572 573 } // namespace 574 575 // static 576 scoped_refptr<const WebRequestConditionAttribute> 577 WebRequestConditionAttributeRequestHeaders::Create( 578 const std::string& name, 579 const base::Value* value, 580 std::string* error, 581 bool* bad_message) { 582 DCHECK(name == keys::kRequestHeadersKey || 583 name == keys::kExcludeRequestHeadersKey); 584 585 scoped_ptr<const HeaderMatcher> header_matcher( 586 PrepareHeaderMatcher(name, value, error)); 587 if (header_matcher.get() == NULL) 588 return scoped_refptr<const WebRequestConditionAttribute>(NULL); 589 590 return scoped_refptr<const WebRequestConditionAttribute>( 591 new WebRequestConditionAttributeRequestHeaders( 592 header_matcher.Pass(), name == keys::kRequestHeadersKey)); 593 } 594 595 int WebRequestConditionAttributeRequestHeaders::GetStages() const { 596 // Currently we only allow matching against headers in the before-send-headers 597 // stage. The headers are accessible in other stages as well, but before 598 // allowing to match against them in further stages, we should consider 599 // caching the match result. 600 return ON_BEFORE_SEND_HEADERS; 601 } 602 603 bool WebRequestConditionAttributeRequestHeaders::IsFulfilled( 604 const WebRequestData& request_data) const { 605 if (!(request_data.stage & GetStages())) 606 return false; 607 608 const net::HttpRequestHeaders& headers = 609 request_data.request->extra_request_headers(); 610 611 bool passed = false; // Did some header pass TestNameValue? 612 net::HttpRequestHeaders::Iterator it(headers); 613 while (!passed && it.GetNext()) 614 passed |= header_matcher_->TestNameValue(it.name(), it.value()); 615 616 return (positive_ ? passed : !passed); 617 } 618 619 WebRequestConditionAttribute::Type 620 WebRequestConditionAttributeRequestHeaders::GetType() const { 621 return CONDITION_REQUEST_HEADERS; 622 } 623 624 std::string WebRequestConditionAttributeRequestHeaders::GetName() const { 625 return (positive_ ? keys::kRequestHeadersKey 626 : keys::kExcludeRequestHeadersKey); 627 } 628 629 bool WebRequestConditionAttributeRequestHeaders::Equals( 630 const WebRequestConditionAttribute* other) const { 631 // Comparing headers is too heavy, so we skip it entirely. 632 return false; 633 } 634 635 // 636 // WebRequestConditionAttributeResponseHeaders 637 // 638 639 WebRequestConditionAttributeResponseHeaders:: 640 WebRequestConditionAttributeResponseHeaders( 641 scoped_ptr<const HeaderMatcher> header_matcher, 642 bool positive) 643 : header_matcher_(header_matcher.Pass()), 644 positive_(positive) {} 645 646 WebRequestConditionAttributeResponseHeaders:: 647 ~WebRequestConditionAttributeResponseHeaders() {} 648 649 // static 650 scoped_refptr<const WebRequestConditionAttribute> 651 WebRequestConditionAttributeResponseHeaders::Create( 652 const std::string& name, 653 const base::Value* value, 654 std::string* error, 655 bool* bad_message) { 656 DCHECK(name == keys::kResponseHeadersKey || 657 name == keys::kExcludeResponseHeadersKey); 658 659 scoped_ptr<const HeaderMatcher> header_matcher( 660 PrepareHeaderMatcher(name, value, error)); 661 if (header_matcher.get() == NULL) 662 return scoped_refptr<const WebRequestConditionAttribute>(NULL); 663 664 return scoped_refptr<const WebRequestConditionAttribute>( 665 new WebRequestConditionAttributeResponseHeaders( 666 header_matcher.Pass(), name == keys::kResponseHeadersKey)); 667 } 668 669 int WebRequestConditionAttributeResponseHeaders::GetStages() const { 670 return ON_HEADERS_RECEIVED; 671 } 672 673 bool WebRequestConditionAttributeResponseHeaders::IsFulfilled( 674 const WebRequestData& request_data) const { 675 if (!(request_data.stage & GetStages())) 676 return false; 677 678 const net::HttpResponseHeaders* headers = 679 request_data.original_response_headers; 680 if (headers == NULL) { 681 // Each header of an empty set satisfies (the negation of) everything; 682 // OTOH, there is no header to satisfy even the most permissive test. 683 return !positive_; 684 } 685 686 bool passed = false; // Did some header pass TestNameValue? 687 std::string name; 688 std::string value; 689 void* iter = NULL; 690 while (!passed && headers->EnumerateHeaderLines(&iter, &name, &value)) { 691 passed |= header_matcher_->TestNameValue(name, value); 692 } 693 694 return (positive_ ? passed : !passed); 695 } 696 697 WebRequestConditionAttribute::Type 698 WebRequestConditionAttributeResponseHeaders::GetType() const { 699 return CONDITION_RESPONSE_HEADERS; 700 } 701 702 std::string WebRequestConditionAttributeResponseHeaders::GetName() const { 703 return (positive_ ? keys::kResponseHeadersKey 704 : keys::kExcludeResponseHeadersKey); 705 } 706 707 bool WebRequestConditionAttributeResponseHeaders::Equals( 708 const WebRequestConditionAttribute* other) const { 709 return false; 710 } 711 712 // 713 // WebRequestConditionAttributeThirdParty 714 // 715 716 WebRequestConditionAttributeThirdParty:: 717 WebRequestConditionAttributeThirdParty(bool match_third_party) 718 : match_third_party_(match_third_party) {} 719 720 WebRequestConditionAttributeThirdParty:: 721 ~WebRequestConditionAttributeThirdParty() {} 722 723 // static 724 scoped_refptr<const WebRequestConditionAttribute> 725 WebRequestConditionAttributeThirdParty::Create( 726 const std::string& name, 727 const base::Value* value, 728 std::string* error, 729 bool* bad_message) { 730 DCHECK(name == keys::kThirdPartyKey); 731 732 bool third_party = false; // Dummy value, gets overwritten. 733 if (!value->GetAsBoolean(&third_party)) { 734 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, 735 keys::kThirdPartyKey); 736 return scoped_refptr<const WebRequestConditionAttribute>(NULL); 737 } 738 739 return scoped_refptr<const WebRequestConditionAttribute>( 740 new WebRequestConditionAttributeThirdParty(third_party)); 741 } 742 743 int WebRequestConditionAttributeThirdParty::GetStages() const { 744 return ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS | ON_SEND_HEADERS | 745 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED | ON_BEFORE_REDIRECT | 746 ON_RESPONSE_STARTED | ON_COMPLETED | ON_ERROR; 747 } 748 749 bool WebRequestConditionAttributeThirdParty::IsFulfilled( 750 const WebRequestData& request_data) const { 751 if (!(request_data.stage & GetStages())) 752 return false; 753 754 // Request is "1st party" if it gets cookies under 3rd party-blocking policy. 755 const net::StaticCookiePolicy block_third_party_policy( 756 net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES); 757 const int can_get_cookies = block_third_party_policy.CanGetCookies( 758 request_data.request->url(), 759 request_data.request->first_party_for_cookies()); 760 const bool is_first_party = (can_get_cookies == net::OK); 761 762 return match_third_party_ ? !is_first_party : is_first_party; 763 } 764 765 WebRequestConditionAttribute::Type 766 WebRequestConditionAttributeThirdParty::GetType() const { 767 return CONDITION_THIRD_PARTY; 768 } 769 770 std::string WebRequestConditionAttributeThirdParty::GetName() const { 771 return keys::kThirdPartyKey; 772 } 773 774 bool WebRequestConditionAttributeThirdParty::Equals( 775 const WebRequestConditionAttribute* other) const { 776 if (!WebRequestConditionAttribute::Equals(other)) 777 return false; 778 const WebRequestConditionAttributeThirdParty* casted_other = 779 static_cast<const WebRequestConditionAttributeThirdParty*>(other); 780 return match_third_party_ == casted_other->match_third_party_; 781 } 782 783 // 784 // WebRequestConditionAttributeStages 785 // 786 787 WebRequestConditionAttributeStages:: 788 WebRequestConditionAttributeStages(int allowed_stages) 789 : allowed_stages_(allowed_stages) {} 790 791 WebRequestConditionAttributeStages:: 792 ~WebRequestConditionAttributeStages() {} 793 794 namespace { 795 796 // Reads strings stored in |value|, which is expected to be a ListValue, and 797 // sets corresponding bits (see RequestStage) in |out_stages|. Returns true on 798 // success, false otherwise. 799 bool ParseListOfStages(const Value& value, int* out_stages) { 800 const ListValue* list = NULL; 801 if (!value.GetAsList(&list)) 802 return false; 803 804 int stages = 0; 805 std::string stage_name; 806 for (ListValue::const_iterator it = list->begin(); it != list->end(); ++it) { 807 if (!((*it)->GetAsString(&stage_name))) 808 return false; 809 if (stage_name == keys::kOnBeforeRequestEnum) { 810 stages |= ON_BEFORE_REQUEST; 811 } else if (stage_name == keys::kOnBeforeSendHeadersEnum) { 812 stages |= ON_BEFORE_SEND_HEADERS; 813 } else if (stage_name == keys::kOnHeadersReceivedEnum) { 814 stages |= ON_HEADERS_RECEIVED; 815 } else if (stage_name == keys::kOnAuthRequiredEnum) { 816 stages |= ON_AUTH_REQUIRED; 817 } else { 818 NOTREACHED(); // JSON schema checks prevent getting here. 819 return false; 820 } 821 } 822 823 *out_stages = stages; 824 return true; 825 } 826 827 } // namespace 828 829 // static 830 scoped_refptr<const WebRequestConditionAttribute> 831 WebRequestConditionAttributeStages::Create(const std::string& name, 832 const Value* value, 833 std::string* error, 834 bool* bad_message) { 835 DCHECK(name == keys::kStagesKey); 836 837 int allowed_stages = 0; 838 if (!ParseListOfStages(*value, &allowed_stages)) { 839 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, 840 keys::kStagesKey); 841 return scoped_refptr<const WebRequestConditionAttribute>(NULL); 842 } 843 844 return scoped_refptr<const WebRequestConditionAttribute>( 845 new WebRequestConditionAttributeStages(allowed_stages)); 846 } 847 848 int WebRequestConditionAttributeStages::GetStages() const { 849 return allowed_stages_; 850 } 851 852 bool WebRequestConditionAttributeStages::IsFulfilled( 853 const WebRequestData& request_data) const { 854 // Note: removing '!=' triggers warning C4800 on the VS compiler. 855 return (request_data.stage & GetStages()) != 0; 856 } 857 858 WebRequestConditionAttribute::Type 859 WebRequestConditionAttributeStages::GetType() const { 860 return CONDITION_STAGES; 861 } 862 863 std::string WebRequestConditionAttributeStages::GetName() const { 864 return keys::kStagesKey; 865 } 866 867 bool WebRequestConditionAttributeStages::Equals( 868 const WebRequestConditionAttribute* other) const { 869 if (!WebRequestConditionAttribute::Equals(other)) 870 return false; 871 const WebRequestConditionAttributeStages* casted_other = 872 static_cast<const WebRequestConditionAttributeStages*>(other); 873 return allowed_stages_ == casted_other->allowed_stages_; 874 } 875 876 } // namespace extensions 877