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