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 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
{
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
.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
))
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 StartsWithASCII(str
, data_
, case_sensitive_
);
427 return EndsWith(str
, data_
, case_sensitive_
);
429 return str
.size() == data_
.size() &&
430 StartsWithASCII(str
, data_
, case_sensitive_
);
432 if (!case_sensitive_
) {
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
) {}
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() {}
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
) {
473 match_type
= StringMatchTest::kPrefix
;
474 } else if (it
.key() == keys::kNameSuffixKey
) {
476 match_type
= StringMatchTest::kSuffix
;
477 } else if (it
.key() == keys::kNameContainsKey
) {
479 match_type
= StringMatchTest::kContains
;
480 } else if (it
.key() == keys::kNameEqualsKey
) {
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
;
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
) {
506 StringMatchTest::Create(*it
, match_type
, !is_name
).release());
510 case base::Value::TYPE_STRING
: {
512 StringMatchTest::Create(content
, match_type
, !is_name
).release());
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
))
533 for (size_t i
= 0; i
< value_match_
.size(); ++i
) {
534 if (!value_match_
[i
]->Matches(value
))
542 // WebRequestConditionAttributeRequestHeaders
545 WebRequestConditionAttributeRequestHeaders::
546 WebRequestConditionAttributeRequestHeaders(
547 scoped_ptr
<const HeaderMatcher
> header_matcher
,
549 : header_matcher_(header_matcher
.Pass()),
550 positive_(positive
) {}
552 WebRequestConditionAttributeRequestHeaders::
553 ~WebRequestConditionAttributeRequestHeaders() {}
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();
577 scoped_refptr
<const WebRequestConditionAttribute
>
578 WebRequestConditionAttributeRequestHeaders::Create(
579 const std::string
& name
,
580 const base::Value
* value
,
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()))
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.
637 // WebRequestConditionAttributeResponseHeaders
640 WebRequestConditionAttributeResponseHeaders::
641 WebRequestConditionAttributeResponseHeaders(
642 scoped_ptr
<const HeaderMatcher
> header_matcher
,
644 : header_matcher_(header_matcher
.Pass()),
645 positive_(positive
) {}
647 WebRequestConditionAttributeResponseHeaders::
648 ~WebRequestConditionAttributeResponseHeaders() {}
651 scoped_refptr
<const WebRequestConditionAttribute
>
652 WebRequestConditionAttributeResponseHeaders::Create(
653 const std::string
& name
,
654 const base::Value
* value
,
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()))
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.
687 bool passed
= false; // Did some header pass TestNameValue?
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 {
714 // WebRequestConditionAttributeThirdParty
717 WebRequestConditionAttributeThirdParty::
718 WebRequestConditionAttributeThirdParty(bool match_third_party
)
719 : match_third_party_(match_third_party
) {}
721 WebRequestConditionAttributeThirdParty::
722 ~WebRequestConditionAttributeThirdParty() {}
725 scoped_refptr
<const WebRequestConditionAttribute
>
726 WebRequestConditionAttributeThirdParty::Create(
727 const std::string
& name
,
728 const base::Value
* value
,
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()))
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
))
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() {}
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
))
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
)))
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
;
820 NOTREACHED(); // JSON schema checks prevent getting here.
825 *out_stages
= stages
;
832 scoped_refptr
<const WebRequestConditionAttribute
>
833 WebRequestConditionAttributeStages::Create(const std::string
& name
,
834 const base::Value
* value
,
837 DCHECK(name
== keys::kStagesKey
);
839 int allowed_stages
= 0;
840 if (!ParseListOfStages(*value
, &allowed_stages
)) {
841 *error
= ErrorUtils::FormatErrorMessage(kInvalidValue
,
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
))
873 const WebRequestConditionAttributeStages
* casted_other
=
874 static_cast<const WebRequestConditionAttributeStages
*>(other
);
875 return allowed_stages_
== casted_other
->allowed_stages_
;
878 } // namespace extensions