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/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
;
33 using content::ResourceType
;
35 namespace helpers
= extension_web_request_api_helpers
;
36 namespace keys
= extensions::declarative_webrequest_constants
;
38 namespace extensions
{
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(
82 DedupingFactory
<WebRequestConditionAttribute
>::IS_PARAMETERIZED
,
83 &WebRequestConditionAttributeThirdParty::Create
);
85 factory
.RegisterFactoryMethod(
87 DedupingFactory
<WebRequestConditionAttribute
>::IS_PARAMETERIZED
,
88 &WebRequestConditionAttributeStages::Create
);
92 base::LazyInstance
<WebRequestConditionAttributeFactory
>::Leaky
93 g_web_request_condition_attribute_factory
= LAZY_INSTANCE_INITIALIZER
;
98 // WebRequestConditionAttribute
101 WebRequestConditionAttribute::WebRequestConditionAttribute() {}
103 WebRequestConditionAttribute::~WebRequestConditionAttribute() {}
105 bool WebRequestConditionAttribute::Equals(
106 const WebRequestConditionAttribute
* other
) const {
107 return GetType() == other
->GetType();
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
)
131 WebRequestConditionAttributeResourceType::
132 ~WebRequestConditionAttributeResourceType() {}
135 scoped_refptr
<const WebRequestConditionAttribute
>
136 WebRequestConditionAttributeResourceType::Create(
137 const std::string
& instance_type
,
138 const base::Value
* value
,
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()))
179 const content::ResourceRequestInfo
* info
=
180 content::ResourceRequestInfo::ForRequest(request_data
.request
);
183 return std::find(types_
.begin(), types_
.end(), info
->GetResourceType()) !=
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
))
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
,
213 : content_types_(content_types
),
214 inclusive_(inclusive
) {}
216 WebRequestConditionAttributeContentType::
217 ~WebRequestConditionAttributeContentType() {}
220 scoped_refptr
<const WebRequestConditionAttribute
>
221 WebRequestConditionAttributeContentType::Create(
222 const std::string
& name
,
223 const base::Value
* value
,
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()))
257 std::string content_type
;
258 request_data
.original_response_headers
->GetNormalizedHeader(
259 net::HttpRequestHeaders::kContentType
, &content_type
);
260 std::string mime_type
;
262 bool had_charset
= false;
263 net::HttpUtil::ParseContentType(
264 content_type
, &mime_type
, &charset
, &had_charset
, NULL
);
267 return std::find(content_types_
.begin(), content_types_
.end(),
268 mime_type
) != content_types_
.end();
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
))
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
{
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;
311 // Represents a single string-matching test.
312 class StringMatchTest
{
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
,
320 bool case_sensitive
);
323 // Does |str| pass |this| StringMatchTest?
324 bool Matches(const std::string
& str
) const;
327 StringMatchTest(const std::string
& data
,
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
{
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;
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() {}
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
))
403 HeaderMatcher::HeaderMatcher(ScopedVector
<const HeaderMatchTest
>* tests
)
404 : tests_(tests
->Pass()) {}
406 // HeaderMatcher::StringMatchTest implementation.
409 scoped_ptr
<HeaderMatcher::StringMatchTest
>
410 HeaderMatcher::StringMatchTest::Create(const base::Value
* data
,
412 bool case_sensitive
) {
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 {
425 return base::StartsWith(str
, data_
, case_sensitive_
);
427 return base::EndsWith(str
, data_
, case_sensitive_
);
429 return str
.size() == data_
.size() &&
430 base::StartsWith(str
, data_
, case_sensitive_
);
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();
436 return str
.find(data_
) != std::string::npos
;
439 // We never get past the "switch", but the compiler worries about no return.
444 HeaderMatcher::StringMatchTest::StringMatchTest(const std::string
& data
,
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() {}
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
) {
474 match_type
= StringMatchTest::kPrefix
;
475 } else if (it
.key() == keys::kNameSuffixKey
) {
477 match_type
= StringMatchTest::kSuffix
;
478 } else if (it
.key() == keys::kNameContainsKey
) {
480 match_type
= StringMatchTest::kContains
;
481 } else if (it
.key() == keys::kNameEqualsKey
) {
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
;
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
) {
507 StringMatchTest::Create(*it
, match_type
, !is_name
).release());
511 case base::Value::TYPE_STRING
: {
513 StringMatchTest::Create(content
, match_type
, !is_name
).release());
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
))
534 for (size_t i
= 0; i
< value_match_
.size(); ++i
) {
535 if (!value_match_
[i
]->Matches(value
))
543 // WebRequestConditionAttributeRequestHeaders
546 WebRequestConditionAttributeRequestHeaders::
547 WebRequestConditionAttributeRequestHeaders(
548 scoped_ptr
<const HeaderMatcher
> header_matcher
,
550 : header_matcher_(header_matcher
.Pass()),
551 positive_(positive
) {}
553 WebRequestConditionAttributeRequestHeaders::
554 ~WebRequestConditionAttributeRequestHeaders() {}
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();
578 scoped_refptr
<const WebRequestConditionAttribute
>
579 WebRequestConditionAttributeRequestHeaders::Create(
580 const std::string
& name
,
581 const base::Value
* value
,
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()))
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.
638 // WebRequestConditionAttributeResponseHeaders
641 WebRequestConditionAttributeResponseHeaders::
642 WebRequestConditionAttributeResponseHeaders(
643 scoped_ptr
<const HeaderMatcher
> header_matcher
,
645 : header_matcher_(header_matcher
.Pass()),
646 positive_(positive
) {}
648 WebRequestConditionAttributeResponseHeaders::
649 ~WebRequestConditionAttributeResponseHeaders() {}
652 scoped_refptr
<const WebRequestConditionAttribute
>
653 WebRequestConditionAttributeResponseHeaders::Create(
654 const std::string
& name
,
655 const base::Value
* value
,
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()))
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.
688 bool passed
= false; // Did some header pass TestNameValue?
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 {
715 // WebRequestConditionAttributeThirdParty
718 WebRequestConditionAttributeThirdParty::
719 WebRequestConditionAttributeThirdParty(bool match_third_party
)
720 : match_third_party_(match_third_party
) {}
722 WebRequestConditionAttributeThirdParty::
723 ~WebRequestConditionAttributeThirdParty() {}
726 scoped_refptr
<const WebRequestConditionAttribute
>
727 WebRequestConditionAttributeThirdParty::Create(
728 const std::string
& name
,
729 const base::Value
* value
,
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()))
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
))
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() {}
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
))
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
)))
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
;
821 NOTREACHED(); // JSON schema checks prevent getting here.
826 *out_stages
= stages
;
833 scoped_refptr
<const WebRequestConditionAttribute
>
834 WebRequestConditionAttributeStages::Create(const std::string
& name
,
835 const base::Value
* value
,
838 DCHECK(name
== keys::kStagesKey
);
840 int allowed_stages
= 0;
841 if (!ParseListOfStages(*value
, &allowed_stages
)) {
842 *error
= ErrorUtils::FormatErrorMessage(kInvalidValue
,
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
))
874 const WebRequestConditionAttributeStages
* casted_other
=
875 static_cast<const WebRequestConditionAttributeStages
*>(other
);
876 return allowed_stages_
== casted_other
->allowed_stages_
;
879 } // namespace extensions