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"
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
;
34 using content::ResourceType
;
36 namespace helpers
= extension_web_request_api_helpers
;
37 namespace keys
= extensions::declarative_webrequest_constants
;
39 namespace extensions
{
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(
83 DedupingFactory
<WebRequestConditionAttribute
>::IS_PARAMETERIZED
,
84 &WebRequestConditionAttributeThirdParty::Create
);
86 factory
.RegisterFactoryMethod(
88 DedupingFactory
<WebRequestConditionAttribute
>::IS_PARAMETERIZED
,
89 &WebRequestConditionAttributeStages::Create
);
93 base::LazyInstance
<WebRequestConditionAttributeFactory
>::Leaky
94 g_web_request_condition_attribute_factory
= LAZY_INSTANCE_INITIALIZER
;
99 // WebRequestConditionAttribute
102 WebRequestConditionAttribute::WebRequestConditionAttribute() {}
104 WebRequestConditionAttribute::~WebRequestConditionAttribute() {}
106 bool WebRequestConditionAttribute::Equals(
107 const WebRequestConditionAttribute
* other
) const {
108 return GetType() == other
->GetType();
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
)
132 WebRequestConditionAttributeResourceType::
133 ~WebRequestConditionAttributeResourceType() {}
136 scoped_refptr
<const WebRequestConditionAttribute
>
137 WebRequestConditionAttributeResourceType::Create(
138 const std::string
& instance_type
,
139 const base::Value
* value
,
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()))
180 const content::ResourceRequestInfo
* info
=
181 content::ResourceRequestInfo::ForRequest(request_data
.request
);
184 return std::find(types_
.begin(), types_
.end(), info
->GetResourceType()) !=
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
))
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
,
214 : content_types_(content_types
),
215 inclusive_(inclusive
) {}
217 WebRequestConditionAttributeContentType::
218 ~WebRequestConditionAttributeContentType() {}
221 scoped_refptr
<const WebRequestConditionAttribute
>
222 WebRequestConditionAttributeContentType::Create(
223 const std::string
& name
,
224 const base::Value
* value
,
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()))
258 std::string content_type
;
259 request_data
.original_response_headers
->GetNormalizedHeader(
260 net::HttpRequestHeaders::kContentType
, &content_type
);
261 std::string mime_type
;
263 bool had_charset
= false;
264 net::HttpUtil::ParseContentType(
265 content_type
, &mime_type
, &charset
, &had_charset
, NULL
);
268 return std::find(content_types_
.begin(), content_types_
.end(),
269 mime_type
) != content_types_
.end();
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
))
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
{
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;
312 // Represents a single string-matching test.
313 class StringMatchTest
{
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
,
321 bool case_sensitive
);
324 // Does |str| pass |this| StringMatchTest?
325 bool Matches(const std::string
& str
) const;
328 StringMatchTest(const std::string
& data
,
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
{
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;
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() {}
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
))
404 HeaderMatcher::HeaderMatcher(ScopedVector
<const HeaderMatchTest
>* tests
)
405 : tests_(tests
->Pass()) {}
407 // HeaderMatcher::StringMatchTest implementation.
410 scoped_ptr
<HeaderMatcher::StringMatchTest
>
411 HeaderMatcher::StringMatchTest::Create(const base::Value
* data
,
413 bool case_sensitive
) {
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 {
426 return base::StartsWith(str
, data_
, case_sensitive_
);
428 return base::EndsWith(str
, data_
, case_sensitive_
);
430 return str
.size() == data_
.size() &&
431 base::StartsWith(str
, data_
, case_sensitive_
);
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();
437 return str
.find(data_
) != std::string::npos
;
440 // We never get past the "switch", but the compiler worries about no return.
445 HeaderMatcher::StringMatchTest::StringMatchTest(const std::string
& data
,
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() {}
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
) {
475 match_type
= StringMatchTest::kPrefix
;
476 } else if (it
.key() == keys::kNameSuffixKey
) {
478 match_type
= StringMatchTest::kSuffix
;
479 } else if (it
.key() == keys::kNameContainsKey
) {
481 match_type
= StringMatchTest::kContains
;
482 } else if (it
.key() == keys::kNameEqualsKey
) {
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
;
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
) {
508 StringMatchTest::Create(*it
, match_type
, !is_name
).release());
512 case base::Value::TYPE_STRING
: {
514 StringMatchTest::Create(content
, match_type
, !is_name
).release());
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
))
535 for (size_t i
= 0; i
< value_match_
.size(); ++i
) {
536 if (!value_match_
[i
]->Matches(value
))
544 // WebRequestConditionAttributeRequestHeaders
547 WebRequestConditionAttributeRequestHeaders::
548 WebRequestConditionAttributeRequestHeaders(
549 scoped_ptr
<const HeaderMatcher
> header_matcher
,
551 : header_matcher_(header_matcher
.Pass()),
552 positive_(positive
) {}
554 WebRequestConditionAttributeRequestHeaders::
555 ~WebRequestConditionAttributeRequestHeaders() {}
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();
579 scoped_refptr
<const WebRequestConditionAttribute
>
580 WebRequestConditionAttributeRequestHeaders::Create(
581 const std::string
& name
,
582 const base::Value
* value
,
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()))
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.
639 // WebRequestConditionAttributeResponseHeaders
642 WebRequestConditionAttributeResponseHeaders::
643 WebRequestConditionAttributeResponseHeaders(
644 scoped_ptr
<const HeaderMatcher
> header_matcher
,
646 : header_matcher_(header_matcher
.Pass()),
647 positive_(positive
) {}
649 WebRequestConditionAttributeResponseHeaders::
650 ~WebRequestConditionAttributeResponseHeaders() {}
653 scoped_refptr
<const WebRequestConditionAttribute
>
654 WebRequestConditionAttributeResponseHeaders::Create(
655 const std::string
& name
,
656 const base::Value
* value
,
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()))
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.
689 bool passed
= false; // Did some header pass TestNameValue?
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 {
716 // WebRequestConditionAttributeThirdParty
719 WebRequestConditionAttributeThirdParty::
720 WebRequestConditionAttributeThirdParty(bool match_third_party
)
721 : match_third_party_(match_third_party
) {}
723 WebRequestConditionAttributeThirdParty::
724 ~WebRequestConditionAttributeThirdParty() {}
727 scoped_refptr
<const WebRequestConditionAttribute
>
728 WebRequestConditionAttributeThirdParty::Create(
729 const std::string
& name
,
730 const base::Value
* value
,
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()))
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
))
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() {}
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
))
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
)))
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
;
822 NOTREACHED(); // JSON schema checks prevent getting here.
827 *out_stages
= stages
;
834 scoped_refptr
<const WebRequestConditionAttribute
>
835 WebRequestConditionAttributeStages::Create(const std::string
& name
,
836 const base::Value
* value
,
839 DCHECK(name
== keys::kStagesKey
);
841 int allowed_stages
= 0;
842 if (!ParseListOfStages(*value
, &allowed_stages
)) {
843 *error
= ErrorUtils::FormatErrorMessage(kInvalidValue
,
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
))
875 const WebRequestConditionAttributeStages
* casted_other
=
876 static_cast<const WebRequestConditionAttributeStages
*>(other
);
877 return allowed_stages_
== casted_other
->allowed_stages_
;
880 } // namespace extensions