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

Unified 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, 4 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc
index 4d825d9e154226af331e555bf84de0a77d9073df..1f619b4e245c889c8c7df867c8c82d6426682d3b 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "base/logging.h"
+#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
@@ -18,6 +19,11 @@
#include "net/http/http_request_headers.h"
#include "net/url_request/url_request.h"
+using base::DictionaryValue;
+using base::ListValue;
+using base::StringValue;
+using base::Value;
+
namespace {
// Error messages.
const char kUnknownConditionAttribute[] = "Unknown matching condition: '*'";
@@ -43,7 +49,9 @@ bool WebRequestConditionAttribute::IsKnownType(
const std::string& instance_type) {
return
WebRequestConditionAttributeResourceType::IsMatchingType(instance_type) ||
- WebRequestConditionAttributeContentType::IsMatchingType(instance_type);
+ WebRequestConditionAttributeContentType::IsMatchingType(instance_type) ||
+ WebRequestConditionAttributeResponseHeaders::IsMatchingType(
+ instance_type);
}
// static
@@ -52,10 +60,15 @@ WebRequestConditionAttribute::Create(
const std::string& name,
const base::Value* value,
std::string* error) {
+ CHECK(value != NULL && error != NULL);
if (WebRequestConditionAttributeResourceType::IsMatchingType(name)) {
return WebRequestConditionAttributeResourceType::Create(name, value, error);
} else if (WebRequestConditionAttributeContentType::IsMatchingType(name)) {
return WebRequestConditionAttributeContentType::Create(name, value, error);
+ } else if (WebRequestConditionAttributeResponseHeaders::IsMatchingType(
+ name)) {
+ return WebRequestConditionAttributeResponseHeaders::Create(
+ name, value, error);
}
*error = ExtensionErrorUtils::FormatErrorMessage(kUnknownConditionAttribute,
@@ -122,7 +135,7 @@ int WebRequestConditionAttributeResourceType::GetStages() const {
}
bool WebRequestConditionAttributeResourceType::IsFulfilled(
- const WebRequestRule::RequestData& request_data) {
+ const WebRequestRule::RequestData& request_data) const {
if (!(request_data.stage & GetStages()))
return false;
const content::ResourceRequestInfo* info =
@@ -193,7 +206,7 @@ int WebRequestConditionAttributeContentType::GetStages() const {
}
bool WebRequestConditionAttributeContentType::IsFulfilled(
- const WebRequestRule::RequestData& request_data) {
+ const WebRequestRule::RequestData& request_data) const {
if (!(request_data.stage & GetStages()))
return false;
std::string content_type;
@@ -219,4 +232,234 @@ WebRequestConditionAttributeContentType::GetType() const {
return CONDITION_CONTENT_TYPE;
}
+//
+// WebRequestConditionAttributeResponseHeaders
+//
+
+WebRequestConditionAttributeResponseHeaders::MatchTest::MatchTest(
+ const std::string& data,
+ MatchType type)
+ : data_(data),
+ type_(type) {}
+
+WebRequestConditionAttributeResponseHeaders::MatchTest::~MatchTest() {}
+
+WebRequestConditionAttributeResponseHeaders::TestGroup::TestGroup(
+ ScopedVector<const MatchTest>* name,
+ ScopedVector<const MatchTest>* value)
+ : name_(name->Pass()),
+ value_(value->Pass()) {}
+
+WebRequestConditionAttributeResponseHeaders::TestGroup::~TestGroup() {}
+
+WebRequestConditionAttributeResponseHeaders::
+WebRequestConditionAttributeResponseHeaders(
+ bool positive_test, ScopedVector<const TestGroup>* tests)
+ : tests_(tests->Pass()),
+ positive_test_(positive_test) {}
+
+WebRequestConditionAttributeResponseHeaders::
+~WebRequestConditionAttributeResponseHeaders() {}
+
+// static
+bool WebRequestConditionAttributeResponseHeaders::IsMatchingType(
+ const std::string& instance_type) {
+ return instance_type == keys::kResponseHeadersKey ||
+ instance_type == keys::kExcludeResponseHeadersKey;
+}
+
+// static
+scoped_ptr<WebRequestConditionAttribute>
+WebRequestConditionAttributeResponseHeaders::Create(
+ const std::string& name,
+ const base::Value* value,
+ std::string* error) {
+ DCHECK(IsMatchingType(name));
+
+ const ListValue* value_as_list = NULL;
+ if (!value->GetAsList(&value_as_list)) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
+ return scoped_ptr<WebRequestConditionAttribute>(NULL);
+ }
+
+ ScopedVector<const TestGroup> groups;
+ for (ListValue::const_iterator it = value_as_list->begin();
+ it != value_as_list->end(); ++it) {
+ const DictionaryValue* tests = NULL;
+ if (!(*it)->GetAsDictionary(&tests)) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
+ return scoped_ptr<WebRequestConditionAttribute>(NULL);
+ }
+
+ scoped_ptr<const TestGroup> group(CreateTests(tests, error));
+ if (group.get() == NULL)
+ return scoped_ptr<WebRequestConditionAttribute>(NULL);
+ groups.push_back(group.release());
+ }
+
+ scoped_ptr<WebRequestConditionAttributeResponseHeaders> result;
+ result.reset(new WebRequestConditionAttributeResponseHeaders(
+ name == keys::kResponseHeadersKey, &groups));
+
+ return result.PassAs<WebRequestConditionAttribute>();
+}
+
+int WebRequestConditionAttributeResponseHeaders::GetStages() const {
+ return ON_HEADERS_RECEIVED;
+}
+
+bool WebRequestConditionAttributeResponseHeaders::IsFulfilled(
+ const WebRequestRule::RequestData& request_data) const {
+ if (!(request_data.stage & GetStages()))
+ return false;
+
+ const net::HttpResponseHeaders* headers =
+ request_data.original_response_headers;
+ if (headers == NULL) {
+ // Each header of an empty set satisfies (the negation of) everything;
+ // OTOH, there is no header to satisfy even the most permissive test.
+ return !positive_test_;
+ }
+
+ // Has some header already passed some test group?
+ bool header_found = false;
+
+ for (size_t i = 0; !header_found && i < tests_.size(); ++i) {
+ std::string name;
+ std::string value;
+
+ for (void* iter = NULL;
+ !header_found && headers->EnumerateHeaderLines(&iter, &name, &value);
+ /* 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.
+ StringToLowerASCII(&name); // Header names are case-insensitive.
+ header_found |= tests_[i]->Matches(name, value);
+ }
+ }
+
+ return (positive_test_ ? header_found : !header_found);
+}
+
+WebRequestConditionAttribute::Type
+WebRequestConditionAttributeResponseHeaders::GetType() const {
+ return CONDITION_REQUEST_HEADERS;
+}
+
+bool WebRequestConditionAttributeResponseHeaders::MatchTest::Matches(
+ const std::string& str) const {
+ switch (type_) {
+ case kPrefix:
+ return StartsWithASCII(str, data_, true /*case_sensitive*/);
+ case kSuffix:
+ return EndsWith(str, data_, true /*case_sensitive*/);
+ case kEquals:
+ return data_ == str;
+ case kContains:
+ return str.find(data_) != std::string::npos;
+ }
+ // We never get past the "switch", but the compiler worries about no return.
+ NOTREACHED();
+ return false;
+}
+
+bool WebRequestConditionAttributeResponseHeaders::TestGroup::Matches(
+ const std::string& name,
+ const std::string& value) const {
+ for (size_t i = 0; i < name_.size(); ++i) {
+ if (!name_[i]->Matches(name))
+ return false;
+ }
+
+ for (size_t i = 0; i < value_.size(); ++i) {
+ if (!value_[i]->Matches(value))
+ return false;
+ }
+
+ return true;
+}
+
+
+// static
+scoped_ptr<const WebRequestConditionAttributeResponseHeaders::TestGroup>
+WebRequestConditionAttributeResponseHeaders::CreateTests(
+ const DictionaryValue* tests,
+ std::string* error) {
+ ScopedVector<const MatchTest> name;
+ ScopedVector<const MatchTest> value;
+
+ for (DictionaryValue::key_iterator key = tests->begin_keys();
+ key != tests->end_keys();
+ ++key) {
+ bool is_name = false; // Is this test for header name?
+ MatchType match_type;
+ if (*key == keys::kNamePrefixKey) {
+ is_name = true;
+ match_type = kPrefix;
+ } else if (*key == keys::kNameSuffixKey) {
+ is_name = true;
+ match_type = kSuffix;
+ } else if (*key == keys::kNameContainsKey) {
+ is_name = true;
+ match_type = kContains;
+ } else if (*key == keys::kNameEqualsKey) {
+ is_name = true;
+ match_type = kEquals;
+ } else if (*key == keys::kValuePrefixKey) {
+ match_type = kPrefix;
+ } else if (*key == keys::kValueSuffixKey) {
+ match_type = kSuffix;
+ } else if (*key == keys::kValueContainsKey) {
+ match_type = kContains;
+ } else if (*key == keys::kValueEqualsKey) {
+ match_type = kEquals;
+ } else {
+ NOTREACHED(); // JSON schema type checking should prevent this.
+ *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, *key);
+ return scoped_ptr<const TestGroup>(NULL);
+ }
+ const Value* content = NULL;
+ // This should not fire, we already checked that |key| is there.
+ CHECK(tests->Get(*key, &content));
+
+ switch (content->GetType()) {
+ case Value::TYPE_LIST: {
+ const ListValue* list = NULL;
+ CHECK(content->GetAsList(&list));
+ for (ListValue::const_iterator it = list->begin();
+ it != list->end(); ++it) {
+ ScopedVector<const MatchTest>* tests = is_name ? &name : &value;
+ tests->push_back(CreateMatchTest(*it, is_name, match_type).release());
+ }
+ break;
+ }
+ case Value::TYPE_STRING: {
+ ScopedVector<const MatchTest>* tests = is_name ? &name : &value;
+ tests->push_back(
+ CreateMatchTest(content, is_name, match_type).release());
+ break;
+ }
+ default: {
+ NOTREACHED(); // JSON schema type checking should prevent this.
+ *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, *key);
+ return scoped_ptr<const TestGroup>(NULL);
+ }
+ }
+ }
+
+ return scoped_ptr<const TestGroup>(new TestGroup(&name, &value));
+}
+
+// static
+scoped_ptr<const WebRequestConditionAttributeResponseHeaders::MatchTest>
+WebRequestConditionAttributeResponseHeaders::CreateMatchTest(
+ const Value* content, bool is_name_test, MatchType match_type) {
+ std::string str;
+
+ CHECK(content->GetAsString(&str));
+ if (is_name_test) // Header names are case-insensitive.
+ StringToLowerASCII(&str);
+
+ return scoped_ptr<const MatchTest>(
+ 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
+}
+
} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698