OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condit
ion.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/lazy_instance.h" |
| 9 #include "base/logging.h" |
| 10 #include "base/stringprintf.h" |
| 11 #include "base/values.h" |
| 12 #include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h" |
| 13 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condit
ion_attribute.h" |
| 14 #include "net/url_request/url_request.h" |
| 15 |
| 16 namespace { |
| 17 static extensions::URLMatcherConditionSet::ID g_next_id = 0; |
| 18 |
| 19 // TODO(battre): improve error messaging to give more meaningful messages |
| 20 // to the extension developer. |
| 21 // Error messages: |
| 22 const char kExpectedDictionary[] = "A condition has to be a dictionary."; |
| 23 const char kConditionWithoutInstanceType[] = "A condition had no instanceType"; |
| 24 const char kExpectedOtherConditionType[] = "Expected a condition of type " |
| 25 "experimental.webRequest.RequestMatcher"; |
| 26 const char kUnknownConditionAttribute[] = "UnKnown condition attribute '%s'"; |
| 27 const char kConditionExpectedString[] = |
| 28 "Condition '%s' expected a string value"; |
| 29 |
| 30 // String literals from the JavaScript API: |
| 31 const char kRequestMatcher[] = "experimental.webRequest.RequestMatcher"; |
| 32 const char kInstanceType[] = "instanceType"; |
| 33 |
| 34 const char kHostContainsKey[] = "host_contains"; |
| 35 const char kHostEqualsKey[] = "host_equals"; |
| 36 const char kHostPrefixKey[] = "host_prefix"; |
| 37 const char kHostSuffixKey[] = "host_suffix"; |
| 38 const char kHostSuffixPathPrefixKey[] = "host_suffix_path_prefix"; |
| 39 const char kPathContainsKey[] = "path_contains"; |
| 40 const char kPathEqualsKey[] = "path_equals"; |
| 41 const char kPathPrefixKey[] = "path_prefix"; |
| 42 const char kPathSuffixKey[] = "path_suffix"; |
| 43 const char kQueryContainsKey[] = "query_contains"; |
| 44 const char kQueryEqualsKey[] = "query_equals"; |
| 45 const char kQueryPrefixKey[] = "query_prefix"; |
| 46 const char kQuerySuffixKey[] = "query_suffix"; |
| 47 const char kURLContainsKey[] = "url_contains"; |
| 48 const char kURLEqualsKey[] = "url_equals"; |
| 49 const char kURLPrefixKey[] = "url_prefix"; |
| 50 const char kURLSuffixKey[] = "url_suffix"; |
| 51 |
| 52 // Registry for all factory methods of extensions::URLMatcherConditionFactory |
| 53 // that allows translating string literals from the extension API into |
| 54 // the corresponding factory method to be called. |
| 55 class URLMatcherConditionFactoryMethods { |
| 56 public: |
| 57 URLMatcherConditionFactoryMethods() { |
| 58 typedef extensions::URLMatcherConditionFactory F; |
| 59 factory_methods_[kHostContainsKey] = &F::CreateHostContainsCondition; |
| 60 factory_methods_[kHostEqualsKey] = &F::CreateHostEqualsCondition; |
| 61 factory_methods_[kHostPrefixKey] = &F::CreateHostPrefixCondition; |
| 62 factory_methods_[kHostSuffixKey] = &F::CreateHostSuffixCondition; |
| 63 factory_methods_[kPathContainsKey] = &F::CreatePathContainsCondition; |
| 64 factory_methods_[kPathEqualsKey] = &F::CreatePathEqualsCondition; |
| 65 factory_methods_[kPathPrefixKey] = &F::CreatePathPrefixCondition; |
| 66 factory_methods_[kPathSuffixKey] = &F::CreatePathSuffixCondition; |
| 67 factory_methods_[kQueryContainsKey] = &F::CreateQueryContainsCondition; |
| 68 factory_methods_[kQueryEqualsKey] = &F::CreateQueryEqualsCondition; |
| 69 factory_methods_[kQueryPrefixKey] = &F::CreateQueryPrefixCondition; |
| 70 factory_methods_[kQuerySuffixKey] = &F::CreateQuerySuffixCondition; |
| 71 factory_methods_[kURLContainsKey] = &F::CreateURLContainsCondition; |
| 72 factory_methods_[kURLEqualsKey] = &F::CreateURLEqualsCondition; |
| 73 factory_methods_[kURLPrefixKey] = &F::CreateURLPrefixCondition; |
| 74 factory_methods_[kURLSuffixKey] = &F::CreateURLSuffixCondition; |
| 75 } |
| 76 |
| 77 // Returns whether a factory method for the specified |pattern_type| (e.g. |
| 78 // "host_suffix") is known. |
| 79 bool Contains(const std::string& pattern_type) const { |
| 80 return factory_methods_.find(pattern_type) != factory_methods_.end(); |
| 81 } |
| 82 |
| 83 // Creates a URLMatcherCondition instance from |url_matcher_condition_factory| |
| 84 // of the given |pattern_type| (e.g. "host_suffix") for the given |
| 85 // |pattern_value| (e.g. "example.com"). |
| 86 // The |pattern_type| needs to be known to this class (see Contains()) or |
| 87 // a CHECK is triggered. |
| 88 extensions::URLMatcherCondition Call( |
| 89 extensions::URLMatcherConditionFactory* url_matcher_condition_factory, |
| 90 const std::string& pattern_type, |
| 91 const std::string& pattern_value) const { |
| 92 FactoryMethods::const_iterator i = factory_methods_.find(pattern_type); |
| 93 CHECK(i != factory_methods_.end()); |
| 94 const FactoryMethod& method = i->second; |
| 95 return (url_matcher_condition_factory->*method)(pattern_value); |
| 96 } |
| 97 |
| 98 private: |
| 99 typedef extensions::URLMatcherCondition |
| 100 (extensions::URLMatcherConditionFactory::* FactoryMethod) |
| 101 (const std::string& prefix); |
| 102 typedef std::map<std::string, FactoryMethod> FactoryMethods; |
| 103 |
| 104 FactoryMethods factory_methods_; |
| 105 |
| 106 DISALLOW_COPY_AND_ASSIGN(URLMatcherConditionFactoryMethods); |
| 107 }; |
| 108 |
| 109 static base::LazyInstance<URLMatcherConditionFactoryMethods> |
| 110 g_url_matcher_condition_factory_methods = LAZY_INSTANCE_INITIALIZER; |
| 111 |
| 112 } // namespace |
| 113 |
| 114 namespace extensions { |
| 115 |
| 116 // |
| 117 // WebRequestCondition |
| 118 // |
| 119 |
| 120 WebRequestCondition::WebRequestCondition( |
| 121 const URLMatcherConditionSet& url_matcher_conditions, |
| 122 const WebRequestConditionAttributes& condition_attributes) |
| 123 : url_matcher_conditions_(url_matcher_conditions), |
| 124 condition_attributes_(condition_attributes) {} |
| 125 |
| 126 WebRequestCondition::~WebRequestCondition() {} |
| 127 |
| 128 bool WebRequestCondition::IsFulfilled(net::URLRequest* request) const { |
| 129 // All condition attributes must be fulfilled for a fulfilled condition. |
| 130 for (WebRequestConditionAttributes::const_iterator i = |
| 131 condition_attributes_.begin(); i != condition_attributes_.end(); ++i) { |
| 132 if (!(*i)->IsFulfilled(request)) |
| 133 return false; |
| 134 } |
| 135 return true; |
| 136 } |
| 137 |
| 138 // static |
| 139 scoped_ptr<WebRequestCondition> WebRequestCondition::Create( |
| 140 URLMatcherConditionFactory* url_matcher_condition_factory, |
| 141 const base::Value& condition, |
| 142 std::string* error) { |
| 143 const base::DictionaryValue* condition_dict = NULL; |
| 144 if (!condition.GetAsDictionary(&condition_dict)) { |
| 145 *error = kExpectedDictionary; |
| 146 return scoped_ptr<WebRequestCondition>(NULL); |
| 147 } |
| 148 |
| 149 // Verify that we are dealing with a Condition whose type we understand. |
| 150 std::string instance_type; |
| 151 if (!condition_dict->GetString(kInstanceType, &instance_type)) { |
| 152 *error = kConditionWithoutInstanceType; |
| 153 return scoped_ptr<WebRequestCondition>(NULL); |
| 154 } |
| 155 if (instance_type != kRequestMatcher) { |
| 156 *error = kExpectedOtherConditionType; |
| 157 return scoped_ptr<WebRequestCondition>(NULL); |
| 158 } |
| 159 |
| 160 WebRequestConditionAttributes attributes; |
| 161 URLMatcherConditionSet::Conditions url_matcher_conditions; |
| 162 |
| 163 for (base::DictionaryValue::Iterator iter(*condition_dict); |
| 164 iter.HasNext(); iter.Advance()) { |
| 165 const std::string& condition_attribute_name = iter.key(); |
| 166 const Value& condition_attribute_value = iter.value(); |
| 167 if (condition_attribute_name == kInstanceType) { |
| 168 // Skip this. |
| 169 } else if (IsURLMatcherConditionAttribute(condition_attribute_name)) { |
| 170 URLMatcherCondition url_matcher_condition = |
| 171 CreateURLMatcherCondition( |
| 172 url_matcher_condition_factory, |
| 173 condition_attribute_name, |
| 174 &condition_attribute_value, |
| 175 error); |
| 176 if (!error->empty()) |
| 177 return scoped_ptr<WebRequestCondition>(NULL); |
| 178 url_matcher_conditions.insert(url_matcher_condition); |
| 179 } else if (WebRequestConditionAttribute::IsKnownType( |
| 180 condition_attribute_name)) { |
| 181 scoped_ptr<WebRequestConditionAttribute> attribute = |
| 182 WebRequestConditionAttribute::Create( |
| 183 condition_attribute_name, |
| 184 &condition_attribute_value, |
| 185 error); |
| 186 if (!error->empty()) |
| 187 return scoped_ptr<WebRequestCondition>(NULL); |
| 188 attributes.push_back(make_linked_ptr(attribute.release())); |
| 189 } else { |
| 190 *error = base::StringPrintf(kUnknownConditionAttribute, |
| 191 condition_attribute_name.c_str()); |
| 192 return scoped_ptr<WebRequestCondition>(NULL); |
| 193 } |
| 194 } |
| 195 |
| 196 // As the URL is the preliminary matching criterion that triggers the tests |
| 197 // for the remaining condition attributes, we insert an empty URL match if |
| 198 // no other url match conditions were specified. Such an empty URL is always |
| 199 // matched. |
| 200 if (url_matcher_conditions.empty()) { |
| 201 url_matcher_conditions.insert( |
| 202 url_matcher_condition_factory->CreateHostPrefixCondition("")); |
| 203 } |
| 204 |
| 205 URLMatcherConditionSet url_matcher_condition_set(++g_next_id, |
| 206 url_matcher_conditions); |
| 207 return scoped_ptr<WebRequestCondition>( |
| 208 new WebRequestCondition(url_matcher_condition_set, attributes)); |
| 209 } |
| 210 |
| 211 // static |
| 212 bool WebRequestCondition::IsURLMatcherConditionAttribute( |
| 213 const std::string& condition_attribute_name) { |
| 214 return g_url_matcher_condition_factory_methods.Get().Contains( |
| 215 condition_attribute_name); |
| 216 } |
| 217 |
| 218 // static |
| 219 URLMatcherCondition WebRequestCondition::CreateURLMatcherCondition( |
| 220 URLMatcherConditionFactory* url_matcher_condition_factory, |
| 221 const std::string& condition_attribute_name, |
| 222 const base::Value* value, |
| 223 std::string* error) { |
| 224 std::string str_value; |
| 225 if (!value->GetAsString(&str_value)) { |
| 226 *error = base::StringPrintf(kConditionExpectedString, |
| 227 condition_attribute_name.c_str()); |
| 228 return URLMatcherCondition(); |
| 229 } |
| 230 return g_url_matcher_condition_factory_methods.Get().Call( |
| 231 url_matcher_condition_factory, condition_attribute_name, str_value); |
| 232 } |
| 233 |
| 234 |
| 235 // |
| 236 // WebRequestConditionSet |
| 237 // |
| 238 |
| 239 WebRequestConditionSet::WebRequestConditionSet( |
| 240 const std::vector<linked_ptr<WebRequestCondition> >& conditions) |
| 241 : conditions_(conditions) { |
| 242 for (Conditions::iterator i = conditions_.begin(); i != conditions_.end(); |
| 243 ++i) { |
| 244 URLMatcherConditionSet::ID trigger_id = |
| 245 (*i)->url_matcher_condition_set_id(); |
| 246 match_triggers_[trigger_id] = i->get(); |
| 247 } |
| 248 } |
| 249 |
| 250 WebRequestConditionSet::~WebRequestConditionSet() {} |
| 251 |
| 252 bool WebRequestConditionSet::IsFulfilled( |
| 253 URLMatcherConditionSet::ID url_match, |
| 254 net::URLRequest* request) const { |
| 255 MatchTriggers::const_iterator trigger = match_triggers_.find(url_match); |
| 256 DCHECK(trigger != match_triggers_.end()); |
| 257 DCHECK_EQ(url_match, trigger->second->url_matcher_condition_set_id()); |
| 258 return trigger->second->IsFulfilled(request); |
| 259 } |
| 260 |
| 261 void WebRequestConditionSet::GetURLMatcherConditionSets( |
| 262 std::vector<URLMatcherConditionSet>* condition_sets) const { |
| 263 for (Conditions::const_iterator i = conditions_.begin(); |
| 264 i != conditions_.end(); ++i) { |
| 265 condition_sets->push_back((*i)->url_matcher_condition_set()); |
| 266 } |
| 267 } |
| 268 |
| 269 // static |
| 270 scoped_ptr<WebRequestConditionSet> WebRequestConditionSet::Create( |
| 271 URLMatcherConditionFactory* url_matcher_condition_factory, |
| 272 const AnyVector& conditions, |
| 273 std::string* error) { |
| 274 std::vector<linked_ptr<WebRequestCondition> > result; |
| 275 |
| 276 for (AnyVector::const_iterator i = conditions.begin(); |
| 277 i != conditions.end(); ++i) { |
| 278 CHECK(i->get()); |
| 279 scoped_ptr<WebRequestCondition> condition = |
| 280 WebRequestCondition::Create(url_matcher_condition_factory, |
| 281 (*i)->value(), error); |
| 282 if (!error->empty()) |
| 283 return scoped_ptr<WebRequestConditionSet>(NULL); |
| 284 result.push_back(make_linked_ptr(condition.release())); |
| 285 } |
| 286 |
| 287 return scoped_ptr<WebRequestConditionSet>(new WebRequestConditionSet(result)); |
| 288 } |
| 289 |
| 290 } // namespace extensions |
OLD | NEW |