Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / extensions / browser / api / declarative_webrequest / webrequest_condition_attribute.cc
blob8c0635fb7148dca1def2a915763412c43dba9b94
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 bool 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.release());
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 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;
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) {}
451 // HeaderMatcher::HeaderMatchTest implementation.
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()) {}
459 HeaderMatcher::HeaderMatchTest::~HeaderMatchTest() {}
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;
467 for (base::DictionaryValue::Iterator it(*tests);
468 !it.IsAtEnd(); it.Advance()) {
469 bool is_name = false; // Is this test for header name?
470 StringMatchTest::MatchType match_type;
471 if (it.key() == keys::kNamePrefixKey) {
472 is_name = true;
473 match_type = StringMatchTest::kPrefix;
474 } else if (it.key() == keys::kNameSuffixKey) {
475 is_name = true;
476 match_type = StringMatchTest::kSuffix;
477 } else if (it.key() == keys::kNameContainsKey) {
478 is_name = true;
479 match_type = StringMatchTest::kContains;
480 } else if (it.key() == keys::kNameEqualsKey) {
481 is_name = true;
482 match_type = StringMatchTest::kEquals;
483 } else if (it.key() == keys::kValuePrefixKey) {
484 match_type = StringMatchTest::kPrefix;
485 } else if (it.key() == keys::kValueSuffixKey) {
486 match_type = StringMatchTest::kSuffix;
487 } else if (it.key() == keys::kValueContainsKey) {
488 match_type = StringMatchTest::kContains;
489 } else if (it.key() == keys::kValueEqualsKey) {
490 match_type = StringMatchTest::kEquals;
491 } else {
492 NOTREACHED(); // JSON schema type checking should prevent this.
493 return scoped_ptr<const HeaderMatchTest>();
495 const base::Value* content = &it.value();
497 ScopedVector<const StringMatchTest>* tests =
498 is_name ? &name_match : &value_match;
499 switch (content->GetType()) {
500 case base::Value::TYPE_LIST: {
501 const base::ListValue* list = NULL;
502 CHECK(content->GetAsList(&list));
503 for (base::ListValue::const_iterator it = list->begin();
504 it != list->end(); ++it) {
505 tests->push_back(
506 StringMatchTest::Create(*it, match_type, !is_name).release());
508 break;
510 case base::Value::TYPE_STRING: {
511 tests->push_back(
512 StringMatchTest::Create(content, match_type, !is_name).release());
513 break;
515 default: {
516 NOTREACHED(); // JSON schema type checking should prevent this.
517 return scoped_ptr<const HeaderMatchTest>();
522 return scoped_ptr<const HeaderMatchTest>(
523 new HeaderMatchTest(&name_match, &value_match));
526 bool HeaderMatcher::HeaderMatchTest::Matches(const std::string& name,
527 const std::string& value) const {
528 for (size_t i = 0; i < name_match_.size(); ++i) {
529 if (!name_match_[i]->Matches(name))
530 return false;
533 for (size_t i = 0; i < value_match_.size(); ++i) {
534 if (!value_match_[i]->Matches(value))
535 return false;
538 return true;
542 // WebRequestConditionAttributeRequestHeaders
545 WebRequestConditionAttributeRequestHeaders::
546 WebRequestConditionAttributeRequestHeaders(
547 scoped_ptr<const HeaderMatcher> header_matcher,
548 bool positive)
549 : header_matcher_(header_matcher.Pass()),
550 positive_(positive) {}
552 WebRequestConditionAttributeRequestHeaders::
553 ~WebRequestConditionAttributeRequestHeaders() {}
555 namespace {
557 scoped_ptr<const HeaderMatcher> PrepareHeaderMatcher(
558 const std::string& name,
559 const base::Value* value,
560 std::string* error) {
561 const base::ListValue* value_as_list = NULL;
562 if (!value->GetAsList(&value_as_list)) {
563 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name);
564 return scoped_ptr<const HeaderMatcher>();
567 scoped_ptr<const HeaderMatcher> header_matcher(
568 HeaderMatcher::Create(value_as_list));
569 if (header_matcher.get() == NULL)
570 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name);
571 return header_matcher.Pass();
574 } // namespace
576 // static
577 scoped_refptr<const WebRequestConditionAttribute>
578 WebRequestConditionAttributeRequestHeaders::Create(
579 const std::string& name,
580 const base::Value* value,
581 std::string* error,
582 bool* bad_message) {
583 DCHECK(name == keys::kRequestHeadersKey ||
584 name == keys::kExcludeRequestHeadersKey);
586 scoped_ptr<const HeaderMatcher> header_matcher(
587 PrepareHeaderMatcher(name, value, error));
588 if (header_matcher.get() == NULL)
589 return scoped_refptr<const WebRequestConditionAttribute>(NULL);
591 return scoped_refptr<const WebRequestConditionAttribute>(
592 new WebRequestConditionAttributeRequestHeaders(
593 header_matcher.Pass(), name == keys::kRequestHeadersKey));
596 int WebRequestConditionAttributeRequestHeaders::GetStages() const {
597 // Currently we only allow matching against headers in the before-send-headers
598 // stage. The headers are accessible in other stages as well, but before
599 // allowing to match against them in further stages, we should consider
600 // caching the match result.
601 return ON_BEFORE_SEND_HEADERS;
604 bool WebRequestConditionAttributeRequestHeaders::IsFulfilled(
605 const WebRequestData& request_data) const {
606 if (!(request_data.stage & GetStages()))
607 return false;
609 const net::HttpRequestHeaders& headers =
610 request_data.request->extra_request_headers();
612 bool passed = false; // Did some header pass TestNameValue?
613 net::HttpRequestHeaders::Iterator it(headers);
614 while (!passed && it.GetNext())
615 passed |= header_matcher_->TestNameValue(it.name(), it.value());
617 return (positive_ ? passed : !passed);
620 WebRequestConditionAttribute::Type
621 WebRequestConditionAttributeRequestHeaders::GetType() const {
622 return CONDITION_REQUEST_HEADERS;
625 std::string WebRequestConditionAttributeRequestHeaders::GetName() const {
626 return (positive_ ? keys::kRequestHeadersKey
627 : keys::kExcludeRequestHeadersKey);
630 bool WebRequestConditionAttributeRequestHeaders::Equals(
631 const WebRequestConditionAttribute* other) const {
632 // Comparing headers is too heavy, so we skip it entirely.
633 return false;
637 // WebRequestConditionAttributeResponseHeaders
640 WebRequestConditionAttributeResponseHeaders::
641 WebRequestConditionAttributeResponseHeaders(
642 scoped_ptr<const HeaderMatcher> header_matcher,
643 bool positive)
644 : header_matcher_(header_matcher.Pass()),
645 positive_(positive) {}
647 WebRequestConditionAttributeResponseHeaders::
648 ~WebRequestConditionAttributeResponseHeaders() {}
650 // static
651 scoped_refptr<const WebRequestConditionAttribute>
652 WebRequestConditionAttributeResponseHeaders::Create(
653 const std::string& name,
654 const base::Value* value,
655 std::string* error,
656 bool* bad_message) {
657 DCHECK(name == keys::kResponseHeadersKey ||
658 name == keys::kExcludeResponseHeadersKey);
660 scoped_ptr<const HeaderMatcher> header_matcher(
661 PrepareHeaderMatcher(name, value, error));
662 if (header_matcher.get() == NULL)
663 return scoped_refptr<const WebRequestConditionAttribute>(NULL);
665 return scoped_refptr<const WebRequestConditionAttribute>(
666 new WebRequestConditionAttributeResponseHeaders(
667 header_matcher.Pass(), name == keys::kResponseHeadersKey));
670 int WebRequestConditionAttributeResponseHeaders::GetStages() const {
671 return ON_HEADERS_RECEIVED;
674 bool WebRequestConditionAttributeResponseHeaders::IsFulfilled(
675 const WebRequestData& request_data) const {
676 if (!(request_data.stage & GetStages()))
677 return false;
679 const net::HttpResponseHeaders* headers =
680 request_data.original_response_headers;
681 if (headers == NULL) {
682 // Each header of an empty set satisfies (the negation of) everything;
683 // OTOH, there is no header to satisfy even the most permissive test.
684 return !positive_;
687 bool passed = false; // Did some header pass TestNameValue?
688 std::string name;
689 std::string value;
690 void* iter = NULL;
691 while (!passed && headers->EnumerateHeaderLines(&iter, &name, &value)) {
692 passed |= header_matcher_->TestNameValue(name, value);
695 return (positive_ ? passed : !passed);
698 WebRequestConditionAttribute::Type
699 WebRequestConditionAttributeResponseHeaders::GetType() const {
700 return CONDITION_RESPONSE_HEADERS;
703 std::string WebRequestConditionAttributeResponseHeaders::GetName() const {
704 return (positive_ ? keys::kResponseHeadersKey
705 : keys::kExcludeResponseHeadersKey);
708 bool WebRequestConditionAttributeResponseHeaders::Equals(
709 const WebRequestConditionAttribute* other) const {
710 return false;
714 // WebRequestConditionAttributeThirdParty
717 WebRequestConditionAttributeThirdParty::
718 WebRequestConditionAttributeThirdParty(bool match_third_party)
719 : match_third_party_(match_third_party) {}
721 WebRequestConditionAttributeThirdParty::
722 ~WebRequestConditionAttributeThirdParty() {}
724 // static
725 scoped_refptr<const WebRequestConditionAttribute>
726 WebRequestConditionAttributeThirdParty::Create(
727 const std::string& name,
728 const base::Value* value,
729 std::string* error,
730 bool* bad_message) {
731 DCHECK(name == keys::kThirdPartyKey);
733 bool third_party = false; // Dummy value, gets overwritten.
734 if (!value->GetAsBoolean(&third_party)) {
735 *error = ErrorUtils::FormatErrorMessage(kInvalidValue,
736 keys::kThirdPartyKey);
737 return scoped_refptr<const WebRequestConditionAttribute>(NULL);
740 return scoped_refptr<const WebRequestConditionAttribute>(
741 new WebRequestConditionAttributeThirdParty(third_party));
744 int WebRequestConditionAttributeThirdParty::GetStages() const {
745 return ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS | ON_SEND_HEADERS |
746 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED | ON_BEFORE_REDIRECT |
747 ON_RESPONSE_STARTED | ON_COMPLETED | ON_ERROR;
750 bool WebRequestConditionAttributeThirdParty::IsFulfilled(
751 const WebRequestData& request_data) const {
752 if (!(request_data.stage & GetStages()))
753 return false;
755 // Request is "1st party" if it gets cookies under 3rd party-blocking policy.
756 const net::StaticCookiePolicy block_third_party_policy(
757 net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES);
758 const int can_get_cookies = block_third_party_policy.CanGetCookies(
759 request_data.request->url(),
760 request_data.request->first_party_for_cookies());
761 const bool is_first_party = (can_get_cookies == net::OK);
763 return match_third_party_ ? !is_first_party : is_first_party;
766 WebRequestConditionAttribute::Type
767 WebRequestConditionAttributeThirdParty::GetType() const {
768 return CONDITION_THIRD_PARTY;
771 std::string WebRequestConditionAttributeThirdParty::GetName() const {
772 return keys::kThirdPartyKey;
775 bool WebRequestConditionAttributeThirdParty::Equals(
776 const WebRequestConditionAttribute* other) const {
777 if (!WebRequestConditionAttribute::Equals(other))
778 return false;
779 const WebRequestConditionAttributeThirdParty* casted_other =
780 static_cast<const WebRequestConditionAttributeThirdParty*>(other);
781 return match_third_party_ == casted_other->match_third_party_;
785 // WebRequestConditionAttributeStages
788 WebRequestConditionAttributeStages::
789 WebRequestConditionAttributeStages(int allowed_stages)
790 : allowed_stages_(allowed_stages) {}
792 WebRequestConditionAttributeStages::
793 ~WebRequestConditionAttributeStages() {}
795 namespace {
797 // Reads strings stored in |value|, which is expected to be a ListValue, and
798 // sets corresponding bits (see RequestStage) in |out_stages|. Returns true on
799 // success, false otherwise.
800 bool ParseListOfStages(const base::Value& value, int* out_stages) {
801 const base::ListValue* list = NULL;
802 if (!value.GetAsList(&list))
803 return false;
805 int stages = 0;
806 std::string stage_name;
807 for (base::ListValue::const_iterator it = list->begin();
808 it != list->end(); ++it) {
809 if (!((*it)->GetAsString(&stage_name)))
810 return false;
811 if (stage_name == keys::kOnBeforeRequestEnum) {
812 stages |= ON_BEFORE_REQUEST;
813 } else if (stage_name == keys::kOnBeforeSendHeadersEnum) {
814 stages |= ON_BEFORE_SEND_HEADERS;
815 } else if (stage_name == keys::kOnHeadersReceivedEnum) {
816 stages |= ON_HEADERS_RECEIVED;
817 } else if (stage_name == keys::kOnAuthRequiredEnum) {
818 stages |= ON_AUTH_REQUIRED;
819 } else {
820 NOTREACHED(); // JSON schema checks prevent getting here.
821 return false;
825 *out_stages = stages;
826 return true;
829 } // namespace
831 // static
832 scoped_refptr<const WebRequestConditionAttribute>
833 WebRequestConditionAttributeStages::Create(const std::string& name,
834 const base::Value* value,
835 std::string* error,
836 bool* bad_message) {
837 DCHECK(name == keys::kStagesKey);
839 int allowed_stages = 0;
840 if (!ParseListOfStages(*value, &allowed_stages)) {
841 *error = ErrorUtils::FormatErrorMessage(kInvalidValue,
842 keys::kStagesKey);
843 return scoped_refptr<const WebRequestConditionAttribute>(NULL);
846 return scoped_refptr<const WebRequestConditionAttribute>(
847 new WebRequestConditionAttributeStages(allowed_stages));
850 int WebRequestConditionAttributeStages::GetStages() const {
851 return allowed_stages_;
854 bool WebRequestConditionAttributeStages::IsFulfilled(
855 const WebRequestData& request_data) const {
856 // Note: removing '!=' triggers warning C4800 on the VS compiler.
857 return (request_data.stage & GetStages()) != 0;
860 WebRequestConditionAttribute::Type
861 WebRequestConditionAttributeStages::GetType() const {
862 return CONDITION_STAGES;
865 std::string WebRequestConditionAttributeStages::GetName() const {
866 return keys::kStagesKey;
869 bool WebRequestConditionAttributeStages::Equals(
870 const WebRequestConditionAttribute* other) const {
871 if (!WebRequestConditionAttribute::Equals(other))
872 return false;
873 const WebRequestConditionAttributeStages* casted_other =
874 static_cast<const WebRequestConditionAttributeStages*>(other);
875 return allowed_stages_ == casted_other->allowed_stages_;
878 } // namespace extensions