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

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: 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::StringMatchTest::StringMatchTest(
240 const std::string& data,
241 MatchType type)
242 : data_(data),
243 type_(type) {}
244
245 WebRequestConditionAttributeResponseHeaders::StringMatchTest::~StringMatchTest()
246 {}
247
248 WebRequestConditionAttributeResponseHeaders::HeaderMatchTest::HeaderMatchTest(
249 ScopedVector<const StringMatchTest>* name,
250 ScopedVector<const StringMatchTest>* value)
251 : name_(name->Pass()),
252 value_(value->Pass()) {}
253
254 WebRequestConditionAttributeResponseHeaders::HeaderMatchTest::~HeaderMatchTest()
255 {}
256
257 WebRequestConditionAttributeResponseHeaders::
258 WebRequestConditionAttributeResponseHeaders(
259 bool positive_test, ScopedVector<const HeaderMatchTest>* tests)
260 : tests_(tests->Pass()),
261 positive_test_(positive_test) {}
262
263 WebRequestConditionAttributeResponseHeaders::
264 ~WebRequestConditionAttributeResponseHeaders() {}
265
266 // static
267 bool WebRequestConditionAttributeResponseHeaders::IsMatchingType(
268 const std::string& instance_type) {
269 return instance_type == keys::kResponseHeadersKey ||
270 instance_type == keys::kExcludeResponseHeadersKey;
271 }
272
273 // static
274 scoped_ptr<WebRequestConditionAttribute>
275 WebRequestConditionAttributeResponseHeaders::Create(
276 const std::string& name,
277 const base::Value* value,
278 std::string* error) {
279 DCHECK(IsMatchingType(name));
280
281 const ListValue* value_as_list = NULL;
282 if (!value->GetAsList(&value_as_list)) {
283 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
284 return scoped_ptr<WebRequestConditionAttribute>(NULL);
285 }
286
287 ScopedVector<const HeaderMatchTest> header_tests;
288 for (ListValue::const_iterator it = value_as_list->begin();
289 it != value_as_list->end(); ++it) {
290 const DictionaryValue* tests = NULL;
291 if (!(*it)->GetAsDictionary(&tests)) {
292 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
293 return scoped_ptr<WebRequestConditionAttribute>(NULL);
294 }
295
296 scoped_ptr<const HeaderMatchTest> header_test(CreateTests(tests, error));
297 if (header_test.get() == NULL)
298 return scoped_ptr<WebRequestConditionAttribute>(NULL);
299 header_tests.push_back(header_test.release());
300 }
301
302 scoped_ptr<WebRequestConditionAttributeResponseHeaders> result;
303 result.reset(new WebRequestConditionAttributeResponseHeaders(
304 name == keys::kResponseHeadersKey, &header_tests));
305
306 return result.PassAs<WebRequestConditionAttribute>();
307 }
308
309 int WebRequestConditionAttributeResponseHeaders::GetStages() const {
310 return ON_HEADERS_RECEIVED;
311 }
312
313 bool WebRequestConditionAttributeResponseHeaders::IsFulfilled(
314 const WebRequestRule::RequestData& request_data) const {
315 if (!(request_data.stage & GetStages()))
316 return false;
317
318 const net::HttpResponseHeaders* headers =
319 request_data.original_response_headers;
320 if (headers == NULL) {
321 // Each header of an empty set satisfies (the negation of) everything;
322 // OTOH, there is no header to satisfy even the most permissive test.
323 return !positive_test_;
324 }
325
326 // Has some header already passed some header test?
327 bool header_found = false;
328
329 for (size_t i = 0; !header_found && i < tests_.size(); ++i) {
330 std::string name;
331 std::string value;
332
333 void* iter = NULL;
334 while (!header_found &&
335 headers->EnumerateHeaderLines(&iter, &name, &value)) {
336 StringToLowerASCII(&name); // Header names are case-insensitive.
337 header_found |= tests_[i]->Matches(name, value);
338 }
339 }
340
341 return (positive_test_ ? header_found : !header_found);
342 }
343
344 WebRequestConditionAttribute::Type
345 WebRequestConditionAttributeResponseHeaders::GetType() const {
346 return CONDITION_REQUEST_HEADERS;
347 }
348
349 bool WebRequestConditionAttributeResponseHeaders::StringMatchTest::Matches(
350 const std::string& str) const {
351 switch (type_) {
352 case kPrefix:
353 return StartsWithASCII(str, data_, true /*case_sensitive*/);
354 case kSuffix:
355 return EndsWith(str, data_, true /*case_sensitive*/);
356 case kEquals:
357 return data_ == str;
358 case kContains:
359 return str.find(data_) != std::string::npos;
360 }
361 // We never get past the "switch", but the compiler worries about no return.
362 NOTREACHED();
363 return false;
364 }
365
366 bool WebRequestConditionAttributeResponseHeaders::HeaderMatchTest::Matches(
367 const std::string& name,
368 const std::string& value) const {
369 for (size_t i = 0; i < name_.size(); ++i) {
370 if (!name_[i]->Matches(name))
371 return false;
372 }
373
374 for (size_t i = 0; i < value_.size(); ++i) {
375 if (!value_[i]->Matches(value))
376 return false;
377 }
378
379 return true;
380 }
381
382
383 // static
384 scoped_ptr<const WebRequestConditionAttributeResponseHeaders::HeaderMatchTest>
385 WebRequestConditionAttributeResponseHeaders::CreateTests(
386 const DictionaryValue* tests,
387 std::string* error) {
388 ScopedVector<const StringMatchTest> name;
389 ScopedVector<const StringMatchTest> value;
390
391 for (DictionaryValue::key_iterator key = tests->begin_keys();
392 key != tests->end_keys();
393 ++key) {
394 bool is_name = false; // Is this test for header name?
395 MatchType match_type;
396 if (*key == keys::kNamePrefixKey) {
397 is_name = true;
398 match_type = kPrefix;
399 } else if (*key == keys::kNameSuffixKey) {
400 is_name = true;
401 match_type = kSuffix;
402 } else if (*key == keys::kNameContainsKey) {
403 is_name = true;
404 match_type = kContains;
405 } else if (*key == keys::kNameEqualsKey) {
406 is_name = true;
407 match_type = kEquals;
408 } else if (*key == keys::kValuePrefixKey) {
409 match_type = kPrefix;
410 } else if (*key == keys::kValueSuffixKey) {
411 match_type = kSuffix;
412 } else if (*key == keys::kValueContainsKey) {
413 match_type = kContains;
414 } else if (*key == keys::kValueEqualsKey) {
415 match_type = kEquals;
416 } else {
417 NOTREACHED(); // JSON schema type checking should prevent this.
418 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, *key);
419 return scoped_ptr<const HeaderMatchTest>(NULL);
420 }
421 const Value* content = NULL;
422 // This should not fire, we already checked that |key| is there.
423 CHECK(tests->Get(*key, &content));
424
425 switch (content->GetType()) {
426 case Value::TYPE_LIST: {
427 const ListValue* list = NULL;
428 CHECK(content->GetAsList(&list));
429 for (ListValue::const_iterator it = list->begin();
430 it != list->end(); ++it) {
431 ScopedVector<const StringMatchTest>* tests = is_name ? &name : &value;
432 tests->push_back(CreateMatchTest(*it, is_name, match_type).release());
433 }
434 break;
435 }
436 case Value::TYPE_STRING: {
437 ScopedVector<const StringMatchTest>* tests = is_name ? &name : &value;
438 tests->push_back(
439 CreateMatchTest(content, is_name, match_type).release());
440 break;
441 }
442 default: {
443 NOTREACHED(); // JSON schema type checking should prevent this.
444 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, *key);
445 return scoped_ptr<const HeaderMatchTest>(NULL);
446 }
447 }
448 }
449
450 return scoped_ptr<const HeaderMatchTest>(new HeaderMatchTest(&name, &value));
451 }
452
453 // static
454 scoped_ptr<const WebRequestConditionAttributeResponseHeaders::StringMatchTest>
455 WebRequestConditionAttributeResponseHeaders::CreateMatchTest(
456 const Value* content, bool is_name_test, MatchType match_type) {
457 std::string str;
458
459 CHECK(content->GetAsString(&str));
460 if (is_name_test) // Header names are case-insensitive.
461 StringToLowerASCII(&str);
462
463 return scoped_ptr<const StringMatchTest>(
464 new StringMatchTest(str, match_type));
465 }
466
222 } // namespace extensions 467 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698