Add ICU message format support
[chromium-blink-merge.git] / extensions / browser / api / declarative_webrequest / webrequest_condition_attribute.cc
blob430a05c1bf195207c2ffee64091a66d641725c2c
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.
5 #include "extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.h"
7 #include <algorithm>
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 "content/public/browser/resource_request_info.h"
15 #include "extensions/browser/api/declarative/deduping_factory.h"
16 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
17 #include "extensions/browser/api/declarative_webrequest/webrequest_condition.h"
18 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
19 #include "extensions/browser/api/web_request/web_request_api_helpers.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"
28 using base::CaseInsensitiveCompareASCII;
29 using base::DictionaryValue;
30 using base::ListValue;
31 using base::StringValue;
32 using base::Value;
33 using content::ResourceType;
35 namespace helpers = extension_web_request_api_helpers;
36 namespace keys = extensions::declarative_webrequest_constants;
38 namespace extensions {
40 namespace {
41 // Error messages.
42 const char kInvalidValue[] = "Condition '*' has an invalid value";
44 struct WebRequestConditionAttributeFactory {
45 DedupingFactory<WebRequestConditionAttribute> factory;
47 WebRequestConditionAttributeFactory() : factory(5) {
48 factory.RegisterFactoryMethod(
49 keys::kResourceTypeKey,
50 DedupingFactory<WebRequestConditionAttribute>::IS_PARAMETERIZED,
51 &WebRequestConditionAttributeResourceType::Create);
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);
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);
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);
80 factory.RegisterFactoryMethod(
81 keys::kThirdPartyKey,
82 DedupingFactory<WebRequestConditionAttribute>::IS_PARAMETERIZED,
83 &WebRequestConditionAttributeThirdParty::Create);
85 factory.RegisterFactoryMethod(
86 keys::kStagesKey,
87 DedupingFactory<WebRequestConditionAttribute>::IS_PARAMETERIZED,
88 &WebRequestConditionAttributeStages::Create);
92 base::LazyInstance<WebRequestConditionAttributeFactory>::Leaky
93 g_web_request_condition_attribute_factory = LAZY_INSTANCE_INITIALIZER;
95 } // namespace
98 // WebRequestConditionAttribute
101 WebRequestConditionAttribute::WebRequestConditionAttribute() {}
103 WebRequestConditionAttribute::~WebRequestConditionAttribute() {}
105 bool WebRequestConditionAttribute::Equals(
106 const WebRequestConditionAttribute* other) const {
107 return GetType() == other->GetType();
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);
123 // WebRequestConditionAttributeResourceType
126 WebRequestConditionAttributeResourceType::
127 WebRequestConditionAttributeResourceType(
128 const std::vector<ResourceType>& types)
129 : types_(types) {}
131 WebRequestConditionAttributeResourceType::
132 ~WebRequestConditionAttributeResourceType() {}
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 base::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);
149 size_t number_types = value_as_list->GetSize();
151 std::vector<ResourceType> 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 = content::RESOURCE_TYPE_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);
162 passed_types.push_back(type);
165 return scoped_refptr<const WebRequestConditionAttribute>(
166 new WebRequestConditionAttributeResourceType(passed_types));
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;
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();
187 WebRequestConditionAttribute::Type
188 WebRequestConditionAttributeResourceType::GetType() const {
189 return CONDITION_RESOURCE_TYPE;
192 std::string WebRequestConditionAttributeResourceType::GetName() const {
193 return keys::kResourceTypeKey;
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_;
206 // WebRequestConditionAttributeContentType
209 WebRequestConditionAttributeContentType::
210 WebRequestConditionAttributeContentType(
211 const std::vector<std::string>& content_types,
212 bool inclusive)
213 : content_types_(content_types),
214 inclusive_(inclusive) {}
216 WebRequestConditionAttributeContentType::
217 ~WebRequestConditionAttributeContentType() {}
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);
228 const base::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);
233 std::vector<std::string> content_types;
234 for (base::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);
241 content_types.push_back(content_type);
244 return scoped_refptr<const WebRequestConditionAttribute>(
245 new WebRequestConditionAttributeContentType(
246 content_types, name == keys::kContentTypeKey));
249 int WebRequestConditionAttributeContentType::GetStages() const {
250 return ON_HEADERS_RECEIVED;
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);
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();
275 WebRequestConditionAttribute::Type
276 WebRequestConditionAttributeContentType::GetType() const {
277 return CONDITION_CONTENT_TYPE;
280 std::string WebRequestConditionAttributeContentType::GetName() const {
281 return (inclusive_ ? keys::kContentTypeKey : keys::kExcludeContentTypeKey);
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_;
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();
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);
307 // Does |this| match the header "|name|: |value|"?
308 bool TestNameValue(const std::string& name, const std::string& value) const;
310 private:
311 // Represents a single string-matching test.
312 class StringMatchTest {
313 public:
314 enum MatchType { kPrefix, kSuffix, kEquals, kContains };
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 base::Value* data,
319 MatchType type,
320 bool case_sensitive);
321 ~StringMatchTest();
323 // Does |str| pass |this| StringMatchTest?
324 bool Matches(const std::string& str) const;
326 private:
327 StringMatchTest(const std::string& data,
328 MatchType type,
329 bool case_sensitive);
331 const std::string data_;
332 const MatchType type_;
333 const base::CompareCase case_sensitive_;
334 DISALLOW_COPY_AND_ASSIGN(StringMatchTest);
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();
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);
348 // Does the header "|name|: |value|" match all tests in |this|?
349 bool Matches(const std::string& name, const std::string& value) const;
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);
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);
363 explicit HeaderMatcher(ScopedVector<const HeaderMatchTest>* tests);
365 const ScopedVector<const HeaderMatchTest> tests_;
367 DISALLOW_COPY_AND_ASSIGN(HeaderMatcher);
370 // HeaderMatcher implementation.
372 HeaderMatcher::~HeaderMatcher() {}
374 // static
375 scoped_ptr<const HeaderMatcher> HeaderMatcher::Create(
376 const base::ListValue* tests) {
377 ScopedVector<const HeaderMatchTest> header_tests;
378 for (base::ListValue::const_iterator it = tests->begin();
379 it != tests->end(); ++it) {
380 const base::DictionaryValue* tests = NULL;
381 if (!(*it)->GetAsDictionary(&tests))
382 return scoped_ptr<const HeaderMatcher>();
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.Pass());
391 return scoped_ptr<const HeaderMatcher>(new HeaderMatcher(&header_tests));
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;
400 return false;
403 HeaderMatcher::HeaderMatcher(ScopedVector<const HeaderMatchTest>* tests)
404 : tests_(tests->Pass()) {}
406 // HeaderMatcher::StringMatchTest implementation.
408 // static
409 scoped_ptr<HeaderMatcher::StringMatchTest>
410 HeaderMatcher::StringMatchTest::Create(const base::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));
419 HeaderMatcher::StringMatchTest::~StringMatchTest() {}
421 bool HeaderMatcher::StringMatchTest::Matches(
422 const std::string& str) const {
423 switch (type_) {
424 case kPrefix:
425 return base::StartsWith(str, data_, case_sensitive_);
426 case kSuffix:
427 return base::EndsWith(str, data_, case_sensitive_);
428 case kEquals:
429 return str.size() == data_.size() &&
430 base::StartsWith(str, data_, case_sensitive_);
431 case kContains:
432 if (case_sensitive_ == base::CompareCase::INSENSITIVE_ASCII) {
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;
439 // We never get past the "switch", but the compiler worries about no return.
440 NOTREACHED();
441 return false;
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 ? base::CompareCase::SENSITIVE
450 : base::CompareCase::INSENSITIVE_ASCII) {}
452 // HeaderMatcher::HeaderMatchTest implementation.
454 HeaderMatcher::HeaderMatchTest::HeaderMatchTest(
455 ScopedVector<const StringMatchTest>* name_match,
456 ScopedVector<const StringMatchTest>* value_match)
457 : name_match_(name_match->Pass()),
458 value_match_(value_match->Pass()) {}
460 HeaderMatcher::HeaderMatchTest::~HeaderMatchTest() {}
462 // static
463 scoped_ptr<const HeaderMatcher::HeaderMatchTest>
464 HeaderMatcher::HeaderMatchTest::Create(const base::DictionaryValue* tests) {
465 ScopedVector<const StringMatchTest> name_match;
466 ScopedVector<const StringMatchTest> value_match;
468 for (base::DictionaryValue::Iterator it(*tests);
469 !it.IsAtEnd(); it.Advance()) {
470 bool is_name = false; // Is this test for header name?
471 StringMatchTest::MatchType match_type;
472 if (it.key() == keys::kNamePrefixKey) {
473 is_name = true;
474 match_type = StringMatchTest::kPrefix;
475 } else if (it.key() == keys::kNameSuffixKey) {
476 is_name = true;
477 match_type = StringMatchTest::kSuffix;
478 } else if (it.key() == keys::kNameContainsKey) {
479 is_name = true;
480 match_type = StringMatchTest::kContains;
481 } else if (it.key() == keys::kNameEqualsKey) {
482 is_name = true;
483 match_type = StringMatchTest::kEquals;
484 } else if (it.key() == keys::kValuePrefixKey) {
485 match_type = StringMatchTest::kPrefix;
486 } else if (it.key() == keys::kValueSuffixKey) {
487 match_type = StringMatchTest::kSuffix;
488 } else if (it.key() == keys::kValueContainsKey) {
489 match_type = StringMatchTest::kContains;
490 } else if (it.key() == keys::kValueEqualsKey) {
491 match_type = StringMatchTest::kEquals;
492 } else {
493 NOTREACHED(); // JSON schema type checking should prevent this.
494 return scoped_ptr<const HeaderMatchTest>();
496 const base::Value* content = &it.value();
498 ScopedVector<const StringMatchTest>* tests =
499 is_name ? &name_match : &value_match;
500 switch (content->GetType()) {
501 case base::Value::TYPE_LIST: {
502 const base::ListValue* list = NULL;
503 CHECK(content->GetAsList(&list));
504 for (base::ListValue::const_iterator it = list->begin();
505 it != list->end(); ++it) {
506 tests->push_back(
507 StringMatchTest::Create(*it, match_type, !is_name).release());
509 break;
511 case base::Value::TYPE_STRING: {
512 tests->push_back(
513 StringMatchTest::Create(content, match_type, !is_name).release());
514 break;
516 default: {
517 NOTREACHED(); // JSON schema type checking should prevent this.
518 return scoped_ptr<const HeaderMatchTest>();
523 return scoped_ptr<const HeaderMatchTest>(
524 new HeaderMatchTest(&name_match, &value_match));
527 bool HeaderMatcher::HeaderMatchTest::Matches(const std::string& name,
528 const std::string& value) const {
529 for (size_t i = 0; i < name_match_.size(); ++i) {
530 if (!name_match_[i]->Matches(name))
531 return false;
534 for (size_t i = 0; i < value_match_.size(); ++i) {
535 if (!value_match_[i]->Matches(value))
536 return false;
539 return true;
543 // WebRequestConditionAttributeRequestHeaders
546 WebRequestConditionAttributeRequestHeaders::
547 WebRequestConditionAttributeRequestHeaders(
548 scoped_ptr<const HeaderMatcher> header_matcher,
549 bool positive)
550 : header_matcher_(header_matcher.Pass()),
551 positive_(positive) {}
553 WebRequestConditionAttributeRequestHeaders::
554 ~WebRequestConditionAttributeRequestHeaders() {}
556 namespace {
558 scoped_ptr<const HeaderMatcher> PrepareHeaderMatcher(
559 const std::string& name,
560 const base::Value* value,
561 std::string* error) {
562 const base::ListValue* value_as_list = NULL;
563 if (!value->GetAsList(&value_as_list)) {
564 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name);
565 return scoped_ptr<const HeaderMatcher>();
568 scoped_ptr<const HeaderMatcher> header_matcher(
569 HeaderMatcher::Create(value_as_list));
570 if (header_matcher.get() == NULL)
571 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name);
572 return header_matcher.Pass();
575 } // namespace
577 // static
578 scoped_refptr<const WebRequestConditionAttribute>
579 WebRequestConditionAttributeRequestHeaders::Create(
580 const std::string& name,
581 const base::Value* value,
582 std::string* error,
583 bool* bad_message) {
584 DCHECK(name == keys::kRequestHeadersKey ||
585 name == keys::kExcludeRequestHeadersKey);
587 scoped_ptr<const HeaderMatcher> header_matcher(
588 PrepareHeaderMatcher(name, value, error));
589 if (header_matcher.get() == NULL)
590 return scoped_refptr<const WebRequestConditionAttribute>(NULL);
592 return scoped_refptr<const WebRequestConditionAttribute>(
593 new WebRequestConditionAttributeRequestHeaders(
594 header_matcher.Pass(), name == keys::kRequestHeadersKey));
597 int WebRequestConditionAttributeRequestHeaders::GetStages() const {
598 // Currently we only allow matching against headers in the before-send-headers
599 // stage. The headers are accessible in other stages as well, but before
600 // allowing to match against them in further stages, we should consider
601 // caching the match result.
602 return ON_BEFORE_SEND_HEADERS;
605 bool WebRequestConditionAttributeRequestHeaders::IsFulfilled(
606 const WebRequestData& request_data) const {
607 if (!(request_data.stage & GetStages()))
608 return false;
610 const net::HttpRequestHeaders& headers =
611 request_data.request->extra_request_headers();
613 bool passed = false; // Did some header pass TestNameValue?
614 net::HttpRequestHeaders::Iterator it(headers);
615 while (!passed && it.GetNext())
616 passed |= header_matcher_->TestNameValue(it.name(), it.value());
618 return (positive_ ? passed : !passed);
621 WebRequestConditionAttribute::Type
622 WebRequestConditionAttributeRequestHeaders::GetType() const {
623 return CONDITION_REQUEST_HEADERS;
626 std::string WebRequestConditionAttributeRequestHeaders::GetName() const {
627 return (positive_ ? keys::kRequestHeadersKey
628 : keys::kExcludeRequestHeadersKey);
631 bool WebRequestConditionAttributeRequestHeaders::Equals(
632 const WebRequestConditionAttribute* other) const {
633 // Comparing headers is too heavy, so we skip it entirely.
634 return false;
638 // WebRequestConditionAttributeResponseHeaders
641 WebRequestConditionAttributeResponseHeaders::
642 WebRequestConditionAttributeResponseHeaders(
643 scoped_ptr<const HeaderMatcher> header_matcher,
644 bool positive)
645 : header_matcher_(header_matcher.Pass()),
646 positive_(positive) {}
648 WebRequestConditionAttributeResponseHeaders::
649 ~WebRequestConditionAttributeResponseHeaders() {}
651 // static
652 scoped_refptr<const WebRequestConditionAttribute>
653 WebRequestConditionAttributeResponseHeaders::Create(
654 const std::string& name,
655 const base::Value* value,
656 std::string* error,
657 bool* bad_message) {
658 DCHECK(name == keys::kResponseHeadersKey ||
659 name == keys::kExcludeResponseHeadersKey);
661 scoped_ptr<const HeaderMatcher> header_matcher(
662 PrepareHeaderMatcher(name, value, error));
663 if (header_matcher.get() == NULL)
664 return scoped_refptr<const WebRequestConditionAttribute>(NULL);
666 return scoped_refptr<const WebRequestConditionAttribute>(
667 new WebRequestConditionAttributeResponseHeaders(
668 header_matcher.Pass(), name == keys::kResponseHeadersKey));
671 int WebRequestConditionAttributeResponseHeaders::GetStages() const {
672 return ON_HEADERS_RECEIVED;
675 bool WebRequestConditionAttributeResponseHeaders::IsFulfilled(
676 const WebRequestData& request_data) const {
677 if (!(request_data.stage & GetStages()))
678 return false;
680 const net::HttpResponseHeaders* headers =
681 request_data.original_response_headers;
682 if (headers == NULL) {
683 // Each header of an empty set satisfies (the negation of) everything;
684 // OTOH, there is no header to satisfy even the most permissive test.
685 return !positive_;
688 bool passed = false; // Did some header pass TestNameValue?
689 std::string name;
690 std::string value;
691 void* iter = NULL;
692 while (!passed && headers->EnumerateHeaderLines(&iter, &name, &value)) {
693 passed |= header_matcher_->TestNameValue(name, value);
696 return (positive_ ? passed : !passed);
699 WebRequestConditionAttribute::Type
700 WebRequestConditionAttributeResponseHeaders::GetType() const {
701 return CONDITION_RESPONSE_HEADERS;
704 std::string WebRequestConditionAttributeResponseHeaders::GetName() const {
705 return (positive_ ? keys::kResponseHeadersKey
706 : keys::kExcludeResponseHeadersKey);
709 bool WebRequestConditionAttributeResponseHeaders::Equals(
710 const WebRequestConditionAttribute* other) const {
711 return false;
715 // WebRequestConditionAttributeThirdParty
718 WebRequestConditionAttributeThirdParty::
719 WebRequestConditionAttributeThirdParty(bool match_third_party)
720 : match_third_party_(match_third_party) {}
722 WebRequestConditionAttributeThirdParty::
723 ~WebRequestConditionAttributeThirdParty() {}
725 // static
726 scoped_refptr<const WebRequestConditionAttribute>
727 WebRequestConditionAttributeThirdParty::Create(
728 const std::string& name,
729 const base::Value* value,
730 std::string* error,
731 bool* bad_message) {
732 DCHECK(name == keys::kThirdPartyKey);
734 bool third_party = false; // Dummy value, gets overwritten.
735 if (!value->GetAsBoolean(&third_party)) {
736 *error = ErrorUtils::FormatErrorMessage(kInvalidValue,
737 keys::kThirdPartyKey);
738 return scoped_refptr<const WebRequestConditionAttribute>(NULL);
741 return scoped_refptr<const WebRequestConditionAttribute>(
742 new WebRequestConditionAttributeThirdParty(third_party));
745 int WebRequestConditionAttributeThirdParty::GetStages() const {
746 return ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS | ON_SEND_HEADERS |
747 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED | ON_BEFORE_REDIRECT |
748 ON_RESPONSE_STARTED | ON_COMPLETED | ON_ERROR;
751 bool WebRequestConditionAttributeThirdParty::IsFulfilled(
752 const WebRequestData& request_data) const {
753 if (!(request_data.stage & GetStages()))
754 return false;
756 // Request is "1st party" if it gets cookies under 3rd party-blocking policy.
757 const net::StaticCookiePolicy block_third_party_policy(
758 net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES);
759 const int can_get_cookies = block_third_party_policy.CanGetCookies(
760 request_data.request->url(),
761 request_data.request->first_party_for_cookies());
762 const bool is_first_party = (can_get_cookies == net::OK);
764 return match_third_party_ ? !is_first_party : is_first_party;
767 WebRequestConditionAttribute::Type
768 WebRequestConditionAttributeThirdParty::GetType() const {
769 return CONDITION_THIRD_PARTY;
772 std::string WebRequestConditionAttributeThirdParty::GetName() const {
773 return keys::kThirdPartyKey;
776 bool WebRequestConditionAttributeThirdParty::Equals(
777 const WebRequestConditionAttribute* other) const {
778 if (!WebRequestConditionAttribute::Equals(other))
779 return false;
780 const WebRequestConditionAttributeThirdParty* casted_other =
781 static_cast<const WebRequestConditionAttributeThirdParty*>(other);
782 return match_third_party_ == casted_other->match_third_party_;
786 // WebRequestConditionAttributeStages
789 WebRequestConditionAttributeStages::
790 WebRequestConditionAttributeStages(int allowed_stages)
791 : allowed_stages_(allowed_stages) {}
793 WebRequestConditionAttributeStages::
794 ~WebRequestConditionAttributeStages() {}
796 namespace {
798 // Reads strings stored in |value|, which is expected to be a ListValue, and
799 // sets corresponding bits (see RequestStage) in |out_stages|. Returns true on
800 // success, false otherwise.
801 bool ParseListOfStages(const base::Value& value, int* out_stages) {
802 const base::ListValue* list = NULL;
803 if (!value.GetAsList(&list))
804 return false;
806 int stages = 0;
807 std::string stage_name;
808 for (base::ListValue::const_iterator it = list->begin();
809 it != list->end(); ++it) {
810 if (!((*it)->GetAsString(&stage_name)))
811 return false;
812 if (stage_name == keys::kOnBeforeRequestEnum) {
813 stages |= ON_BEFORE_REQUEST;
814 } else if (stage_name == keys::kOnBeforeSendHeadersEnum) {
815 stages |= ON_BEFORE_SEND_HEADERS;
816 } else if (stage_name == keys::kOnHeadersReceivedEnum) {
817 stages |= ON_HEADERS_RECEIVED;
818 } else if (stage_name == keys::kOnAuthRequiredEnum) {
819 stages |= ON_AUTH_REQUIRED;
820 } else {
821 NOTREACHED(); // JSON schema checks prevent getting here.
822 return false;
826 *out_stages = stages;
827 return true;
830 } // namespace
832 // static
833 scoped_refptr<const WebRequestConditionAttribute>
834 WebRequestConditionAttributeStages::Create(const std::string& name,
835 const base::Value* value,
836 std::string* error,
837 bool* bad_message) {
838 DCHECK(name == keys::kStagesKey);
840 int allowed_stages = 0;
841 if (!ParseListOfStages(*value, &allowed_stages)) {
842 *error = ErrorUtils::FormatErrorMessage(kInvalidValue,
843 keys::kStagesKey);
844 return scoped_refptr<const WebRequestConditionAttribute>(NULL);
847 return scoped_refptr<const WebRequestConditionAttribute>(
848 new WebRequestConditionAttributeStages(allowed_stages));
851 int WebRequestConditionAttributeStages::GetStages() const {
852 return allowed_stages_;
855 bool WebRequestConditionAttributeStages::IsFulfilled(
856 const WebRequestData& request_data) const {
857 // Note: removing '!=' triggers warning C4800 on the VS compiler.
858 return (request_data.stage & GetStages()) != 0;
861 WebRequestConditionAttribute::Type
862 WebRequestConditionAttributeStages::GetType() const {
863 return CONDITION_STAGES;
866 std::string WebRequestConditionAttributeStages::GetName() const {
867 return keys::kStagesKey;
870 bool WebRequestConditionAttributeStages::Equals(
871 const WebRequestConditionAttribute* other) const {
872 if (!WebRequestConditionAttribute::Equals(other))
873 return false;
874 const WebRequestConditionAttributeStages* casted_other =
875 static_cast<const WebRequestConditionAttributeStages*>(other);
876 return allowed_stages_ == casted_other->allowed_stages_;
879 } // namespace extensions