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 "chrome/browser/extensions/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 "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
13 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h"
14 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
15 #include "extensions/common/matcher/url_matcher_factory.h"
16 #include "net/url_request/url_request.h"
18 namespace keys = extensions::declarative_webrequest_constants;
21 static extensions::URLMatcherConditionSet::ID g_next_id = 0;
23 // TODO(battre): improve error messaging to give more meaningful messages
24 // to the extension developer.
26 const char kExpectedDictionary[] = "A condition has to be a dictionary.";
27 const char kConditionWithoutInstanceType[] = "A condition had no instanceType";
28 const char kExpectedOtherConditionType[] = "Expected a condition of type "
29 "declarativeWebRequest.RequestMatcher";
30 const char kInvalidTypeOfParamter[] = "Attribute '%s' has an invalid type";
31 const char kConditionCannotBeFulfilled[] = "A condition can never be "
32 "fulfilled because its attributes cannot all be tested at the "
33 "same time in the request life-cycle.";
36 namespace extensions {
38 namespace keys = declarative_webrequest_constants;
44 WebRequestData::WebRequestData(net::URLRequest* request, RequestStage stage)
47 original_response_headers(NULL) {}
49 WebRequestData::WebRequestData(
50 net::URLRequest* request,
52 const net::HttpResponseHeaders* original_response_headers)
55 original_response_headers(original_response_headers) {}
57 WebRequestData::~WebRequestData() {}
60 // WebRequestDataWithMatchIds
63 WebRequestDataWithMatchIds::WebRequestDataWithMatchIds(
64 const WebRequestData* request_data)
65 : data(request_data) {}
67 WebRequestDataWithMatchIds::~WebRequestDataWithMatchIds() {}
70 // WebRequestCondition
73 WebRequestCondition::WebRequestCondition(
74 scoped_refptr<URLMatcherConditionSet> url_matcher_conditions,
75 scoped_refptr<URLMatcherConditionSet> first_party_url_matcher_conditions,
76 const WebRequestConditionAttributes& condition_attributes)
77 : url_matcher_conditions_(url_matcher_conditions),
78 first_party_url_matcher_conditions_(first_party_url_matcher_conditions),
79 condition_attributes_(condition_attributes),
80 applicable_request_stages_(~0) {
81 for (WebRequestConditionAttributes::const_iterator i =
82 condition_attributes_.begin(); i != condition_attributes_.end(); ++i) {
83 applicable_request_stages_ &= (*i)->GetStages();
87 WebRequestCondition::~WebRequestCondition() {}
89 bool WebRequestCondition::IsFulfilled(
90 const MatchData& request_data) const {
91 if (!(request_data.data->stage & applicable_request_stages_)) {
92 // A condition that cannot be evaluated is considered as violated.
96 // Check URL attributes if present.
97 if (url_matcher_conditions_.get() &&
98 !ContainsKey(request_data.url_match_ids, url_matcher_conditions_->id()))
100 if (first_party_url_matcher_conditions_.get() &&
101 !ContainsKey(request_data.first_party_url_match_ids,
102 first_party_url_matcher_conditions_->id()))
105 // All condition attributes must be fulfilled for a fulfilled condition.
106 for (WebRequestConditionAttributes::const_iterator i =
107 condition_attributes_.begin();
108 i != condition_attributes_.end(); ++i) {
109 if (!(*i)->IsFulfilled(*(request_data.data)))
115 void WebRequestCondition::GetURLMatcherConditionSets(
116 URLMatcherConditionSet::Vector* condition_sets) const {
117 if (url_matcher_conditions_.get())
118 condition_sets->push_back(url_matcher_conditions_);
119 if (first_party_url_matcher_conditions_.get())
120 condition_sets->push_back(first_party_url_matcher_conditions_);
124 scoped_ptr<WebRequestCondition> WebRequestCondition::Create(
125 const Extension* extension,
126 URLMatcherConditionFactory* url_matcher_condition_factory,
127 const base::Value& condition,
128 std::string* error) {
129 const base::DictionaryValue* condition_dict = NULL;
130 if (!condition.GetAsDictionary(&condition_dict)) {
131 *error = kExpectedDictionary;
132 return scoped_ptr<WebRequestCondition>();
135 // Verify that we are dealing with a Condition whose type we understand.
136 std::string instance_type;
137 if (!condition_dict->GetString(keys::kInstanceTypeKey, &instance_type)) {
138 *error = kConditionWithoutInstanceType;
139 return scoped_ptr<WebRequestCondition>();
141 if (instance_type != keys::kRequestMatcherType) {
142 *error = kExpectedOtherConditionType;
143 return scoped_ptr<WebRequestCondition>();
146 WebRequestConditionAttributes attributes;
147 scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set;
148 scoped_refptr<URLMatcherConditionSet> first_party_url_matcher_condition_set;
150 for (base::DictionaryValue::Iterator iter(*condition_dict);
151 !iter.IsAtEnd(); iter.Advance()) {
152 const std::string& condition_attribute_name = iter.key();
153 const Value& condition_attribute_value = iter.value();
154 const bool name_is_url = condition_attribute_name == keys::kUrlKey;
155 if (condition_attribute_name == keys::kInstanceTypeKey) {
157 } else if (name_is_url ||
158 condition_attribute_name == keys::kFirstPartyForCookiesUrlKey) {
159 const base::DictionaryValue* dict = NULL;
160 if (!condition_attribute_value.GetAsDictionary(&dict)) {
161 *error = base::StringPrintf(kInvalidTypeOfParamter,
162 condition_attribute_name.c_str());
165 url_matcher_condition_set =
166 URLMatcherFactory::CreateFromURLFilterDictionary(
167 url_matcher_condition_factory, dict, ++g_next_id, error);
169 first_party_url_matcher_condition_set =
170 URLMatcherFactory::CreateFromURLFilterDictionary(
171 url_matcher_condition_factory, dict, ++g_next_id, error);
175 scoped_refptr<const WebRequestConditionAttribute> attribute =
176 WebRequestConditionAttribute::Create(
177 condition_attribute_name,
178 &condition_attribute_value,
181 attributes.push_back(attribute);
184 return scoped_ptr<WebRequestCondition>();
187 scoped_ptr<WebRequestCondition> result(
188 new WebRequestCondition(url_matcher_condition_set,
189 first_party_url_matcher_condition_set,
192 if (!result->stages()) {
193 *error = kConditionCannotBeFulfilled;
194 return scoped_ptr<WebRequestCondition>();
197 return result.Pass();
200 } // namespace extensions