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

Unified Diff: chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc

Issue 10923002: Extracting header testing code from WebRequestConditionAttributeResponseHeaders. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Typo in a 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 a0ca0d986ecede3a99c906d0f65bb4f9047af90c..3c686164c69d8753a846bda27318aa61e6d7c3ba 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc
@@ -232,160 +232,128 @@ 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;
-}
+// Manages a set of tests to be applied to name-value pairs representing
+// headers. This is a helper class to header-related condition attributes.
+// It contains a set of test groups. A name-value pair satisfies the whole
+// set of test groups iff it passes at least one test group.
+class TestManager {
+ public:
+ ~TestManager();
+
+ // Creates an instance based on a list |tests| of test groups, encoded as
+ // dictionaries of the type declarativeWebRequest.HeaderFilter (see
+ // declarative_web_request.json).
+ static scoped_ptr<const TestManager> Create(const base::ListValue* tests);
+
+ bool TestNameValue(const std::string& name, const std::string& value) const;
+
+ private:
+ // Represents a single string-matching test.
+ class StringMatchTest {
+ public:
+ enum MatchType { kPrefix, kSuffix, kEquals, kContains };
+
+ StringMatchTest(const std::string& data, MatchType type);
+ ~StringMatchTest();
+
+ // Takes a string to be matched, as a StringValue in |content|, an
+ // indication |is_name_test| of whether the test will be used for matching
+ // against header values or names, and a |match_type|. Never returns NULL,
+ // except for memory failures.
+ static scoped_ptr<const StringMatchTest> Create(const Value* content,
+ bool is_name_test,
+ MatchType match_type);
+
+ // Does |str| pass |*this| StringMatchTest?
+ bool Matches(const std::string& str) const;
+
+ private:
+ const std::string data_;
+ const MatchType type_;
+ DISALLOW_COPY_AND_ASSIGN(StringMatchTest);
+ };
+
+ // Represents a test group -- a set of string matching tests to be applied to
+ // both the header name and value.
+ class HeaderMatchTest {
+ public:
+ // Takes ownership of the content of both |name| and |value|.
+ HeaderMatchTest(ScopedVector<const StringMatchTest>* name,
+ ScopedVector<const StringMatchTest>* value);
+ ~HeaderMatchTest();
+
+ // Gets the test group description in |tests| and creates the corresponding
+ // HeaderMatchTest. On failure returns NULL.
+ static scoped_ptr<const HeaderMatchTest> Create(
+ const base::DictionaryValue* tests);
+
+ // Does the header |name|: |value| match all tests in this header test?
+ bool Matches(const std::string& name, const std::string& value) const;
+
+ private:
+ // Tests to be passed by a header's name.
+ const ScopedVector<const StringMatchTest> name_;
+ // Tests to be passed by a header's value.
+ const ScopedVector<const StringMatchTest> value_;
+ DISALLOW_COPY_AND_ASSIGN(HeaderMatchTest);
+ };
+
+ explicit TestManager(ScopedVector<const HeaderMatchTest>* tests);
+
+ const ScopedVector<const HeaderMatchTest> tests_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestManager);
+};
+
+// TestManager implementation
+TestManager::~TestManager() {}
// 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);
- }
-
+scoped_ptr<const TestManager> TestManager::Create(
+ const base::ListValue* tests) {
ScopedVector<const HeaderMatchTest> header_tests;
- for (ListValue::const_iterator it = value_as_list->begin();
- it != value_as_list->end(); ++it) {
+ for (ListValue::const_iterator it = tests->begin();
+ it != tests->end(); ++it) {
const DictionaryValue* tests = NULL;
- if (!(*it)->GetAsDictionary(&tests)) {
- *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
- return scoped_ptr<WebRequestConditionAttribute>(NULL);
- }
+ if (!(*it)->GetAsDictionary(&tests))
+ return scoped_ptr<const TestManager>(NULL);
scoped_ptr<const HeaderMatchTest> header_test(
- CreateHeaderMatchTest(tests, error));
+ HeaderMatchTest::Create(tests));
if (header_test.get() == NULL)
- return scoped_ptr<WebRequestConditionAttribute>(NULL);
+ return scoped_ptr<const TestManager>(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;
+ return scoped_ptr<const TestManager>(
+ new TestManager(&header_tests));
}
-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_RESPONSE_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;
+bool TestManager::TestNameValue(const std::string& name,
+ const std::string& value) const {
+ for (size_t i = 0; i < tests_.size(); ++i) {
+ if (tests_[i]->Matches(name, value))
+ return true;
}
- // 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;
- }
+TestManager::TestManager(ScopedVector<const HeaderMatchTest>* tests)
+ : tests_(tests->Pass()) {}
- for (size_t i = 0; i < value_.size(); ++i) {
- if (!value_[i]->Matches(value))
- return false;
- }
+// TestManager::HeaderMatchTest implementation.
- return true;
-}
+TestManager::HeaderMatchTest::HeaderMatchTest(
+ ScopedVector<const StringMatchTest>* name,
+ ScopedVector<const StringMatchTest>* value)
+ : name_(name->Pass()),
+ value_(value->Pass()) {}
+TestManager::HeaderMatchTest::~HeaderMatchTest() {}
// static
-scoped_ptr<const WebRequestConditionAttributeResponseHeaders::HeaderMatchTest>
-WebRequestConditionAttributeResponseHeaders::CreateHeaderMatchTest(
- const DictionaryValue* tests,
- std::string* error) {
+scoped_ptr<const TestManager::HeaderMatchTest>
+TestManager::HeaderMatchTest::Create(const base::DictionaryValue* tests) {
ScopedVector<const StringMatchTest> name;
ScopedVector<const StringMatchTest> value;
@@ -393,30 +361,29 @@ WebRequestConditionAttributeResponseHeaders::CreateHeaderMatchTest(
key != tests->end_keys();
++key) {
bool is_name = false; // Is this test for header name?
- MatchType match_type;
+ StringMatchTest::MatchType match_type;
if (*key == keys::kNamePrefixKey) {
is_name = true;
- match_type = kPrefix;
+ match_type = StringMatchTest::kPrefix;
} else if (*key == keys::kNameSuffixKey) {
is_name = true;
- match_type = kSuffix;
+ match_type = StringMatchTest::kSuffix;
} else if (*key == keys::kNameContainsKey) {
is_name = true;
- match_type = kContains;
+ match_type = StringMatchTest::kContains;
} else if (*key == keys::kNameEqualsKey) {
is_name = true;
- match_type = kEquals;
+ match_type = StringMatchTest::kEquals;
} else if (*key == keys::kValuePrefixKey) {
- match_type = kPrefix;
+ match_type = StringMatchTest::kPrefix;
} else if (*key == keys::kValueSuffixKey) {
- match_type = kSuffix;
+ match_type = StringMatchTest::kSuffix;
} else if (*key == keys::kValueContainsKey) {
- match_type = kContains;
+ match_type = StringMatchTest::kContains;
} else if (*key == keys::kValueEqualsKey) {
- match_type = kEquals;
+ match_type = StringMatchTest::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;
@@ -431,19 +398,18 @@ WebRequestConditionAttributeResponseHeaders::CreateHeaderMatchTest(
it != list->end(); ++it) {
ScopedVector<const StringMatchTest>* tests = is_name ? &name : &value;
tests->push_back(
- CreateStringMatchTest(*it, is_name, match_type).release());
+ StringMatchTest::Create(*it, is_name, match_type).release());
}
break;
}
case Value::TYPE_STRING: {
ScopedVector<const StringMatchTest>* tests = is_name ? &name : &value;
tests->push_back(
- CreateStringMatchTest(content, is_name, match_type).release());
+ StringMatchTest::Create(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);
}
}
@@ -452,12 +418,36 @@ WebRequestConditionAttributeResponseHeaders::CreateHeaderMatchTest(
return scoped_ptr<const HeaderMatchTest>(new HeaderMatchTest(&name, &value));
}
+bool TestManager::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;
+}
+
+// TestManager::StringMatchTest implementation.
+
+TestManager::StringMatchTest::StringMatchTest(const std::string& data,
+ MatchType type)
+ : data_(data),
+ type_(type) {}
+
+TestManager::StringMatchTest::~StringMatchTest() {}
+
// static
-scoped_ptr<const WebRequestConditionAttributeResponseHeaders::StringMatchTest>
-WebRequestConditionAttributeResponseHeaders::CreateStringMatchTest(
- const Value* content,
- bool is_name_test,
- MatchType match_type) {
+scoped_ptr<const TestManager::StringMatchTest>
+TestManager::StringMatchTest::Create(const Value* content,
+ bool is_name_test,
+ MatchType match_type) {
std::string str;
CHECK(content->GetAsString(&str));
@@ -468,4 +458,101 @@ WebRequestConditionAttributeResponseHeaders::CreateStringMatchTest(
new StringMatchTest(str, match_type));
}
+bool TestManager::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.
Yoyo Zhou 2012/09/01 19:44:50 I think this is usually in a default: section (as
vabr (Chromium) 2012/09/03 07:37:05 Done.
+ NOTREACHED();
+ return false;
+}
+
+//
+// WebRequestConditionAttributeResponseHeaders
+//
+
+WebRequestConditionAttributeResponseHeaders::
+WebRequestConditionAttributeResponseHeaders(
+ scoped_ptr<const TestManager>* test_manager, bool positive)
+ : test_manager_(test_manager->Pass()),
+ positive_(positive) {}
+
+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);
+ }
+
+ scoped_ptr<const TestManager> test_manager(
+ TestManager::Create(value_as_list));
+ if (test_manager.get() == NULL) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
+ return scoped_ptr<WebRequestConditionAttribute>(NULL);
+ }
+
+ const bool positive = name == keys::kResponseHeadersKey;
+ return scoped_ptr<WebRequestConditionAttribute>(
+ new WebRequestConditionAttributeResponseHeaders(&test_manager, positive));
+}
+
+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_;
+ }
+
+ bool passed = false; // Did some header pass TestNameValue?
+ std::string name;
+ std::string value;
+ void* iter = NULL;
+ while (!passed && headers->EnumerateHeaderLines(&iter, &name, &value)) {
+ StringToLowerASCII(&name); // Header names are case-insensitive.
+ passed |= test_manager_->TestNameValue(name, value);
+ }
+
+ return (positive_ ? passed : !passed);
+}
+
+WebRequestConditionAttribute::Type
+WebRequestConditionAttributeResponseHeaders::GetType() const {
+ return CONDITION_RESPONSE_HEADERS;
+}
+
} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698