Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc

Issue 10874029: Adding condition attributes for response headers to Declarative WebRequest (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: MatchTest constructor also changed to address Dominic's comment Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condit ion_attribute.h" 5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condit ion_attribute.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/string_util.h"
10 #include "base/stringprintf.h" 11 #include "base/stringprintf.h"
11 #include "base/values.h" 12 #include "base/values.h"
12 #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h" 13 #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
13 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_consta nts.h" 14 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_consta nts.h"
14 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" 15 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h"
15 #include "chrome/common/extensions/extension_error_utils.h" 16 #include "chrome/common/extensions/extension_error_utils.h"
16 #include "content/public/browser/resource_request_info.h" 17 #include "content/public/browser/resource_request_info.h"
17 #include "net/http/http_util.h" 18 #include "net/http/http_util.h"
18 #include "net/http/http_request_headers.h" 19 #include "net/http/http_request_headers.h"
19 #include "net/url_request/url_request.h" 20 #include "net/url_request/url_request.h"
20 21
22 using base::DictionaryValue;
23 using base::ListValue;
24 using base::StringValue;
25 using base::Value;
26
21 namespace { 27 namespace {
22 // Error messages. 28 // Error messages.
23 const char kUnknownConditionAttribute[] = "Unknown matching condition: '*'"; 29 const char kUnknownConditionAttribute[] = "Unknown matching condition: '*'";
24 const char kInvalidValue[] = "Condition '*' has an invalid value"; 30 const char kInvalidValue[] = "Condition '*' has an invalid value";
25 } 31 }
26 32
27 namespace helpers = extension_web_request_api_helpers; 33 namespace helpers = extension_web_request_api_helpers;
28 34
29 namespace extensions { 35 namespace extensions {
30 36
31 namespace keys = declarative_webrequest_constants; 37 namespace keys = declarative_webrequest_constants;
32 38
33 // 39 //
34 // WebRequestConditionAttribute 40 // WebRequestConditionAttribute
35 // 41 //
36 42
37 WebRequestConditionAttribute::WebRequestConditionAttribute() {} 43 WebRequestConditionAttribute::WebRequestConditionAttribute() {}
38 44
39 WebRequestConditionAttribute::~WebRequestConditionAttribute() {} 45 WebRequestConditionAttribute::~WebRequestConditionAttribute() {}
40 46
41 // static 47 // static
42 bool WebRequestConditionAttribute::IsKnownType( 48 bool WebRequestConditionAttribute::IsKnownType(
43 const std::string& instance_type) { 49 const std::string& instance_type) {
44 return 50 return
45 WebRequestConditionAttributeResourceType::IsMatchingType(instance_type) || 51 WebRequestConditionAttributeResourceType::IsMatchingType(instance_type) ||
46 WebRequestConditionAttributeContentType::IsMatchingType(instance_type); 52 WebRequestConditionAttributeContentType::IsMatchingType(instance_type) ||
53 WebRequestConditionAttributeResponseHeaders::IsMatchingType(
54 instance_type);
47 } 55 }
48 56
49 // static 57 // static
50 scoped_ptr<WebRequestConditionAttribute> 58 scoped_ptr<WebRequestConditionAttribute>
51 WebRequestConditionAttribute::Create( 59 WebRequestConditionAttribute::Create(
52 const std::string& name, 60 const std::string& name,
53 const base::Value* value, 61 const base::Value* value,
54 std::string* error) { 62 std::string* error) {
63 CHECK(value != NULL && error != NULL);
55 if (WebRequestConditionAttributeResourceType::IsMatchingType(name)) { 64 if (WebRequestConditionAttributeResourceType::IsMatchingType(name)) {
56 return WebRequestConditionAttributeResourceType::Create(name, value, error); 65 return WebRequestConditionAttributeResourceType::Create(name, value, error);
57 } else if (WebRequestConditionAttributeContentType::IsMatchingType(name)) { 66 } else if (WebRequestConditionAttributeContentType::IsMatchingType(name)) {
58 return WebRequestConditionAttributeContentType::Create(name, value, error); 67 return WebRequestConditionAttributeContentType::Create(name, value, error);
68 } else if (WebRequestConditionAttributeResponseHeaders::IsMatchingType(
69 name)) {
70 return WebRequestConditionAttributeResponseHeaders::Create(
71 name, value, error);
59 } 72 }
60 73
61 *error = ExtensionErrorUtils::FormatErrorMessage(kUnknownConditionAttribute, 74 *error = ExtensionErrorUtils::FormatErrorMessage(kUnknownConditionAttribute,
62 name); 75 name);
63 return scoped_ptr<WebRequestConditionAttribute>(NULL); 76 return scoped_ptr<WebRequestConditionAttribute>(NULL);
64 } 77 }
65 78
66 // 79 //
67 // WebRequestConditionAttributeResourceType 80 // WebRequestConditionAttributeResourceType
68 // 81 //
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 new WebRequestConditionAttributeResourceType(passed_types)); 128 new WebRequestConditionAttributeResourceType(passed_types));
116 } 129 }
117 130
118 int WebRequestConditionAttributeResourceType::GetStages() const { 131 int WebRequestConditionAttributeResourceType::GetStages() const {
119 return ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS | ON_SEND_HEADERS | 132 return ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS | ON_SEND_HEADERS |
120 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED | ON_BEFORE_REDIRECT | 133 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED | ON_BEFORE_REDIRECT |
121 ON_RESPONSE_STARTED | ON_COMPLETED | ON_ERROR; 134 ON_RESPONSE_STARTED | ON_COMPLETED | ON_ERROR;
122 } 135 }
123 136
124 bool WebRequestConditionAttributeResourceType::IsFulfilled( 137 bool WebRequestConditionAttributeResourceType::IsFulfilled(
125 const WebRequestRule::RequestData& request_data) { 138 const WebRequestRule::RequestData& request_data) const {
126 if (!(request_data.stage & GetStages())) 139 if (!(request_data.stage & GetStages()))
127 return false; 140 return false;
128 const content::ResourceRequestInfo* info = 141 const content::ResourceRequestInfo* info =
129 content::ResourceRequestInfo::ForRequest(request_data.request); 142 content::ResourceRequestInfo::ForRequest(request_data.request);
130 if (!info) 143 if (!info)
131 return false; 144 return false;
132 return std::find(types_.begin(), types_.end(), info->GetResourceType()) != 145 return std::find(types_.begin(), types_.end(), info->GetResourceType()) !=
133 types_.end(); 146 types_.end();
134 } 147 }
135 148
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 return scoped_ptr<WebRequestConditionAttribute>( 199 return scoped_ptr<WebRequestConditionAttribute>(
187 new WebRequestConditionAttributeContentType( 200 new WebRequestConditionAttributeContentType(
188 content_types, name == keys::kContentTypeKey)); 201 content_types, name == keys::kContentTypeKey));
189 } 202 }
190 203
191 int WebRequestConditionAttributeContentType::GetStages() const { 204 int WebRequestConditionAttributeContentType::GetStages() const {
192 return ON_HEADERS_RECEIVED; 205 return ON_HEADERS_RECEIVED;
193 } 206 }
194 207
195 bool WebRequestConditionAttributeContentType::IsFulfilled( 208 bool WebRequestConditionAttributeContentType::IsFulfilled(
196 const WebRequestRule::RequestData& request_data) { 209 const WebRequestRule::RequestData& request_data) const {
197 if (!(request_data.stage & GetStages())) 210 if (!(request_data.stage & GetStages()))
198 return false; 211 return false;
199 std::string content_type; 212 std::string content_type;
200 request_data.original_response_headers->GetNormalizedHeader( 213 request_data.original_response_headers->GetNormalizedHeader(
201 net::HttpRequestHeaders::kContentType, &content_type); 214 net::HttpRequestHeaders::kContentType, &content_type);
202 std::string mime_type; 215 std::string mime_type;
203 std::string charset; 216 std::string charset;
204 bool had_charset = false; 217 bool had_charset = false;
205 net::HttpUtil::ParseContentType( 218 net::HttpUtil::ParseContentType(
206 content_type, &mime_type, &charset, &had_charset, NULL); 219 content_type, &mime_type, &charset, &had_charset, NULL);
207 220
208 if (inclusive_) { 221 if (inclusive_) {
209 return std::find(content_types_.begin(), content_types_.end(), 222 return std::find(content_types_.begin(), content_types_.end(),
210 mime_type) != content_types_.end(); 223 mime_type) != content_types_.end();
211 } else { 224 } else {
212 return std::find(content_types_.begin(), content_types_.end(), 225 return std::find(content_types_.begin(), content_types_.end(),
213 mime_type) == content_types_.end(); 226 mime_type) == content_types_.end();
214 } 227 }
215 } 228 }
216 229
217 WebRequestConditionAttribute::Type 230 WebRequestConditionAttribute::Type
218 WebRequestConditionAttributeContentType::GetType() const { 231 WebRequestConditionAttributeContentType::GetType() const {
219 return CONDITION_CONTENT_TYPE; 232 return CONDITION_CONTENT_TYPE;
220 } 233 }
221 234
235 //
236 // WebRequestConditionAttributeResponseHeaders
237 //
238
239 WebRequestConditionAttributeResponseHeaders::MatchTest::MatchTest(
240 const std::string& data,
241 MatchType type)
242 : data_(data),
243 type_(type) {}
244
245 WebRequestConditionAttributeResponseHeaders::MatchTest::~MatchTest() {}
246
247 WebRequestConditionAttributeResponseHeaders::TestGroup::TestGroup(
248 ScopedVector<const MatchTest>* name,
249 ScopedVector<const MatchTest>* value)
250 : name_(name->Pass()),
251 value_(value->Pass()) {}
252
253 WebRequestConditionAttributeResponseHeaders::TestGroup::~TestGroup() {}
254
255 WebRequestConditionAttributeResponseHeaders::
256 WebRequestConditionAttributeResponseHeaders(
257 bool positive_test, ScopedVector<const TestGroup>* tests)
258 : tests_(tests->Pass()),
259 positive_test_(positive_test) {}
260
261 WebRequestConditionAttributeResponseHeaders::
262 ~WebRequestConditionAttributeResponseHeaders() {}
263
264 // static
265 bool WebRequestConditionAttributeResponseHeaders::IsMatchingType(
266 const std::string& instance_type) {
267 return instance_type == keys::kResponseHeadersKey ||
268 instance_type == keys::kExcludeResponseHeadersKey;
269 }
270
271 // static
272 scoped_ptr<WebRequestConditionAttribute>
273 WebRequestConditionAttributeResponseHeaders::Create(
274 const std::string& name,
275 const base::Value* value,
276 std::string* error) {
277 DCHECK(IsMatchingType(name));
278
279 const ListValue* value_as_list = NULL;
280 if (!value->GetAsList(&value_as_list)) {
281 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
282 return scoped_ptr<WebRequestConditionAttribute>(NULL);
283 }
284
285 ScopedVector<const TestGroup> groups;
286 for (ListValue::const_iterator it = value_as_list->begin();
287 it != value_as_list->end(); ++it) {
288 const DictionaryValue* tests = NULL;
289 if (!(*it)->GetAsDictionary(&tests)) {
290 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
291 return scoped_ptr<WebRequestConditionAttribute>(NULL);
292 }
293
294 scoped_ptr<const TestGroup> group(CreateTests(tests, error));
295 if (group.get() == NULL)
296 return scoped_ptr<WebRequestConditionAttribute>(NULL);
297 groups.push_back(group.release());
298 }
299
300 scoped_ptr<WebRequestConditionAttributeResponseHeaders> result;
301 result.reset(new WebRequestConditionAttributeResponseHeaders(
302 name == keys::kResponseHeadersKey, &groups));
303
304 return result.PassAs<WebRequestConditionAttribute>();
305 }
306
307 int WebRequestConditionAttributeResponseHeaders::GetStages() const {
308 return ON_HEADERS_RECEIVED;
309 }
310
311 bool WebRequestConditionAttributeResponseHeaders::IsFulfilled(
312 const WebRequestRule::RequestData& request_data) const {
313 if (!(request_data.stage & GetStages()))
314 return false;
315
316 const net::HttpResponseHeaders* headers =
317 request_data.original_response_headers;
318 if (headers == NULL) {
319 // Each header of an empty set satisfies (the negation of) everything;
320 // OTOH, there is no header to satisfy even the most permissive test.
321 return !positive_test_;
322 }
323
324 // Has some header already passed some test group?
325 bool header_found = false;
326
327 for (size_t i = 0; !header_found && i < tests_.size(); ++i) {
328 std::string name;
329 std::string value;
330
331 for (void* iter = NULL;
332 !header_found && headers->EnumerateHeaderLines(&iter, &name, &value);
333 /* No increment here, this is done inside EnumerateHeaderLines. */) {
battre 2012/08/27 17:16:25 opt: void* iter = NULL; while (!header_found && he
vabr (Chromium) 2012/08/28 17:59:09 Done.
334 StringToLowerASCII(&name); // Header names are case-insensitive.
335 header_found |= tests_[i]->Matches(name, value);
336 }
337 }
338
339 return (positive_test_ ? header_found : !header_found);
340 }
341
342 WebRequestConditionAttribute::Type
343 WebRequestConditionAttributeResponseHeaders::GetType() const {
344 return CONDITION_REQUEST_HEADERS;
345 }
346
347 bool WebRequestConditionAttributeResponseHeaders::MatchTest::Matches(
348 const std::string& str) const {
349 switch (type_) {
350 case kPrefix:
351 return StartsWithASCII(str, data_, true /*case_sensitive*/);
352 case kSuffix:
353 return EndsWith(str, data_, true /*case_sensitive*/);
354 case kEquals:
355 return data_ == str;
356 case kContains:
357 return str.find(data_) != std::string::npos;
358 }
359 // We never get past the "switch", but the compiler worries about no return.
360 NOTREACHED();
361 return false;
362 }
363
364 bool WebRequestConditionAttributeResponseHeaders::TestGroup::Matches(
365 const std::string& name,
366 const std::string& value) const {
367 for (size_t i = 0; i < name_.size(); ++i) {
368 if (!name_[i]->Matches(name))
369 return false;
370 }
371
372 for (size_t i = 0; i < value_.size(); ++i) {
373 if (!value_[i]->Matches(value))
374 return false;
375 }
376
377 return true;
378 }
379
380
381 // static
382 scoped_ptr<const WebRequestConditionAttributeResponseHeaders::TestGroup>
383 WebRequestConditionAttributeResponseHeaders::CreateTests(
384 const DictionaryValue* tests,
385 std::string* error) {
386 ScopedVector<const MatchTest> name;
387 ScopedVector<const MatchTest> value;
388
389 for (DictionaryValue::key_iterator key = tests->begin_keys();
390 key != tests->end_keys();
391 ++key) {
392 bool is_name = false; // Is this test for header name?
393 MatchType match_type;
394 if (*key == keys::kNamePrefixKey) {
395 is_name = true;
396 match_type = kPrefix;
397 } else if (*key == keys::kNameSuffixKey) {
398 is_name = true;
399 match_type = kSuffix;
400 } else if (*key == keys::kNameContainsKey) {
401 is_name = true;
402 match_type = kContains;
403 } else if (*key == keys::kNameEqualsKey) {
404 is_name = true;
405 match_type = kEquals;
406 } else if (*key == keys::kValuePrefixKey) {
407 match_type = kPrefix;
408 } else if (*key == keys::kValueSuffixKey) {
409 match_type = kSuffix;
410 } else if (*key == keys::kValueContainsKey) {
411 match_type = kContains;
412 } else if (*key == keys::kValueEqualsKey) {
413 match_type = kEquals;
414 } else {
415 NOTREACHED(); // JSON schema type checking should prevent this.
416 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, *key);
417 return scoped_ptr<const TestGroup>(NULL);
418 }
419 const Value* content = NULL;
420 // This should not fire, we already checked that |key| is there.
421 CHECK(tests->Get(*key, &content));
422
423 switch (content->GetType()) {
424 case Value::TYPE_LIST: {
425 const ListValue* list = NULL;
426 CHECK(content->GetAsList(&list));
427 for (ListValue::const_iterator it = list->begin();
428 it != list->end(); ++it) {
429 ScopedVector<const MatchTest>* tests = is_name ? &name : &value;
430 tests->push_back(CreateMatchTest(*it, is_name, match_type).release());
431 }
432 break;
433 }
434 case Value::TYPE_STRING: {
435 ScopedVector<const MatchTest>* tests = is_name ? &name : &value;
436 tests->push_back(
437 CreateMatchTest(content, is_name, match_type).release());
438 break;
439 }
440 default: {
441 NOTREACHED(); // JSON schema type checking should prevent this.
442 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, *key);
443 return scoped_ptr<const TestGroup>(NULL);
444 }
445 }
446 }
447
448 return scoped_ptr<const TestGroup>(new TestGroup(&name, &value));
449 }
450
451 // static
452 scoped_ptr<const WebRequestConditionAttributeResponseHeaders::MatchTest>
453 WebRequestConditionAttributeResponseHeaders::CreateMatchTest(
454 const Value* content, bool is_name_test, MatchType match_type) {
455 std::string str;
456
457 CHECK(content->GetAsString(&str));
458 if (is_name_test) // Header names are case-insensitive.
459 StringToLowerASCII(&str);
460
461 return scoped_ptr<const MatchTest>(
462 new MatchTest(str, match_type));
battre 2012/08/27 17:16:25 nit: single line
vabr (Chromium) 2012/08/28 17:59:09 Does not fit any more after renaming MatchTest to
463 }
464
222 } // namespace extensions 465 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698