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

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: Corrected indenting, clarified comments and some names 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..df6b0d447f6e6cd5b36e3c61f2e366a3e7e968c3 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc
@@ -232,122 +232,144 @@ 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() {}
+// 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 HeaderMatcher {
+ public:
+ ~HeaderMatcher();
+
+ // 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 HeaderMatcher> Create(const base::ListValue* tests);
+
+ // Does |this| match the header "|name|: |value|"?
+ 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);
battre 2012/09/03 08:46:47 You can do this in a separate CL, but I think we c
vabr (Chromium) 2012/09/03 10:12:36 I thought about this before, but decided against i
battre 2012/09/03 12:48:08 My thoughts were from the perspective of somebody
vabr (Chromium) 2012/09/03 14:21:29 I agree with both points. StringToLowerASCII is no
+
+ // 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:
+ ~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|?
+ bool Matches(const std::string& name, const std::string& value) const;
+
+ private:
+ // Takes ownership of the content of both |name_match| and |value_match|.
+ HeaderMatchTest(ScopedVector<const StringMatchTest>* name_match,
+ ScopedVector<const StringMatchTest>* value_match);
+
+ // Tests to be passed by a header's name.
+ const ScopedVector<const StringMatchTest> name_match_;
+ // Tests to be passed by a header's value.
+ const ScopedVector<const StringMatchTest> value_match_;
+ DISALLOW_COPY_AND_ASSIGN(HeaderMatchTest);
+ };
+
+ explicit HeaderMatcher(ScopedVector<const HeaderMatchTest>* tests);
+
+ const ScopedVector<const HeaderMatchTest> tests_;
+
+ DISALLOW_COPY_AND_ASSIGN(HeaderMatcher);
+};
+
+// HeaderMatcher implementation.
+
+HeaderMatcher::~HeaderMatcher() {}
// 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 HeaderMatcher> HeaderMatcher::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 HeaderMatcher>(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 HeaderMatcher>(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>();
+ return scoped_ptr<const HeaderMatcher>(
+ new HeaderMatcher(&header_tests));
battre 2012/09/03 08:46:47 nit: single line
vabr (Chromium) 2012/09/03 10:12:36 Done.
}
-int WebRequestConditionAttributeResponseHeaders::GetStages() const {
- return ON_HEADERS_RECEIVED;
+bool HeaderMatcher::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;
+ }
+ return false;
}
-bool WebRequestConditionAttributeResponseHeaders::IsFulfilled(
- const WebRequestRule::RequestData& request_data) const {
- if (!(request_data.stage & GetStages()))
- return false;
+HeaderMatcher::HeaderMatcher(ScopedVector<const HeaderMatchTest>* tests)
+ : tests_(tests->Pass()) {}
- 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_;
- }
+// HeaderMatcher::StringMatchTest implementation.
- // Has some header already passed some header test?
- bool header_found = false;
+HeaderMatcher::StringMatchTest::StringMatchTest(const std::string& data,
+ MatchType type)
+ : data_(data),
+ type_(type) {}
- for (size_t i = 0; !header_found && i < tests_.size(); ++i) {
- std::string name;
- std::string value;
+HeaderMatcher::StringMatchTest::~StringMatchTest() {}
- 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);
- }
- }
+// static
+scoped_ptr<const HeaderMatcher::StringMatchTest>
+HeaderMatcher::StringMatchTest::Create(const Value* content,
+ bool is_name_test,
+ MatchType match_type) {
+ std::string str;
- return (positive_test_ ? header_found : !header_found);
-}
+ CHECK(content->GetAsString(&str));
+ // Header names are case-insensitive, we match them in lowercase.
+ if (is_name_test)
+ StringToLowerASCII(&str);
-WebRequestConditionAttribute::Type
-WebRequestConditionAttributeResponseHeaders::GetType() const {
- return CONDITION_RESPONSE_HEADERS;
+ return scoped_ptr<const StringMatchTest>(
+ new StringMatchTest(str, match_type));
}
-bool WebRequestConditionAttributeResponseHeaders::StringMatchTest::Matches(
+bool HeaderMatcher::StringMatchTest::Matches(
const std::string& str) const {
switch (type_) {
case kPrefix:
@@ -358,65 +380,56 @@ bool WebRequestConditionAttributeResponseHeaders::StringMatchTest::Matches(
return data_ == str;
case kContains:
return str.find(data_) != std::string::npos;
+ default:
+ // We never go here, all cases done above. Just to silence the compiler.
+ NOTREACHED();
+ return false;
battre 2012/09/03 08:46:47 I disagree with this change. This makes the compil
vabr (Chromium) 2012/09/03 10:12:36 You're right, reverted. I guess I need to learn to
}
- // 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;
- }
+// HeaderMatcher::HeaderMatchTest implementation.
- for (size_t i = 0; i < value_.size(); ++i) {
- if (!value_[i]->Matches(value))
- return false;
- }
-
- return true;
-}
+HeaderMatcher::HeaderMatchTest::HeaderMatchTest(
+ ScopedVector<const StringMatchTest>* name_match,
+ ScopedVector<const StringMatchTest>* value_match)
+ : name_match_(name_match->Pass()),
+ value_match_(value_match->Pass()) {}
+HeaderMatcher::HeaderMatchTest::~HeaderMatchTest() {}
// static
-scoped_ptr<const WebRequestConditionAttributeResponseHeaders::HeaderMatchTest>
-WebRequestConditionAttributeResponseHeaders::CreateHeaderMatchTest(
- const DictionaryValue* tests,
- std::string* error) {
- ScopedVector<const StringMatchTest> name;
- ScopedVector<const StringMatchTest> value;
+scoped_ptr<const HeaderMatcher::HeaderMatchTest>
+HeaderMatcher::HeaderMatchTest::Create(const base::DictionaryValue* tests) {
+ ScopedVector<const StringMatchTest> name_match;
+ ScopedVector<const StringMatchTest> value_match;
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;
+ 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);
battre 2012/09/03 08:46:47 why did you remove this?
vabr (Chromium) 2012/09/03 10:12:36 In all situations where creating a HeaderMatchTest
battre 2012/09/03 12:48:08 Thanks. Makes sense.
return scoped_ptr<const HeaderMatchTest>(NULL);
}
const Value* content = NULL;
@@ -429,43 +442,125 @@ WebRequestConditionAttributeResponseHeaders::CreateHeaderMatchTest(
CHECK(content->GetAsList(&list));
for (ListValue::const_iterator it = list->begin();
it != list->end(); ++it) {
- ScopedVector<const StringMatchTest>* tests = is_name ? &name : &value;
+ ScopedVector<const StringMatchTest>* tests =
+ is_name ? &name_match : &value_match;
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;
+ ScopedVector<const StringMatchTest>* tests =
+ is_name ? &name_match : &value_match;
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);
battre 2012/09/03 08:46:47 why did you remove this?
vabr (Chromium) 2012/09/03 10:12:36 Please see above the explanation for HeaderMatchTe
return scoped_ptr<const HeaderMatchTest>(NULL);
}
}
}
- return scoped_ptr<const HeaderMatchTest>(new HeaderMatchTest(&name, &value));
+ return scoped_ptr<const HeaderMatchTest>(
+ new HeaderMatchTest(&name_match, &value_match));
}
+bool HeaderMatcher::HeaderMatchTest::Matches(const std::string& name,
+ const std::string& value) const {
+ for (size_t i = 0; i < name_match_.size(); ++i) {
+ if (!name_match_[i]->Matches(name))
+ return false;
+ }
+
+ for (size_t i = 0; i < value_match_.size(); ++i) {
+ if (!value_match_[i]->Matches(value))
+ return false;
+ }
+
+ return true;
+}
+
+//
+// WebRequestConditionAttributeResponseHeaders
+//
+
+WebRequestConditionAttributeResponseHeaders::
+WebRequestConditionAttributeResponseHeaders(
+ scoped_ptr<const HeaderMatcher>* header_matcher, bool positive)
battre 2012/09/03 08:46:47 nit: bool positive goes into next line (either all
vabr (Chromium) 2012/09/03 10:12:36 Done.
+ : header_matcher_(header_matcher->Pass()),
+ positive_(positive) {}
+
+WebRequestConditionAttributeResponseHeaders::
+~WebRequestConditionAttributeResponseHeaders() {}
+
// static
-scoped_ptr<const WebRequestConditionAttributeResponseHeaders::StringMatchTest>
-WebRequestConditionAttributeResponseHeaders::CreateStringMatchTest(
- const Value* content,
- bool is_name_test,
- MatchType match_type) {
- std::string str;
+bool WebRequestConditionAttributeResponseHeaders::IsMatchingType(
+ const std::string& instance_type) {
+ return instance_type == keys::kResponseHeadersKey ||
+ instance_type == keys::kExcludeResponseHeadersKey;
+}
- CHECK(content->GetAsString(&str));
- if (is_name_test) // Header names are case-insensitive.
- StringToLowerASCII(&str);
+// static
+scoped_ptr<WebRequestConditionAttribute>
+WebRequestConditionAttributeResponseHeaders::Create(
+ const std::string& name,
+ const base::Value* value,
+ std::string* error) {
+ DCHECK(IsMatchingType(name));
- return scoped_ptr<const StringMatchTest>(
- new StringMatchTest(str, match_type));
+ 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 HeaderMatcher> header_matcher(
+ HeaderMatcher::Create(value_as_list));
+ if (header_matcher.get() == NULL) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
+ return scoped_ptr<WebRequestConditionAttribute>(NULL);
+ }
+
+ const bool positive = name == keys::kResponseHeadersKey;
battre 2012/09/03 08:46:47 nit: no need for const
vabr (Chromium) 2012/09/03 10:12:36 I disagree. I want to document that |positive| is
battre 2012/09/03 12:48:08 I think the downside is the additional amount of c
+ return scoped_ptr<WebRequestConditionAttribute>(
+ new WebRequestConditionAttributeResponseHeaders(
+ &header_matcher, 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 |= header_matcher_->TestNameValue(name, value);
+ }
+
+ return (positive_ ? passed : !passed);
+}
+
+WebRequestConditionAttribute::Type
+WebRequestConditionAttributeResponseHeaders::GetType() const {
+ return CONDITION_RESPONSE_HEADERS;
}
} // namespace extensions
« no previous file with comments | « chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698