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