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

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: 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..bd95cec8622b1aeb0ca6b282e42c92982ca3c013 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,236 @@ WebRequestConditionAttributeContentType::GetType() const {
return CONDITION_CONTENT_TYPE;
}
+//
+// WebRequestConditionAttributeResponseHeaders
+//
+
+WebRequestConditionAttributeResponseHeaders::StringMatchTest::StringMatchTest(
+ const std::string& data,
+ MatchType type)
+ : data_(data),
+ type_(type) {}
+
+WebRequestConditionAttributeResponseHeaders::StringMatchTest::~StringMatchTest()
+{}
+
+WebRequestConditionAttributeResponseHeaders::HeaderMatchTest::HeaderMatchTest(
+ ScopedVector<const StringMatchTest>* name,
+ ScopedVector<const StringMatchTest>* value)
+ : name_(name->Pass()),
+ value_(value->Pass()) {}
+
+WebRequestConditionAttributeResponseHeaders::HeaderMatchTest::~HeaderMatchTest()
+{}
+
+WebRequestConditionAttributeResponseHeaders::
+WebRequestConditionAttributeResponseHeaders(
+ bool positive_test, ScopedVector<const HeaderMatchTest>* 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 HeaderMatchTest> header_tests;
+ 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 HeaderMatchTest> header_test(CreateTests(tests, error));
+ if (header_test.get() == NULL)
+ return scoped_ptr<WebRequestConditionAttribute>(NULL);
+ header_tests.push_back(header_test.release());
+ }
+
+ scoped_ptr<WebRequestConditionAttributeResponseHeaders> result;
+ result.reset(new WebRequestConditionAttributeResponseHeaders(
+ name == keys::kResponseHeadersKey, &header_tests));
+
+ 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 header test?
+ bool header_found = false;
+
+ for (size_t i = 0; !header_found && i < tests_.size(); ++i) {
+ std::string name;
+ std::string value;
+
+ void* iter = NULL;
+ while (!header_found &&
+ headers->EnumerateHeaderLines(&iter, &name, &value)) {
+ 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::StringMatchTest::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::HeaderMatchTest::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::HeaderMatchTest>
+WebRequestConditionAttributeResponseHeaders::CreateTests(
+ const DictionaryValue* tests,
+ std::string* error) {
+ ScopedVector<const StringMatchTest> name;
+ ScopedVector<const StringMatchTest> 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 HeaderMatchTest>(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 StringMatchTest>* tests = is_name ? &name : &value;
+ tests->push_back(CreateMatchTest(*it, is_name, match_type).release());
+ }
+ break;
+ }
+ case Value::TYPE_STRING: {
+ ScopedVector<const StringMatchTest>* 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 HeaderMatchTest>(NULL);
+ }
+ }
+ }
+
+ return scoped_ptr<const HeaderMatchTest>(new HeaderMatchTest(&name, &value));
+}
+
+// static
+scoped_ptr<const WebRequestConditionAttributeResponseHeaders::StringMatchTest>
+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 StringMatchTest>(
+ new StringMatchTest(str, match_type));
+}
+
} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698