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.h"
8 #include "base/logging.h"
9 #include "base/stl_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/values.h"
12 #include "components/url_matcher/url_matcher_factory.h"
13 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
14 #include "extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.h"
15 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
16 #include "net/url_request/url_request.h"
18 using url_matcher::URLMatcherConditionFactory
;
19 using url_matcher::URLMatcherConditionSet
;
20 using url_matcher::URLMatcherFactory
;
22 namespace keys
= extensions::declarative_webrequest_constants
;
25 static URLMatcherConditionSet::ID g_next_id
= 0;
27 // TODO(battre): improve error messaging to give more meaningful messages
28 // to the extension developer.
30 const char kExpectedDictionary
[] = "A condition has to be a dictionary.";
31 const char kConditionWithoutInstanceType
[] = "A condition had no instanceType";
32 const char kExpectedOtherConditionType
[] = "Expected a condition of type "
33 "declarativeWebRequest.RequestMatcher";
34 const char kInvalidTypeOfParamter
[] = "Attribute '%s' has an invalid type";
35 const char kConditionCannotBeFulfilled
[] = "A condition can never be "
36 "fulfilled because its attributes cannot all be tested at the "
37 "same time in the request life-cycle.";
40 namespace extensions
{
42 namespace keys
= declarative_webrequest_constants
;
48 WebRequestData::WebRequestData(net::URLRequest
* request
, RequestStage stage
)
51 original_response_headers(NULL
) {}
53 WebRequestData::WebRequestData(
54 net::URLRequest
* request
,
56 const net::HttpResponseHeaders
* original_response_headers
)
59 original_response_headers(original_response_headers
) {}
61 WebRequestData::~WebRequestData() {}
64 // WebRequestDataWithMatchIds
67 WebRequestDataWithMatchIds::WebRequestDataWithMatchIds(
68 const WebRequestData
* request_data
)
69 : data(request_data
) {}
71 WebRequestDataWithMatchIds::~WebRequestDataWithMatchIds() {}
74 // WebRequestCondition
77 WebRequestCondition::WebRequestCondition(
78 scoped_refptr
<URLMatcherConditionSet
> url_matcher_conditions
,
79 scoped_refptr
<URLMatcherConditionSet
> first_party_url_matcher_conditions
,
80 const WebRequestConditionAttributes
& condition_attributes
)
81 : url_matcher_conditions_(url_matcher_conditions
),
82 first_party_url_matcher_conditions_(first_party_url_matcher_conditions
),
83 condition_attributes_(condition_attributes
),
84 applicable_request_stages_(~0) {
85 for (WebRequestConditionAttributes::const_iterator i
=
86 condition_attributes_
.begin(); i
!= condition_attributes_
.end(); ++i
) {
87 applicable_request_stages_
&= (*i
)->GetStages();
91 WebRequestCondition::~WebRequestCondition() {}
93 bool WebRequestCondition::IsFulfilled(
94 const MatchData
& request_data
) const {
95 if (!(request_data
.data
->stage
& applicable_request_stages_
)) {
96 // A condition that cannot be evaluated is considered as violated.
100 // Check URL attributes if present.
101 if (url_matcher_conditions_
.get() &&
102 !ContainsKey(request_data
.url_match_ids
, url_matcher_conditions_
->id()))
104 if (first_party_url_matcher_conditions_
.get() &&
105 !ContainsKey(request_data
.first_party_url_match_ids
,
106 first_party_url_matcher_conditions_
->id()))
109 // All condition attributes must be fulfilled for a fulfilled condition.
110 for (WebRequestConditionAttributes::const_iterator i
=
111 condition_attributes_
.begin();
112 i
!= condition_attributes_
.end(); ++i
) {
113 if (!(*i
)->IsFulfilled(*(request_data
.data
)))
119 void WebRequestCondition::GetURLMatcherConditionSets(
120 URLMatcherConditionSet::Vector
* condition_sets
) const {
121 if (url_matcher_conditions_
.get())
122 condition_sets
->push_back(url_matcher_conditions_
);
123 if (first_party_url_matcher_conditions_
.get())
124 condition_sets
->push_back(first_party_url_matcher_conditions_
);
128 scoped_ptr
<WebRequestCondition
> WebRequestCondition::Create(
129 const Extension
* extension
,
130 URLMatcherConditionFactory
* url_matcher_condition_factory
,
131 const base::Value
& condition
,
132 std::string
* error
) {
133 const base::DictionaryValue
* condition_dict
= NULL
;
134 if (!condition
.GetAsDictionary(&condition_dict
)) {
135 *error
= kExpectedDictionary
;
136 return scoped_ptr
<WebRequestCondition
>();
139 // Verify that we are dealing with a Condition whose type we understand.
140 std::string instance_type
;
141 if (!condition_dict
->GetString(keys::kInstanceTypeKey
, &instance_type
)) {
142 *error
= kConditionWithoutInstanceType
;
143 return scoped_ptr
<WebRequestCondition
>();
145 if (instance_type
!= keys::kRequestMatcherType
) {
146 *error
= kExpectedOtherConditionType
;
147 return scoped_ptr
<WebRequestCondition
>();
150 WebRequestConditionAttributes attributes
;
151 scoped_refptr
<URLMatcherConditionSet
> url_matcher_condition_set
;
152 scoped_refptr
<URLMatcherConditionSet
> first_party_url_matcher_condition_set
;
154 for (base::DictionaryValue::Iterator
iter(*condition_dict
);
155 !iter
.IsAtEnd(); iter
.Advance()) {
156 const std::string
& condition_attribute_name
= iter
.key();
157 const base::Value
& condition_attribute_value
= iter
.value();
158 const bool name_is_url
= condition_attribute_name
== keys::kUrlKey
;
159 if (condition_attribute_name
== keys::kInstanceTypeKey
) {
161 } else if (name_is_url
||
162 condition_attribute_name
== keys::kFirstPartyForCookiesUrlKey
) {
163 const base::DictionaryValue
* dict
= NULL
;
164 if (!condition_attribute_value
.GetAsDictionary(&dict
)) {
165 *error
= base::StringPrintf(kInvalidTypeOfParamter
,
166 condition_attribute_name
.c_str());
169 url_matcher_condition_set
=
170 URLMatcherFactory::CreateFromURLFilterDictionary(
171 url_matcher_condition_factory
, dict
, ++g_next_id
, error
);
173 first_party_url_matcher_condition_set
=
174 URLMatcherFactory::CreateFromURLFilterDictionary(
175 url_matcher_condition_factory
, dict
, ++g_next_id
, error
);
179 scoped_refptr
<const WebRequestConditionAttribute
> attribute
=
180 WebRequestConditionAttribute::Create(
181 condition_attribute_name
,
182 &condition_attribute_value
,
185 attributes
.push_back(attribute
);
188 return scoped_ptr
<WebRequestCondition
>();
191 scoped_ptr
<WebRequestCondition
> result(
192 new WebRequestCondition(url_matcher_condition_set
,
193 first_party_url_matcher_condition_set
,
196 if (!result
->stages()) {
197 *error
= kConditionCannotBeFulfilled
;
198 return scoped_ptr
<WebRequestCondition
>();
201 return result
.Pass();
204 } // namespace extensions