Home | History | Annotate | Download | only in declarative_webrequest
      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