diff options
22 files changed, 1156 insertions, 771 deletions
diff --git a/chrome/browser/extensions/api/declarative/declarative_rule.h b/chrome/browser/extensions/api/declarative/declarative_rule.h new file mode 100644 index 0000000..703ca34 --- /dev/null +++ b/chrome/browser/extensions/api/declarative/declarative_rule.h @@ -0,0 +1,492 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DeclarativeRule<>, DeclarativeConditionSet<>, and DeclarativeActionSet<> +// templates usable with multiple different declarativeFoo systems. These are +// templated on the Condition and Action types that define the behavior of a +// particular declarative event. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DECLARATIVE_RULE_H__ +#define CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DECLARATIVE_RULE_H__ + +#include <limits> + +#include "base/memory/linked_ptr.h" +#include "base/memory/scoped_vector.h" +#include "base/time.h" +#include "chrome/common/extensions/api/events.h" +#include "chrome/common/extensions/matcher/url_matcher.h" + +namespace base { +class Time; +} + +namespace extensions { + +// This class stores a set of conditions that may be part of a DeclarativeRule. +// If any condition is fulfilled, the Actions of the DeclarativeRule can be +// triggered. +// +// ConditionT should be immutable after creation. It must define the following +// members: +// +// // Arguments passed through from ConditionSet::Create. +// static scoped_ptr<ConditionT> Create( +// URLMatcherConditionFactory*, +// // Except this argument gets elements of the AnyVector. +// const base::Value& definition, +// std::string* error); +// // If the Condition needs to be filtered by some +// // URLMatcherConditionSets, append them to this argument. +// // DeclarativeConditionSet::GetURLMatcherConditionSets forwards here. +// void GetURLMatcherConditionSets( +// URLMatcherConditionSet::Vector* condition_sets) +// // True if GetURLMatcherConditionSets would append anything to its +// // argument. +// bool has_url_matcher_condition_set(); +// // |url_matches| and |match_data| passed through from +// // ConditionSet::IsFulfilled. +// bool IsFulfilled( +// const std::set<URLMatcherConditionSet::ID>& url_matches, +// const ConditionT::MatchData&); +template<typename ConditionT> +class DeclarativeConditionSet { + public: + typedef std::vector<linked_ptr<json_schema_compiler::any::Any> > AnyVector; + typedef std::vector<linked_ptr<const ConditionT> > Conditions; + typedef typename Conditions::const_iterator const_iterator; + + // Factory method that creates an WebRequestConditionSet according to the JSON + // array |conditions| passed by the extension API. + // Sets |error| and returns NULL in case of an error. + static scoped_ptr<DeclarativeConditionSet> Create( + URLMatcherConditionFactory* url_matcher_condition_factory, + const AnyVector& conditions, + std::string* error); + + const Conditions& conditions() const { + return conditions_; + } + + const_iterator begin() const { return conditions_.begin(); } + const_iterator end() const { return conditions_.end(); } + + // If |url_match_trigger| is a member of |url_matches|, then this + // returns whether the corresponding condition is fulfilled + // wrt. |request_data|. If |url_match_trigger| is -1, this function + // returns whether any of the conditions without URL attributes is + // satisfied. + // + // Conditions for which has_url_matcher_condition_set() is false are always + // checked (aside from short-circuiting when an earlier condition already + // matched.) + // + // Conditions for which has_url_matcher_condition_set() is true are only + // checked if one of the URLMatcherConditionSets returned by + // GetURLMatcherConditionSets() has an id listed in url_matches. That means + // that if |match_data| contains URL matches for two pieces of a request, + // their union should appear in |url_matches|. For kinds of MatchData that + // only have one type of URL, |url_matches| is forwarded on to + // ConditionT::IsFulfilled(), so it doesn't need to appear in |match_data|. + bool IsFulfilled(URLMatcherConditionSet::ID url_match_trigger, + const std::set<URLMatcherConditionSet::ID>& url_matches, + const typename ConditionT::MatchData& match_data) const; + + // Appends the URLMatcherConditionSet from all conditions to |condition_sets|. + void GetURLMatcherConditionSets( + URLMatcherConditionSet::Vector* condition_sets) const; + + // Returns whether there are some conditions without UrlFilter attributes. + bool HasConditionsWithoutUrls() const { + return !conditions_without_urls_.empty(); + } + + private: + typedef std::map<URLMatcherConditionSet::ID, const ConditionT*> + URLMatcherIdToCondition; + + DeclarativeConditionSet( + const Conditions& conditions, + const URLMatcherIdToCondition& match_id_to_condition, + const std::vector<const ConditionT*>& conditions_without_urls); + + const URLMatcherIdToCondition match_id_to_condition_; + const Conditions conditions_; + const std::vector<const ConditionT*> conditions_without_urls_; + + DISALLOW_COPY_AND_ASSIGN(DeclarativeConditionSet); +}; + +// Immutable container for multiple actions. +// +// ActionT should be immutable after creation. It must define the following +// members: +// +// // Arguments passed through from ActionSet::Create. +// static scoped_ptr<ActionT> Create( +// // Except this argument gets elements of the AnyVector. +// const base::Value& definition, +// std::string* error, bool* bad_message); +// void Apply(const std::string& extension_id, +// const base::Time& extension_install_time, +// // Contains action-type-specific in/out parameters. +// typename ActionT::ApplyInfo* apply_info) const; +// // Only needed if the RulesRegistry calls DeclarativeActionSet::Revert(). +// void Revert(const std::string& extension_id, +// const base::Time& extension_install_time, +// // Contains action-type-specific in/out parameters. +// typename ActionT::ApplyInfo* apply_info) const; +// // Return the minimum priority of rules that can be evaluated after this +// // action runs. Return MIN_INT by default. +// int GetMinimumPriority() const; +// +// TODO(battre): As DeclarativeActionSet can become the single owner of all +// actions, we can optimize here by making some of them singletons (e.g. Cancel +// actions). +template<typename ActionT> +class DeclarativeActionSet { + public: + typedef std::vector<linked_ptr<json_schema_compiler::any::Any> > AnyVector; + typedef std::vector<linked_ptr<const ActionT> > Actions; + + explicit DeclarativeActionSet(const Actions& actions); + + // Factory method that instantiates a DeclarativeActionSet according to + // |actions| which represents the array of actions received from the + // extension API. + static scoped_ptr<DeclarativeActionSet> Create(const AnyVector& actions, + std::string* error, + bool* bad_message); + + // Rules call this method when their conditions are fulfilled. + void Apply(const std::string& extension_id, + const base::Time& extension_install_time, + typename ActionT::ApplyInfo* apply_info) const; + + // Rules call this method when they have stateful conditions, and those + // conditions stop being fulfilled. Rules with event-based conditions (e.g. a + // network request happened) will never Revert() an action. + void Revert(const std::string& extension_id, + const base::Time& extension_install_time, + typename ActionT::ApplyInfo* apply_info) const; + + // Returns the minimum priority of rules that may be evaluated after + // this rule. Defaults to MIN_INT. + int GetMinimumPriority() const; + + const Actions& actions() const { return actions_; } + + private: + const Actions actions_; + + DISALLOW_COPY_AND_ASSIGN(DeclarativeActionSet); +}; + +// Representation of a rule of a declarative API: +// https://developer.chrome.com/beta/extensions/events.html#declarative. +// Generally a RulesRegistry will hold a collection of Rules for a given +// declarative API and contain the logic for matching and applying them. +// +// See DeclarativeConditionSet and DeclarativeActionSet for the requirements on +// ConditionT and ActionT. +template<typename ConditionT, typename ActionT> +class DeclarativeRule { + public: + typedef std::string ExtensionId; + typedef std::string RuleId; + typedef std::pair<ExtensionId, RuleId> GlobalRuleId; + typedef int Priority; + typedef DeclarativeConditionSet<ConditionT> ConditionSet; + typedef DeclarativeActionSet<ActionT> ActionSet; + typedef extensions::api::events::Rule JsonRule; + + // Checks whether the set of |conditions| and |actions| are consistent. + // Returns true in case of consistency and MUST set |error| otherwise. + typedef bool (*ConsistencyChecker)(const ConditionSet* conditions, + const ActionSet* actions, + std::string* error); + + DeclarativeRule(const GlobalRuleId& id, + base::Time extension_installation_time, + scoped_ptr<ConditionSet> conditions, + scoped_ptr<ActionSet> actions, + Priority priority); + + // Creates a DeclarativeRule for an extension given a json definition. The + // format of each condition and action's json is up to the specific ConditionT + // and ActionT. + // + // Before constructing the final rule, calls check_consistency(conditions, + // actions, error) and returns NULL if it fails. Pass NULL if no consistency + // check is needed. If |error| is empty, the translation was successful and + // the returned rule is internally consistent. + static scoped_ptr<DeclarativeRule> Create( + URLMatcherConditionFactory* url_matcher_condition_factory, + const std::string& extension_id, + base::Time extension_installation_time, + linked_ptr<JsonRule> rule, + ConsistencyChecker check_consistency, + std::string* error); + + const GlobalRuleId& id() const { return id_; } + const std::string& extension_id() const { return id_.first; } + const ConditionSet& conditions() const { return *conditions_; } + const ActionSet& actions() const { return *actions_; } + Priority priority() const { return priority_; } + + // Calls actions().Apply(extension_id(), extension_installation_time_, + // apply_info). This function should only be called when the conditions_ are + // fulfilled (from a semantic point of view; no harm is done if this function + // is called at other times for testing purposes). + void Apply(typename ActionT::ApplyInfo* apply_info) const; + + // Returns the minimum priority of rules that may be evaluated after + // this rule. Defaults to MIN_INT. Only valid if the conditions of this rule + // are fulfilled. + Priority GetMinimumPriority() const; + + private: + GlobalRuleId id_; + base::Time extension_installation_time_; // For precedences of rules. + scoped_ptr<ConditionSet> conditions_; + scoped_ptr<ActionSet> actions_; + Priority priority_; + + DISALLOW_COPY_AND_ASSIGN(DeclarativeRule); +}; + +// Implementation details below here. + +// +// DeclarativeConditionSet +// + +template<typename ConditionT> +bool DeclarativeConditionSet<ConditionT>::IsFulfilled( + URLMatcherConditionSet::ID url_match_trigger, + const std::set<URLMatcherConditionSet::ID>& url_matches, + const typename ConditionT::MatchData& match_data) const { + if (url_match_trigger == -1) { + // Invalid trigger -- indication that we should only check conditions + // without URL attributes. + for (typename std::vector<const ConditionT*>::const_iterator it = + conditions_without_urls_.begin(); + it != conditions_without_urls_.end(); ++it) { + if ((*it)->IsFulfilled(url_matches, match_data)) + return true; + } + return false; + } + + typename URLMatcherIdToCondition::const_iterator triggered = + match_id_to_condition_.find(url_match_trigger); + return (triggered != match_id_to_condition_.end() && + triggered->second->IsFulfilled(url_matches, match_data)); +} + +template<typename ConditionT> +void DeclarativeConditionSet<ConditionT>::GetURLMatcherConditionSets( + URLMatcherConditionSet::Vector* condition_sets) const { + for (typename Conditions::const_iterator i = conditions_.begin(); + i != conditions_.end(); ++i) { + (*i)->GetURLMatcherConditionSets(condition_sets); + } +} + +// static +template<typename ConditionT> +scoped_ptr<DeclarativeConditionSet<ConditionT> > +DeclarativeConditionSet<ConditionT>::Create( + URLMatcherConditionFactory* url_matcher_condition_factory, + const AnyVector& conditions, + std::string* error) { + Conditions result; + + for (AnyVector::const_iterator i = conditions.begin(); + i != conditions.end(); ++i) { + CHECK(i->get()); + scoped_ptr<ConditionT> condition = + ConditionT::Create(url_matcher_condition_factory, + (*i)->value(), error); + if (!error->empty()) + return scoped_ptr<DeclarativeConditionSet>(NULL); + result.push_back(make_linked_ptr(condition.release())); + } + + URLMatcherIdToCondition match_id_to_condition; + std::vector<const ConditionT*> conditions_without_urls; + URLMatcherConditionSet::Vector condition_sets; + + for (typename Conditions::const_iterator i = result.begin(); + i != result.end(); ++i) { + condition_sets.clear(); + (*i)->GetURLMatcherConditionSets(&condition_sets); + if (condition_sets.empty()) { + conditions_without_urls.push_back(i->get()); + } else { + for (URLMatcherConditionSet::Vector::const_iterator + match_set = condition_sets.begin(); + match_set != condition_sets.end(); ++match_set) + match_id_to_condition[(*match_set)->id()] = i->get(); + } + } + + return make_scoped_ptr(new DeclarativeConditionSet( + result, match_id_to_condition, conditions_without_urls)); +} + +template<typename ConditionT> +DeclarativeConditionSet<ConditionT>::DeclarativeConditionSet( + const Conditions& conditions, + const URLMatcherIdToCondition& match_id_to_condition, + const std::vector<const ConditionT*>& conditions_without_urls) + : match_id_to_condition_(match_id_to_condition), + conditions_(conditions), + conditions_without_urls_(conditions_without_urls) {} + +// +// DeclarativeActionSet +// + +template<typename ActionT> +DeclarativeActionSet<ActionT>::DeclarativeActionSet(const Actions& actions) + : actions_(actions) {} + +// static +template<typename ActionT> +scoped_ptr<DeclarativeActionSet<ActionT> > +DeclarativeActionSet<ActionT>::Create( + const AnyVector& actions, + std::string* error, + bool* bad_message) { + *error = ""; + *bad_message = false; + Actions result; + + for (AnyVector::const_iterator i = actions.begin(); + i != actions.end(); ++i) { + CHECK(i->get()); + scoped_ptr<ActionT> action = + ActionT::Create((*i)->value(), error, bad_message); + if (!error->empty() || *bad_message) + return scoped_ptr<DeclarativeActionSet>(NULL); + result.push_back(make_linked_ptr(action.release())); + } + + return scoped_ptr<DeclarativeActionSet>(new DeclarativeActionSet(result)); +} + +template<typename ActionT> +void DeclarativeActionSet<ActionT>::Apply( + const std::string& extension_id, + const base::Time& extension_install_time, + typename ActionT::ApplyInfo* apply_info) const { + for (typename Actions::const_iterator i = actions_.begin(); + i != actions_.end(); ++i) + (*i)->Apply(extension_id, extension_install_time, apply_info); +} + +template<typename ActionT> +void DeclarativeActionSet<ActionT>::Revert( + const std::string& extension_id, + const base::Time& extension_install_time, + typename ActionT::ApplyInfo* apply_info) const { + for (typename Actions::const_iterator i = actions_.begin(); + i != actions_.end(); ++i) + (*i)->Revert(extension_id, extension_install_time, apply_info); +} + +template<typename ActionT> +int DeclarativeActionSet<ActionT>::GetMinimumPriority() const { + int minimum_priority = std::numeric_limits<int>::min(); + for (typename Actions::const_iterator i = actions_.begin(); + i != actions_.end(); ++i) { + minimum_priority = std::max(minimum_priority, (*i)->GetMinimumPriority()); + } + return minimum_priority; +} + +// +// DeclarativeRule +// + +template<typename ConditionT, typename ActionT> +DeclarativeRule<ConditionT, ActionT>::DeclarativeRule( + const GlobalRuleId& id, + base::Time extension_installation_time, + scoped_ptr<ConditionSet> conditions, + scoped_ptr<ActionSet> actions, + Priority priority) + : id_(id), + extension_installation_time_(extension_installation_time), + conditions_(conditions.release()), + actions_(actions.release()), + priority_(priority) { + CHECK(conditions_.get()); + CHECK(actions_.get()); +} + +// static +template<typename ConditionT, typename ActionT> +scoped_ptr<DeclarativeRule<ConditionT, ActionT> > +DeclarativeRule<ConditionT, ActionT>::Create( + URLMatcherConditionFactory* url_matcher_condition_factory, + const std::string& extension_id, + base::Time extension_installation_time, + linked_ptr<JsonRule> rule, + ConsistencyChecker check_consistency, + std::string* error) { + scoped_ptr<DeclarativeRule> error_result; + + scoped_ptr<ConditionSet> conditions = ConditionSet::Create( + url_matcher_condition_factory, rule->conditions, error); + if (!error->empty()) + return error_result.Pass(); + CHECK(conditions.get()); + + bool bad_message = false; + scoped_ptr<ActionSet> actions = + ActionSet::Create(rule->actions, error, &bad_message); + if (bad_message) { + // TODO(battre) Export concept of bad_message to caller, the extension + // should be killed in case it is true. + *error = "An action of a rule set had an invalid " + "structure that should have been caught by the JSON validator."; + return error_result.Pass(); + } + if (!error->empty() || bad_message) + return error_result.Pass(); + CHECK(actions.get()); + + if (check_consistency && + !check_consistency(conditions.get(), actions.get(), error)) { + DCHECK(!error->empty()); + return error_result.Pass(); + } + + CHECK(rule->priority.get()); + int priority = *(rule->priority); + + GlobalRuleId rule_id(extension_id, *(rule->id)); + return scoped_ptr<DeclarativeRule>( + new DeclarativeRule(rule_id, extension_installation_time, + conditions.Pass(), actions.Pass(), priority)); +} + +template<typename ConditionT, typename ActionT> +void DeclarativeRule<ConditionT, ActionT>::Apply( + typename ActionT::ApplyInfo* apply_info) const { + return actions_->Apply(extension_id(), + extension_installation_time_, + apply_info); +} + +template<typename ConditionT, typename ActionT> +int DeclarativeRule<ConditionT, ActionT>::GetMinimumPriority() const { + return actions_->GetMinimumPriority(); +} + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DECLARATIVE_RULE_H__ diff --git a/chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc b/chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc new file mode 100644 index 0000000..509d0db --- /dev/null +++ b/chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc @@ -0,0 +1,387 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/declarative/declarative_rule.h" + +#include "base/message_loop.h" +#include "base/test/values_test_util.h" +#include "base/values.h" +#include "chrome/common/extensions/matcher/url_matcher_constants.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace extensions { + +using json_schema_compiler::any::Any; +using base::test::ParseJson; + +struct RecordingCondition { + typedef int MatchData; + + URLMatcherConditionFactory* factory; + scoped_ptr<base::Value> value; + + void GetURLMatcherConditionSets( + URLMatcherConditionSet::Vector* condition_sets) const { + // No condition sets. + } + + bool has_url_matcher_condition_set() const { + return false; + } + + static scoped_ptr<RecordingCondition> Create( + URLMatcherConditionFactory* url_matcher_condition_factory, + const base::Value& condition, + std::string* error) { + const base::DictionaryValue* dict = NULL; + if (condition.GetAsDictionary(&dict) && dict->HasKey("bad_key")) { + *error = "Found error key"; + return scoped_ptr<RecordingCondition>(); + } + + scoped_ptr<RecordingCondition> result(new RecordingCondition()); + result->factory = url_matcher_condition_factory; + result->value.reset(condition.DeepCopy()); + return result.Pass(); + } +}; +typedef DeclarativeConditionSet<RecordingCondition> RecordingConditionSet; + +TEST(DeclarativeConditionTest, ErrorConditionSet) { + URLMatcher matcher; + RecordingConditionSet::AnyVector conditions; + conditions.push_back(make_linked_ptr(new Any(ParseJson("{\"key\": 1}")))); + conditions.push_back(make_linked_ptr(new Any(ParseJson("{\"bad_key\": 2}")))); + + std::string error; + scoped_ptr<RecordingConditionSet> result = + RecordingConditionSet::Create(matcher.condition_factory(), + conditions, &error); + EXPECT_EQ("Found error key", error); + ASSERT_FALSE(result); +} + +TEST(DeclarativeConditionTest, CreateConditionSet) { + URLMatcher matcher; + RecordingConditionSet::AnyVector conditions; + conditions.push_back(make_linked_ptr(new Any(ParseJson("{\"key\": 1}")))); + conditions.push_back(make_linked_ptr(new Any(ParseJson("[\"val1\", 2]")))); + + // Test insertion + std::string error; + scoped_ptr<RecordingConditionSet> result = + RecordingConditionSet::Create(matcher.condition_factory(), + conditions, &error); + EXPECT_EQ("", error); + ASSERT_TRUE(result); + EXPECT_EQ(2u, result->conditions().size()); + + EXPECT_EQ(matcher.condition_factory(), result->conditions()[0]->factory); + EXPECT_TRUE(ParseJson("{\"key\": 1}")->Equals( + result->conditions()[0]->value.get())); +} + +struct FulfillableCondition { + typedef int MatchData; + + scoped_refptr<URLMatcherConditionSet> condition_set; + int condition_set_id; + int max_value; + + URLMatcherConditionSet::ID url_matcher_condition_set_id() const { + return condition_set_id; + } + + bool has_url_matcher_condition_set() const { + return true; + } + + scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set() const { + return condition_set; + } + + void GetURLMatcherConditionSets( + URLMatcherConditionSet::Vector* condition_sets) const { + if (condition_set) + condition_sets->push_back(condition_set); + } + + bool IsFulfilled(const std::set<URLMatcherConditionSet::ID>& url_matches, + int match_data) const { + if (condition_set_id != -1 && !ContainsKey(url_matches, condition_set_id)) + return false; + return match_data <= max_value; + } + + static scoped_ptr<FulfillableCondition> Create( + URLMatcherConditionFactory* url_matcher_condition_factory, + const base::Value& condition, + std::string* error) { + scoped_ptr<FulfillableCondition> result(new FulfillableCondition()); + const base::DictionaryValue* dict; + if (!condition.GetAsDictionary(&dict)) { + *error = "Expected dict"; + return result.Pass(); + } + if (!dict->GetInteger("url_id", &result->condition_set_id)) + result->condition_set_id = -1; + if (!dict->GetInteger("max", &result->max_value)) + *error = "Expected integer at ['max']"; + if (result->condition_set_id != -1) { + result->condition_set = new URLMatcherConditionSet( + result->condition_set_id, + URLMatcherConditionSet::Conditions()); + } + return result.Pass(); + } +}; + +TEST(DeclarativeConditionTest, FulfillConditionSet) { + typedef DeclarativeConditionSet<FulfillableCondition> FulfillableConditionSet; + FulfillableConditionSet::AnyVector conditions; + conditions.push_back(make_linked_ptr(new Any(ParseJson( + "{\"url_id\": 1, \"max\": 3}")))); + conditions.push_back(make_linked_ptr(new Any(ParseJson( + "{\"url_id\": 2, \"max\": 5}")))); + conditions.push_back(make_linked_ptr(new Any(ParseJson( + "{\"url_id\": 3, \"max\": 1}")))); + conditions.push_back(make_linked_ptr(new Any(ParseJson( + "{\"max\": -5}")))); // No url. + + // Test insertion + std::string error; + scoped_ptr<FulfillableConditionSet> result = + FulfillableConditionSet::Create(NULL, conditions, &error); + ASSERT_EQ("", error); + ASSERT_TRUE(result); + EXPECT_EQ(4u, result->conditions().size()); + + std::set<URLMatcherConditionSet::ID> url_matches; + EXPECT_FALSE(result->IsFulfilled(1, url_matches, 0)) + << "Testing an ID that's not in url_matches forwards to the Condition, " + << "which doesn't match."; + EXPECT_FALSE(result->IsFulfilled(-1, url_matches, 0)) + << "Testing the 'no ID' value tries to match the 4th condition, but " + << "its max is too low."; + EXPECT_TRUE(result->IsFulfilled(-1, url_matches, -5)) + << "Testing the 'no ID' value tries to match the 4th condition, and " + << "this value is low enough."; + + url_matches.insert(1); + EXPECT_TRUE(result->IsFulfilled(1, url_matches, 3)) + << "Tests a condition with a url matcher, for a matching value."; + EXPECT_FALSE(result->IsFulfilled(1, url_matches, 4)) + << "Tests a condition with a url matcher, for a non-matching value " + << "that would match a different condition."; + url_matches.insert(2); + EXPECT_TRUE(result->IsFulfilled(2, url_matches, 4)) + << "Tests with 2 elements in the match set."; + + // Check the condition sets: + URLMatcherConditionSet::Vector condition_sets; + result->GetURLMatcherConditionSets(&condition_sets); + ASSERT_EQ(3U, condition_sets.size()); + EXPECT_EQ(1, condition_sets[0]->id()); + EXPECT_EQ(2, condition_sets[1]->id()); + EXPECT_EQ(3, condition_sets[2]->id()); +} + +// DeclarativeAction + +struct SummingAction { + typedef int ApplyInfo; + + int increment; + int min_priority; + + static scoped_ptr<SummingAction> Create(const base::Value& action, + std::string* error, + bool* bad_message) { + scoped_ptr<SummingAction> result(new SummingAction()); + const base::DictionaryValue* dict = NULL; + EXPECT_TRUE(action.GetAsDictionary(&dict)); + if (dict->HasKey("error")) { + EXPECT_TRUE(dict->GetString("error", error)); + return result.Pass(); + } + if (dict->HasKey("bad")) { + *bad_message = true; + return result.Pass(); + } + + EXPECT_TRUE(dict->GetInteger("value", &result->increment)); + dict->GetInteger("priority", &result->min_priority); + return result.Pass(); + } + + void Apply(const std::string& extension_id, + const base::Time& install_time, + int* sum) const { + *sum += increment; + } + + int GetMinimumPriority() const { + return min_priority; + } +}; +typedef DeclarativeActionSet<SummingAction> SummingActionSet; + +TEST(DeclarativeActionTest, ErrorActionSet) { + SummingActionSet::AnyVector actions; + actions.push_back(make_linked_ptr(new Any(ParseJson("{\"value\": 1}")))); + actions.push_back(make_linked_ptr(new Any(ParseJson( + "{\"error\": \"the error\"}")))); + + std::string error; + bool bad = false; + scoped_ptr<SummingActionSet> result = + SummingActionSet::Create(actions, &error, &bad); + EXPECT_EQ("the error", error); + EXPECT_FALSE(bad); + EXPECT_FALSE(result); + + actions.clear(); + actions.push_back(make_linked_ptr(new Any(ParseJson("{\"value\": 1}")))); + actions.push_back(make_linked_ptr(new Any(ParseJson("{\"bad\": 3}")))); + result = SummingActionSet::Create(actions, &error, &bad); + EXPECT_EQ("", error); + EXPECT_TRUE(bad); + EXPECT_FALSE(result); +} + +TEST(DeclarativeActionTest, ApplyActionSet) { + SummingActionSet::AnyVector actions; + actions.push_back(make_linked_ptr(new Any(ParseJson( + "{\"value\": 1," + " \"priority\": 5}")))); + actions.push_back(make_linked_ptr(new Any(ParseJson("{\"value\": 2}")))); + + // Test insertion + std::string error; + bool bad = false; + scoped_ptr<SummingActionSet> result = + SummingActionSet::Create(actions, &error, &bad); + EXPECT_EQ("", error); + EXPECT_FALSE(bad); + ASSERT_TRUE(result); + EXPECT_EQ(2u, result->actions().size()); + + int sum = 0; + result->Apply("ext_id", base::Time(), &sum); + EXPECT_EQ(3, sum); + EXPECT_EQ(5, result->GetMinimumPriority()); +} + +TEST(DeclarativeRuleTest, Create) { + typedef DeclarativeRule<FulfillableCondition, SummingAction> Rule; + linked_ptr<Rule::JsonRule> json_rule(new Rule::JsonRule); + ASSERT_TRUE(Rule::JsonRule::Populate( + *ParseJson("{ \n" + " \"id\": \"rule1\", \n" + " \"conditions\": [ \n" + " {\"url_id\": 1, \"max\": 3}, \n" + " {\"url_id\": 2, \"max\": 5}, \n" + " ], \n" + " \"actions\": [ \n" + " { \n" + " \"value\": 2 \n" + " } \n" + " ], \n" + " \"priority\": 200 \n" + "}"), + json_rule.get())); + + const char kExtensionId[] = "ext1"; + + base::Time install_time = base::Time::Now(); + + URLMatcher matcher; + std::string error; + scoped_ptr<Rule> rule(Rule::Create(matcher.condition_factory(), kExtensionId, + install_time, json_rule, NULL, &error)); + EXPECT_EQ("", error); + ASSERT_TRUE(rule.get()); + + EXPECT_EQ(kExtensionId, rule->id().first); + EXPECT_EQ("rule1", rule->id().second); + + EXPECT_EQ(200, rule->priority()); + + const Rule::ConditionSet& condition_set = rule->conditions(); + const Rule::ConditionSet::Conditions& conditions = + condition_set.conditions(); + ASSERT_EQ(2u, conditions.size()); + EXPECT_EQ(3, conditions[0]->max_value); + EXPECT_EQ(5, conditions[1]->max_value); + + const Rule::ActionSet& action_set = rule->actions(); + const Rule::ActionSet::Actions& actions = action_set.actions(); + ASSERT_EQ(1u, actions.size()); + EXPECT_EQ(2, actions[0]->increment); + + int sum = 0; + rule->Apply(&sum); + EXPECT_EQ(2, sum); +} + +bool AtLeastOneCondition( + const DeclarativeConditionSet<FulfillableCondition>* conditions, + const DeclarativeActionSet<SummingAction>* actions, + std::string* error) { + if (conditions->conditions().empty()) { + *error = "No conditions"; + return false; + } + return true; +} + +TEST(DeclarativeRuleTest, CheckConsistency) { + typedef DeclarativeRule<FulfillableCondition, SummingAction> Rule; + URLMatcher matcher; + std::string error; + linked_ptr<Rule::JsonRule> json_rule(new Rule::JsonRule); + const char kExtensionId[] = "ext1"; + + ASSERT_TRUE(Rule::JsonRule::Populate( + *ParseJson("{ \n" + " \"id\": \"rule1\", \n" + " \"conditions\": [ \n" + " {\"url_id\": 1, \"max\": 3}, \n" + " {\"url_id\": 2, \"max\": 5}, \n" + " ], \n" + " \"actions\": [ \n" + " { \n" + " \"value\": 2 \n" + " } \n" + " ], \n" + " \"priority\": 200 \n" + "}"), + json_rule.get())); + scoped_ptr<Rule> rule( + Rule::Create(matcher.condition_factory(), kExtensionId, base::Time(), + json_rule, &AtLeastOneCondition, &error)); + EXPECT_TRUE(rule); + EXPECT_EQ("", error); + + ASSERT_TRUE(Rule::JsonRule::Populate( + *ParseJson("{ \n" + " \"id\": \"rule1\", \n" + " \"conditions\": [ \n" + " ], \n" + " \"actions\": [ \n" + " { \n" + " \"value\": 2 \n" + " } \n" + " ], \n" + " \"priority\": 200 \n" + "}"), + json_rule.get())); + rule = Rule::Create(matcher.condition_factory(), kExtensionId, base::Time(), + json_rule, &AtLeastOneCondition, &error); + EXPECT_FALSE(rule); + EXPECT_EQ("No conditions", error); +} + +} // namespace extensions diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc index 8d573de..f0b1fd7 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc @@ -12,6 +12,7 @@ #include "base/string_util.h" #include "base/values.h" #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h" +#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" #include "chrome/browser/extensions/api/web_request/web_request_permissions.h" @@ -440,70 +441,26 @@ scoped_ptr<WebRequestAction> WebRequestAction::Create( return scoped_ptr<WebRequestAction>(); } - -// -// WebRequestActionSet -// - -WebRequestActionSet::WebRequestActionSet(const Actions& actions) - : actions_(actions) {} - -WebRequestActionSet::~WebRequestActionSet() {} - -// static -scoped_ptr<WebRequestActionSet> WebRequestActionSet::Create( - const AnyVector& actions, - std::string* error, - bool* bad_message) { - *error = ""; - *bad_message = false; - Actions result; - - for (AnyVector::const_iterator i = actions.begin(); - i != actions.end(); ++i) { - CHECK(i->get()); - scoped_ptr<WebRequestAction> action = - WebRequestAction::Create((*i)->value(), error, bad_message); - if (!error->empty() || *bad_message) - return scoped_ptr<WebRequestActionSet>(NULL); - result.push_back(make_linked_ptr(action.release())); - } - - return scoped_ptr<WebRequestActionSet>(new WebRequestActionSet(result)); -} - -std::list<LinkedPtrEventResponseDelta> WebRequestActionSet::CreateDeltas( - const ExtensionInfoMap* extension_info_map, - const std::string& extension_id, - const WebRequestRule::RequestData& request_data, - bool crosses_incognito, - const base::Time& extension_install_time) const { - std::list<LinkedPtrEventResponseDelta> result; - for (Actions::const_iterator i = actions_.begin(); i != actions_.end(); ++i) { - if (!(*i)->HasPermission(extension_info_map, extension_id, - request_data.request, crosses_incognito)) - continue; - if ((*i)->GetStages() & request_data.stage) { - LinkedPtrEventResponseDelta delta = (*i)->CreateDelta( - request_data, extension_id, extension_install_time); - if (delta.get()) { - if ((*i)->DeltaHasPermission(extension_info_map, extension_id, - request_data.request, crosses_incognito, - delta)) - result.push_back(delta); - } +void WebRequestAction::Apply(const std::string& extension_id, + base::Time extension_install_time, + ApplyInfo* apply_info) const { + if (!HasPermission(apply_info->extension_info_map, extension_id, + apply_info->request_data.request, + apply_info->crosses_incognito)) + return; + if (GetStages() & apply_info->request_data.stage) { + LinkedPtrEventResponseDelta delta = CreateDelta( + apply_info->request_data, extension_id, extension_install_time); + if (delta.get()) { + if (DeltaHasPermission(apply_info->extension_info_map, extension_id, + apply_info->request_data.request, + apply_info->crosses_incognito, + delta)) + apply_info->deltas->push_back(delta); } } - return result; } -int WebRequestActionSet::GetMinimumPriority() const { - int minimum_priority = std::numeric_limits<int>::min(); - for (Actions::const_iterator i = actions_.begin(); i != actions_.end(); ++i) { - minimum_priority = std::max(minimum_priority, (*i)->GetMinimumPriority()); - } - return minimum_priority; -} // // WebRequestCancelAction @@ -528,7 +485,7 @@ WebRequestCancelAction::GetHostPermissionsStrategy() const { } LinkedPtrEventResponseDelta WebRequestCancelAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); @@ -561,7 +518,7 @@ WebRequestRedirectAction::GetHostPermissionsStrategy() const { } LinkedPtrEventResponseDelta WebRequestRedirectAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); @@ -599,7 +556,7 @@ WebRequestRedirectToTransparentImageAction::GetHostPermissionsStrategy() const { LinkedPtrEventResponseDelta WebRequestRedirectToTransparentImageAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); @@ -635,7 +592,7 @@ WebRequestRedirectToEmptyDocumentAction::GetHostPermissionsStrategy() const { LinkedPtrEventResponseDelta WebRequestRedirectToEmptyDocumentAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); @@ -724,7 +681,7 @@ WebRequestRedirectByRegExAction::GetHostPermissionsStrategy() const { } LinkedPtrEventResponseDelta WebRequestRedirectByRegExAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); @@ -768,7 +725,7 @@ WebRequestSetRequestHeaderAction::GetType() const { LinkedPtrEventResponseDelta WebRequestSetRequestHeaderAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); @@ -800,7 +757,7 @@ WebRequestRemoveRequestHeaderAction::GetType() const { LinkedPtrEventResponseDelta WebRequestRemoveRequestHeaderAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); @@ -834,7 +791,7 @@ WebRequestAddResponseHeaderAction::GetType() const { LinkedPtrEventResponseDelta WebRequestAddResponseHeaderAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); @@ -879,7 +836,7 @@ WebRequestRemoveResponseHeaderAction::GetType() const { LinkedPtrEventResponseDelta WebRequestRemoveResponseHeaderAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); @@ -935,7 +892,7 @@ WebRequestIgnoreRulesAction::GetHostPermissionsStrategy() const { } LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); @@ -963,7 +920,7 @@ WebRequestAction::Type WebRequestRequestCookieAction::GetType() const { } LinkedPtrEventResponseDelta WebRequestRequestCookieAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); @@ -996,7 +953,7 @@ WebRequestAction::Type WebRequestResponseCookieAction::GetType() const { } LinkedPtrEventResponseDelta WebRequestResponseCookieAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); @@ -1030,7 +987,7 @@ WebRequestAction::Type WebRequestSendMessageToExtensionAction::GetType() const { } LinkedPtrEventResponseDelta WebRequestSendMessageToExtensionAction::CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const { CHECK(request_data.stage & GetStages()); diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h index f68b904..46b382e 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h @@ -11,12 +11,13 @@ #include "base/compiler_specific.h" #include "base/memory/linked_ptr.h" +#include "chrome/browser/extensions/api/declarative/declarative_rule.h" #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" #include "chrome/common/extensions/api/events.h" #include "googleurl/src/gurl.h" +class ExtensionInfoMap; class WebRequestPermission; namespace base { @@ -31,6 +32,7 @@ struct EventResponseDelta; namespace extensions { class Extension; +struct DeclarativeWebRequestData; } namespace net { @@ -77,6 +79,16 @@ class WebRequestAction { // after creating the delta. }; + // Information necessary to decide how to apply a WebRequestAction + // inside a matching rule. + struct ApplyInfo { + const ExtensionInfoMap* extension_info_map; + const DeclarativeWebRequestData& request_data; + bool crosses_incognito; + // Modified by each applied action: + std::list<LinkedPtrEventResponseDelta>* deltas; + }; + WebRequestAction(); virtual ~WebRequestAction(); @@ -135,53 +147,19 @@ class WebRequestAction { // Returns a description of the modification to the request caused by // this action. virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const = 0; -}; - -// Immutable container for multiple actions. -// -// TODO(battre): As WebRequestActionSet can become the single owner of all -// actions, we can optimize here by making some of them singletons (e.g. Cancel -// actions). -class WebRequestActionSet { - public: - typedef std::vector<linked_ptr<json_schema_compiler::any::Any> > AnyVector; - typedef std::vector<linked_ptr<WebRequestAction> > Actions; - - explicit WebRequestActionSet(const Actions& actions); - virtual ~WebRequestActionSet(); - - // Factory method that instantiates a WebRequestActionSet according to - // |actions| which represents the array of actions received from the - // extension API. - static scoped_ptr<WebRequestActionSet> Create(const AnyVector& actions, - std::string* error, - bool* bad_message); - - // Returns a description of the modifications to |request_data.request| caused - // by the |actions_| that can be executed at |request.stage|. If |extension| - // is not NULL, permissions of extensions are checked. - std::list<LinkedPtrEventResponseDelta> CreateDeltas( - const ExtensionInfoMap* extension_info_map, - const std::string& extension_id, - const WebRequestRule::RequestData& request_data, - bool crosses_incognito, - const base::Time& extension_install_time) const; - - // Returns the minimum priority of rules that may be evaluated after - // this rule. Defaults to MIN_INT. - int GetMinimumPriority() const; - const Actions& actions() const { return actions_; } - - private: - Actions actions_; - - DISALLOW_COPY_AND_ASSIGN(WebRequestActionSet); + // Applies this action to a request, recording the results into + // apply_info.deltas. + void Apply(const std::string& extension_id, + base::Time extension_install_time, + ApplyInfo* apply_info) const; }; +typedef DeclarativeActionSet<WebRequestAction> WebRequestActionSet; + // // The following are concrete actions. // @@ -197,7 +175,7 @@ class WebRequestCancelAction : public WebRequestAction { virtual Type GetType() const OVERRIDE; virtual HostPermissionsStrategy GetHostPermissionsStrategy() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; @@ -216,7 +194,7 @@ class WebRequestRedirectAction : public WebRequestAction { virtual Type GetType() const OVERRIDE; virtual HostPermissionsStrategy GetHostPermissionsStrategy() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; @@ -237,7 +215,7 @@ class WebRequestRedirectToTransparentImageAction : public WebRequestAction { virtual Type GetType() const OVERRIDE; virtual HostPermissionsStrategy GetHostPermissionsStrategy() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; @@ -257,7 +235,7 @@ class WebRequestRedirectToEmptyDocumentAction : public WebRequestAction { virtual Type GetType() const OVERRIDE; virtual HostPermissionsStrategy GetHostPermissionsStrategy() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; @@ -283,7 +261,7 @@ class WebRequestRedirectByRegExAction : public WebRequestAction { virtual Type GetType() const OVERRIDE; virtual HostPermissionsStrategy GetHostPermissionsStrategy() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; @@ -305,7 +283,7 @@ class WebRequestSetRequestHeaderAction : public WebRequestAction { virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; @@ -325,7 +303,7 @@ class WebRequestRemoveRequestHeaderAction : public WebRequestAction { virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; @@ -345,7 +323,7 @@ class WebRequestAddResponseHeaderAction : public WebRequestAction { virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; @@ -367,7 +345,7 @@ class WebRequestRemoveResponseHeaderAction : public WebRequestAction { virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; @@ -390,7 +368,7 @@ class WebRequestIgnoreRulesAction : public WebRequestAction { virtual int GetMinimumPriority() const OVERRIDE; virtual HostPermissionsStrategy GetHostPermissionsStrategy() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; @@ -413,7 +391,7 @@ class WebRequestRequestCookieAction : public WebRequestAction { virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; @@ -436,7 +414,7 @@ class WebRequestResponseCookieAction : public WebRequestAction { virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; @@ -456,7 +434,7 @@ class WebRequestSendMessageToExtensionAction : public WebRequestAction { virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, const std::string& extension_id, const base::Time& extension_install_time) const OVERRIDE; diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc index ee15049..db4f6ea 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc @@ -6,6 +6,7 @@ #include "base/message_loop.h" #include "base/values.h" +#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" #include "chrome/common/extensions/extension_constants.h" @@ -56,54 +57,6 @@ TEST(WebRequestActionTest, CreateAction) { EXPECT_EQ(WebRequestAction::ACTION_CANCEL_REQUEST, result->GetType()); } -TEST(WebRequestActionTest, CreateActionSet) { - std::string error; - bool bad_message = false; - scoped_ptr<WebRequestActionSet> result; - - WebRequestActionSet::AnyVector input; - - // Test empty input. - error.clear(); - result = WebRequestActionSet::Create(input, &error, &bad_message); - EXPECT_TRUE(error.empty()) << error; - EXPECT_FALSE(bad_message); - ASSERT_TRUE(result.get()); - EXPECT_TRUE(result->actions().empty()); - EXPECT_EQ(std::numeric_limits<int>::min(), result->GetMinimumPriority()); - - DictionaryValue correct_action; - correct_action.SetString(keys::kInstanceTypeKey, keys::kIgnoreRulesType); - correct_action.SetInteger(keys::kLowerPriorityThanKey, 10); - DictionaryValue incorrect_action; - incorrect_action.SetString(keys::kInstanceTypeKey, kUnknownActionType); - - // Test success. - linked_ptr<json_schema_compiler::any::Any> action1 = make_linked_ptr( - new json_schema_compiler::any::Any); - action1->Init(correct_action); - input.push_back(action1); - error.clear(); - result = WebRequestActionSet::Create(input, &error, &bad_message); - EXPECT_TRUE(error.empty()) << error; - EXPECT_FALSE(bad_message); - ASSERT_TRUE(result.get()); - ASSERT_EQ(1u, result->actions().size()); - EXPECT_EQ(WebRequestAction::ACTION_IGNORE_RULES, - result->actions()[0]->GetType()); - EXPECT_EQ(10, result->GetMinimumPriority()); - - // Test failure. - linked_ptr<json_schema_compiler::any::Any> action2 = make_linked_ptr( - new json_schema_compiler::any::Any); - action2->Init(incorrect_action); - input.push_back(action2); - error.clear(); - result = WebRequestActionSet::Create(input, &error, &bad_message); - EXPECT_NE("", error); - EXPECT_FALSE(result.get()); -} - // Test capture group syntax conversions of WebRequestRedirectByRegExAction TEST(WebRequestActionTest, PerlToRe2Style) { #define CallPerlToRe2Style WebRequestRedirectByRegExAction::PerlToRe2Style @@ -147,19 +100,20 @@ TEST(WebRequestActionTest, TestPermissions) { // Check that redirect works on regular URLs but not on protected URLs. net::TestURLRequest regular_request(GURL("http://test.com"), NULL, &context); - std::list<LinkedPtrEventResponseDelta> deltas = - action_set->CreateDeltas( - NULL, "ext1", - WebRequestRule::RequestData(®ular_request, ON_BEFORE_REQUEST), - false, base::Time()); + std::list<LinkedPtrEventResponseDelta> deltas; + DeclarativeWebRequestData request_data(®ular_request, ON_BEFORE_REQUEST); + WebRequestAction::ApplyInfo apply_info = { + NULL, request_data, false, &deltas + }; + action_set->Apply("ext1", base::Time(), &apply_info); EXPECT_EQ(1u, deltas.size()); net::TestURLRequest protected_request(GURL("http://clients1.google.com"), NULL, &context); - deltas = action_set->CreateDeltas( - NULL, "ext1", - WebRequestRule::RequestData(&protected_request, ON_BEFORE_REQUEST), - false, base::Time()); + deltas.clear(); + request_data = + DeclarativeWebRequestData(&protected_request, ON_BEFORE_REQUEST); + action_set->Apply("ext1", base::Time(), &apply_info); EXPECT_EQ(0u, deltas.size()); } diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc index 97fed38..4a80a5a 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc @@ -59,7 +59,7 @@ WebRequestCondition::~WebRequestCondition() {} bool WebRequestCondition::IsFulfilled( const std::set<URLMatcherConditionSet::ID>& url_matches, - const WebRequestRule::RequestData& request_data) const { + const DeclarativeWebRequestData& request_data) const { if (!(request_data.stage & applicable_request_stages_)) { // A condition that cannot be evaluated is considered as violated. return false; @@ -148,90 +148,4 @@ scoped_ptr<WebRequestCondition> WebRequestCondition::Create( return result.Pass(); } -// -// WebRequestConditionSet -// - -WebRequestConditionSet::~WebRequestConditionSet() {} - -bool WebRequestConditionSet::IsFulfilled( - URLMatcherConditionSet::ID url_match_trigger, - const std::set<URLMatcherConditionSet::ID>& url_matches, - const WebRequestRule::RequestData& request_data) const { - if (url_match_trigger == -1) { - // Invalid trigger -- indication that we should only check conditions - // without URL attributes. - for (std::vector<const WebRequestCondition*>::const_iterator it = - conditions_without_urls_.begin(); - it != conditions_without_urls_.end(); ++it) { - if ((*it)->IsFulfilled(url_matches, request_data)) - return true; - } - return false; - } - - URLMatcherIdToCondition::const_iterator triggered = - match_id_to_condition_.find(url_match_trigger); - return (triggered != match_id_to_condition_.end() && - triggered->second->IsFulfilled(url_matches, request_data)); -} - -void WebRequestConditionSet::GetURLMatcherConditionSets( - URLMatcherConditionSet::Vector* condition_sets) const { - for (Conditions::const_iterator i = conditions_.begin(); - i != conditions_.end(); ++i) { - scoped_refptr<URLMatcherConditionSet> set = - (*i)->url_matcher_condition_set(); - if (set.get()) - condition_sets->push_back(set); - } -} - -// static -scoped_ptr<WebRequestConditionSet> WebRequestConditionSet::Create( - URLMatcherConditionFactory* url_matcher_condition_factory, - const AnyVector& conditions, - std::string* error) { - Conditions result; - - for (AnyVector::const_iterator i = conditions.begin(); - i != conditions.end(); ++i) { - CHECK(i->get()); - scoped_ptr<WebRequestCondition> condition = - WebRequestCondition::Create(url_matcher_condition_factory, - (*i)->value(), error); - if (!error->empty()) - return scoped_ptr<WebRequestConditionSet>(NULL); - result.push_back(make_linked_ptr(condition.release())); - } - - URLMatcherIdToCondition match_id_to_condition; - std::vector<const WebRequestCondition*> conditions_without_urls; - - for (Conditions::const_iterator i = result.begin(); i != result.end(); ++i) { - const URLMatcherConditionSet* set = (*i)->url_matcher_condition_set().get(); - if (set) { - URLMatcherConditionSet::ID id = set->id(); - match_id_to_condition[id] = i->get(); - } else { - conditions_without_urls.push_back(i->get()); - } - } - - return make_scoped_ptr(new WebRequestConditionSet( - result, match_id_to_condition, conditions_without_urls)); -} - -bool WebRequestConditionSet::HasConditionsWithoutUrls() const { - return !conditions_without_urls_.empty(); -} - -WebRequestConditionSet::WebRequestConditionSet( - const Conditions& conditions, - const URLMatcherIdToCondition& match_id_to_condition, - const std::vector<const WebRequestCondition*>& conditions_without_urls) - : match_id_to_condition_(match_id_to_condition), - conditions_(conditions), - conditions_without_urls_(conditions_without_urls) {} - } // namespace extensions diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h index d1fdcdf..fd8c4c1a 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h @@ -12,12 +12,31 @@ #include "base/basictypes.h" #include "base/memory/linked_ptr.h" +#include "chrome/browser/extensions/api/declarative/declarative_rule.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" #include "chrome/common/extensions/matcher/url_matcher.h" +#include "net/http/http_response_headers.h" namespace extensions { +// Container for information about a URLRequest to determine which +// rules apply to the request. +struct DeclarativeWebRequestData { + DeclarativeWebRequestData(net::URLRequest* request, RequestStage stage) + : request(request), stage(stage), + original_response_headers(NULL) {} + DeclarativeWebRequestData( + net::URLRequest* request, RequestStage stage, + const net::HttpResponseHeaders* original_response_headers) + : request(request), stage(stage), + original_response_headers(original_response_headers) {} + net::URLRequest* request; + RequestStage stage; + // Additional information about requests that is not + // available in all request stages. + const net::HttpResponseHeaders* original_response_headers; +}; + // Representation of a condition in the Declarative WebRequest API. A condition // consists of several attributes. Each of these attributes needs to be // fulfilled in order for the condition to be fulfilled. @@ -37,6 +56,8 @@ namespace extensions { // WebRequestConditionSet::GetURLMatcherConditionSets. class WebRequestCondition { public: + typedef DeclarativeWebRequestData MatchData; + WebRequestCondition( scoped_refptr<URLMatcherConditionSet> url_matcher_conditions, const WebRequestConditionAttributes& condition_attributes); @@ -52,20 +73,18 @@ class WebRequestCondition { // Returns whether the request matches this condition. |url_matches| lists // the IDs that match the request's URL. bool IsFulfilled(const std::set<URLMatcherConditionSet::ID> &url_matches, - const WebRequestRule::RequestData &request_data) const; - - // Returns a URLMatcherConditionSet::ID which is the canonical representation - // for all URL patterns that need to be matched by this WebRequestCondition. - // This ID is registered in a URLMatcher that can inform us in case of a - // match. - URLMatcherConditionSet::ID url_matcher_condition_set_id() const { - DCHECK(url_matcher_conditions_.get()); - return url_matcher_conditions_->id(); + const DeclarativeWebRequestData& request_data) const; + + // True if this condition has a url filter. + bool has_url_matcher_condition_set() const { + return url_matcher_conditions_ != NULL; } - // Returns the set of conditions that are checked on the URL. May be NULL. - scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set() const { - return url_matcher_conditions_; + // If this Condition has a url filter, appends it to |condition_sets|. + void GetURLMatcherConditionSets( + URLMatcherConditionSet::Vector* condition_sets) const { + if (url_matcher_conditions_) + condition_sets->push_back(url_matcher_conditions_); } // Returns the condition attributes checked by this condition. @@ -93,59 +112,7 @@ class WebRequestCondition { DISALLOW_COPY_AND_ASSIGN(WebRequestCondition); }; -// This class stores a set of conditions that may be part of a WebRequestRule. -// If any condition is fulfilled, the WebRequestActions of the WebRequestRule -// can be triggered. -class WebRequestConditionSet { - public: - typedef std::vector<linked_ptr<json_schema_compiler::any::Any> > AnyVector; - typedef std::vector<linked_ptr<WebRequestCondition> > Conditions; - - ~WebRequestConditionSet(); - - // Factory method that creates an WebRequestConditionSet according to the JSON - // array |conditions| passed by the extension API. - // Sets |error| and returns NULL in case of an error. - static scoped_ptr<WebRequestConditionSet> Create( - URLMatcherConditionFactory* url_matcher_condition_factory, - const AnyVector& conditions, - std::string* error); - - const Conditions& conditions() const { - return conditions_; - } - - // If |url_match_trigger| is a member of |url_matches|, then this returns - // whether the corresponding condition is fulfilled wrt. |request_data|. If - // |url_match_trigger| is -1, this function returns whether any of the - // conditions without URL attributes is satisfied. - bool IsFulfilled( - URLMatcherConditionSet::ID url_match_trigger, - const std::set<URLMatcherConditionSet::ID>& url_matches, - const WebRequestRule::RequestData& request_data) const; - - // Appends the URLMatcherConditionSet from all conditions to |condition_sets|. - void GetURLMatcherConditionSets( - URLMatcherConditionSet::Vector* condition_sets) const; - - // Returns whether there are some conditions without UrlFilter attributes. - bool HasConditionsWithoutUrls() const; - - private: - typedef std::map<URLMatcherConditionSet::ID, const WebRequestCondition*> - URLMatcherIdToCondition; - - WebRequestConditionSet( - const Conditions& conditions, - const URLMatcherIdToCondition& match_id_to_condition, - const std::vector<const WebRequestCondition*>& conditions_without_urls); - - const URLMatcherIdToCondition match_id_to_condition_; - const Conditions conditions_; - const std::vector<const WebRequestCondition*> conditions_without_urls_; - - DISALLOW_COPY_AND_ASSIGN(WebRequestConditionSet); -}; +typedef DeclarativeConditionSet<WebRequestCondition> WebRequestConditionSet; } // namespace extensions 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 78ccb28..78e1b2b 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc @@ -11,6 +11,7 @@ #include "base/stringprintf.h" #include "base/values.h" #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h" +#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" #include "content/public/browser/resource_request_info.h" @@ -151,7 +152,7 @@ int WebRequestConditionAttributeResourceType::GetStages() const { } bool WebRequestConditionAttributeResourceType::IsFulfilled( - const WebRequestRule::RequestData& request_data) const { + const DeclarativeWebRequestData& request_data) const { if (!(request_data.stage & GetStages())) return false; const content::ResourceRequestInfo* info = @@ -222,7 +223,7 @@ int WebRequestConditionAttributeContentType::GetStages() const { } bool WebRequestConditionAttributeContentType::IsFulfilled( - const WebRequestRule::RequestData& request_data) const { + const DeclarativeWebRequestData& request_data) const { if (!(request_data.stage & GetStages())) return false; std::string content_type; @@ -567,7 +568,7 @@ int WebRequestConditionAttributeRequestHeaders::GetStages() const { } bool WebRequestConditionAttributeRequestHeaders::IsFulfilled( - const WebRequestRule::RequestData& request_data) const { + const DeclarativeWebRequestData& request_data) const { if (!(request_data.stage & GetStages())) return false; @@ -631,7 +632,7 @@ int WebRequestConditionAttributeResponseHeaders::GetStages() const { } bool WebRequestConditionAttributeResponseHeaders::IsFulfilled( - const WebRequestRule::RequestData& request_data) const { + const DeclarativeWebRequestData& request_data) const { if (!(request_data.stage & GetStages())) return false; @@ -702,7 +703,7 @@ int WebRequestConditionAttributeThirdParty::GetStages() const { } bool WebRequestConditionAttributeThirdParty::IsFulfilled( - const WebRequestRule::RequestData& request_data) const { + const DeclarativeWebRequestData& request_data) const { if (!(request_data.stage & GetStages())) return false; @@ -797,7 +798,7 @@ int WebRequestConditionAttributeStages::GetStages() const { } bool WebRequestConditionAttributeStages::IsFulfilled( - const WebRequestRule::RequestData& request_data) const { + const DeclarativeWebRequestData& request_data) const { // Note: removing '!=' triggers warning C4800 on the VS compiler. return (request_data.stage & GetStages()) != 0; } diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h index a87def4..db4daea 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h @@ -13,7 +13,6 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/scoped_vector.h" #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" #include "chrome/common/extensions/api/events.h" #include "webkit/glue/resource_type.h" @@ -28,6 +27,7 @@ class URLRequest; namespace extensions { class HeaderMatcher; +struct DeclarativeWebRequestData; // Base class for all condition attributes of the declarative Web Request API // except for condition attribute to test URLPatterns. @@ -61,7 +61,7 @@ class WebRequestConditionAttribute { // Returns whether the condition is fulfilled for this request. virtual bool IsFulfilled( - const WebRequestRule::RequestData& request_data) const = 0; + const DeclarativeWebRequestData& request_data) const = 0; virtual Type GetType() const = 0; @@ -97,7 +97,7 @@ class WebRequestConditionAttributeResourceType // Implementation of WebRequestConditionAttribute: virtual int GetStages() const OVERRIDE; virtual bool IsFulfilled( - const WebRequestRule::RequestData& request_data) const OVERRIDE; + const DeclarativeWebRequestData& request_data) const OVERRIDE; virtual Type GetType() const OVERRIDE; private: @@ -127,7 +127,7 @@ class WebRequestConditionAttributeContentType // Implementation of WebRequestConditionAttribute: virtual int GetStages() const OVERRIDE; virtual bool IsFulfilled( - const WebRequestRule::RequestData& request_data) const OVERRIDE; + const DeclarativeWebRequestData& request_data) const OVERRIDE; virtual Type GetType() const OVERRIDE; private: @@ -162,7 +162,7 @@ class WebRequestConditionAttributeRequestHeaders // Implementation of WebRequestConditionAttribute: virtual int GetStages() const OVERRIDE; virtual bool IsFulfilled( - const WebRequestRule::RequestData& request_data) const OVERRIDE; + const DeclarativeWebRequestData& request_data) const OVERRIDE; virtual Type GetType() const OVERRIDE; private: @@ -196,7 +196,7 @@ class WebRequestConditionAttributeResponseHeaders // Implementation of WebRequestConditionAttribute: virtual int GetStages() const OVERRIDE; virtual bool IsFulfilled( - const WebRequestRule::RequestData& request_data) const OVERRIDE; + const DeclarativeWebRequestData& request_data) const OVERRIDE; virtual Type GetType() const OVERRIDE; private: @@ -226,7 +226,7 @@ class WebRequestConditionAttributeThirdParty // Implementation of WebRequestConditionAttribute: virtual int GetStages() const OVERRIDE; virtual bool IsFulfilled( - const WebRequestRule::RequestData& request_data) const OVERRIDE; + const DeclarativeWebRequestData& request_data) const OVERRIDE; virtual Type GetType() const OVERRIDE; private: @@ -255,7 +255,7 @@ class WebRequestConditionAttributeStages // Implementation of WebRequestConditionAttribute: virtual int GetStages() const OVERRIDE; virtual bool IsFulfilled( - const WebRequestRule::RequestData& request_data) const OVERRIDE; + const DeclarativeWebRequestData& request_data) const OVERRIDE; virtual Type GetType() const OVERRIDE; private: diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc index ac0e29a..b0e2989 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc @@ -9,8 +9,8 @@ #include "base/memory/scoped_vector.h" #include "base/message_loop.h" #include "base/values.h" +#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" #include "content/public/browser/resource_request_info.h" #include "net/url_request/url_request_test_util.h" #include "net/test/test_server.h" @@ -90,14 +90,14 @@ TEST(WebRequestConditionAttributeTest, ResourceType) { content::ResourceRequestInfo::AllocateForTesting(&url_request_ok, ResourceType::MAIN_FRAME, NULL, -1, -1); EXPECT_TRUE(attribute->IsFulfilled( - WebRequestRule::RequestData(&url_request_ok, ON_BEFORE_REQUEST))); + DeclarativeWebRequestData(&url_request_ok, ON_BEFORE_REQUEST))); net::TestURLRequest url_request_fail( GURL("http://www.example.com"), NULL, &context); content::ResourceRequestInfo::AllocateForTesting(&url_request_ok, ResourceType::SUB_FRAME, NULL, -1, -1); EXPECT_FALSE(attribute->IsFulfilled( - WebRequestRule::RequestData(&url_request_fail, ON_BEFORE_REQUEST))); + DeclarativeWebRequestData(&url_request_fail, ON_BEFORE_REQUEST))); } TEST(WebRequestConditionAttributeTest, ContentType) { @@ -129,11 +129,11 @@ TEST(WebRequestConditionAttributeTest, ContentType) { EXPECT_EQ("", error); ASSERT_TRUE(attribute_include.get()); EXPECT_FALSE(attribute_include->IsFulfilled( - WebRequestRule::RequestData(&url_request, ON_BEFORE_REQUEST, - url_request.response_headers()))); + DeclarativeWebRequestData(&url_request, ON_BEFORE_REQUEST, + url_request.response_headers()))); EXPECT_TRUE(attribute_include->IsFulfilled( - WebRequestRule::RequestData(&url_request, ON_HEADERS_RECEIVED, - url_request.response_headers()))); + DeclarativeWebRequestData(&url_request, ON_HEADERS_RECEIVED, + url_request.response_headers()))); scoped_ptr<WebRequestConditionAttribute> attribute_exclude = WebRequestConditionAttribute::Create( @@ -141,8 +141,8 @@ TEST(WebRequestConditionAttributeTest, ContentType) { EXPECT_EQ("", error); ASSERT_TRUE(attribute_exclude.get()); EXPECT_FALSE(attribute_exclude->IsFulfilled( - WebRequestRule::RequestData(&url_request, ON_HEADERS_RECEIVED, - url_request.response_headers()))); + DeclarativeWebRequestData(&url_request, ON_HEADERS_RECEIVED, + url_request.response_headers()))); content_types.Clear(); content_types.Append(Value::CreateStringValue("something/invalid")); @@ -152,8 +152,8 @@ TEST(WebRequestConditionAttributeTest, ContentType) { EXPECT_EQ("", error); ASSERT_TRUE(attribute_unincluded.get()); EXPECT_FALSE(attribute_unincluded->IsFulfilled( - WebRequestRule::RequestData(&url_request, ON_HEADERS_RECEIVED, - url_request.response_headers()))); + DeclarativeWebRequestData(&url_request, ON_HEADERS_RECEIVED, + url_request.response_headers()))); scoped_ptr<WebRequestConditionAttribute> attribute_unexcluded = WebRequestConditionAttribute::Create( @@ -161,8 +161,8 @@ TEST(WebRequestConditionAttributeTest, ContentType) { EXPECT_EQ("", error); ASSERT_TRUE(attribute_unexcluded.get()); EXPECT_TRUE(attribute_unexcluded->IsFulfilled( - WebRequestRule::RequestData(&url_request, ON_HEADERS_RECEIVED, - url_request.response_headers()))); + DeclarativeWebRequestData(&url_request, ON_HEADERS_RECEIVED, + url_request.response_headers()))); } // Testing WebRequestConditionAttributeThirdParty. @@ -200,21 +200,21 @@ TEST(WebRequestConditionAttributeTest, ThirdParty) { continue; const RequestStage stage = static_cast<RequestStage>(i); url_request.set_first_party_for_cookies(url_empty); - EXPECT_FALSE(third_party_attribute->IsFulfilled(WebRequestRule::RequestData( + EXPECT_FALSE(third_party_attribute->IsFulfilled(DeclarativeWebRequestData( &url_request, stage))); - EXPECT_TRUE(first_party_attribute->IsFulfilled(WebRequestRule::RequestData( + EXPECT_TRUE(first_party_attribute->IsFulfilled(DeclarativeWebRequestData( &url_request, stage))); url_request.set_first_party_for_cookies(url_b); - EXPECT_TRUE(third_party_attribute->IsFulfilled(WebRequestRule::RequestData( + EXPECT_TRUE(third_party_attribute->IsFulfilled(DeclarativeWebRequestData( &url_request, stage))); - EXPECT_FALSE(first_party_attribute->IsFulfilled(WebRequestRule::RequestData( + EXPECT_FALSE(first_party_attribute->IsFulfilled(DeclarativeWebRequestData( &url_request, stage))); url_request.set_first_party_for_cookies(url_a); - EXPECT_FALSE(third_party_attribute->IsFulfilled(WebRequestRule::RequestData( + EXPECT_FALSE(third_party_attribute->IsFulfilled(DeclarativeWebRequestData( &url_request, stage))); - EXPECT_TRUE(first_party_attribute->IsFulfilled(WebRequestRule::RequestData( + EXPECT_TRUE(first_party_attribute->IsFulfilled(DeclarativeWebRequestData( &url_request, stage))); } } @@ -283,17 +283,17 @@ TEST(WebRequestConditionAttributeTest, Stages) { net::TestURLRequest url_request(url_empty, &delegate, &context); for (size_t i = 0; i < arraysize(active_stages); ++i) { - EXPECT_FALSE(empty_attribute->IsFulfilled(WebRequestRule::RequestData( + EXPECT_FALSE(empty_attribute->IsFulfilled(DeclarativeWebRequestData( &url_request, active_stages[i].first))); for (size_t j = 0; j < one_stage_attributes.size(); ++j) { EXPECT_EQ( i == j, - one_stage_attributes[j]->IsFulfilled(WebRequestRule::RequestData( + one_stage_attributes[j]->IsFulfilled(DeclarativeWebRequestData( &url_request, active_stages[i].first))); } - EXPECT_TRUE(attribute_with_all->IsFulfilled(WebRequestRule::RequestData( + EXPECT_TRUE(attribute_with_all->IsFulfilled(DeclarativeWebRequestData( &url_request, active_stages[i].first))); } } @@ -386,7 +386,7 @@ void MatchAndCheck(const std::vector< std::vector<const std::string*> >& tests, ASSERT_EQ("", error); ASSERT_TRUE(attribute.get()); - *result = attribute->IsFulfilled(WebRequestRule::RequestData( + *result = attribute->IsFulfilled(DeclarativeWebRequestData( url_request, stage, url_request->response_headers())); } diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_unittest.cc index 70eb2e2..0db6afb 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_unittest.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_unittest.cc @@ -10,7 +10,6 @@ #include "base/test/values_test_util.h" #include "base/values.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" #include "chrome/common/extensions/matcher/url_matcher_constants.h" #include "content/public/browser/resource_request_info.h" #include "net/url_request/url_request_test_util.h" @@ -70,7 +69,7 @@ TEST(WebRequestConditionTest, CreateCondition) { ASSERT_TRUE(result.get()); URLMatcherConditionSet::Vector url_matcher_condition_set; - url_matcher_condition_set.push_back(result->url_matcher_condition_set()); + result->GetURLMatcherConditionSets(&url_matcher_condition_set); matcher.AddConditionSets(url_matcher_condition_set); std::set<URLMatcherConditionSet::ID> url_match_ids; @@ -83,7 +82,7 @@ TEST(WebRequestConditionTest, CreateCondition) { ResourceType::MAIN_FRAME, NULL, -1, -1); EXPECT_TRUE(result->IsFulfilled( url_match_ids, - WebRequestRule::RequestData(&match_request, ON_BEFORE_REQUEST))); + DeclarativeWebRequestData(&match_request, ON_BEFORE_REQUEST))); GURL https_url("https://www.example.com"); net::TestURLRequest wrong_resource_type(https_url, NULL, &context); @@ -94,7 +93,7 @@ TEST(WebRequestConditionTest, CreateCondition) { ResourceType::SUB_FRAME, NULL, -1, -1); EXPECT_FALSE(result->IsFulfilled( url_match_ids, - WebRequestRule::RequestData(&wrong_resource_type, ON_BEFORE_REQUEST))); + DeclarativeWebRequestData(&wrong_resource_type, ON_BEFORE_REQUEST))); } // Conditions without UrlFilter attributes need to be independent of URL @@ -160,17 +159,17 @@ TEST(WebRequestConditionTest, NoUrlAttributes) { // attributes are fulfilled. EXPECT_FALSE(condition_no_url_false->IsFulfilled( dummy_match_set, - WebRequestRule::RequestData(&https_request, ON_BEFORE_REQUEST))); + DeclarativeWebRequestData(&https_request, ON_BEFORE_REQUEST))); EXPECT_TRUE(condition_no_url_true->IsFulfilled( dummy_match_set, - WebRequestRule::RequestData(&https_request, ON_BEFORE_REQUEST))); + DeclarativeWebRequestData(&https_request, ON_BEFORE_REQUEST))); // 2. An empty condition (in particular, without UrlFilter attributes) is // always fulfilled. EXPECT_TRUE(condition_empty->IsFulfilled( dummy_match_set, - WebRequestRule::RequestData(&https_request, ON_BEFORE_REQUEST))); + DeclarativeWebRequestData(&https_request, ON_BEFORE_REQUEST))); } TEST(WebRequestConditionTest, CreateConditionSet) { @@ -231,7 +230,7 @@ TEST(WebRequestConditionTest, CreateConditionSet) { EXPECT_TRUE(result->IsFulfilled( *(url_match_ids.begin()), url_match_ids, - WebRequestRule::RequestData(&http_request, ON_BEFORE_REQUEST))); + DeclarativeWebRequestData(&http_request, ON_BEFORE_REQUEST))); GURL https_url("https://www.example.com"); url_match_ids = matcher.MatchURL(https_url); @@ -240,7 +239,7 @@ TEST(WebRequestConditionTest, CreateConditionSet) { EXPECT_TRUE(result->IsFulfilled( *(url_match_ids.begin()), url_match_ids, - WebRequestRule::RequestData(&https_request, ON_BEFORE_REQUEST))); + DeclarativeWebRequestData(&https_request, ON_BEFORE_REQUEST))); // Check that both, hostPrefix and hostSuffix are evaluated. GURL https_foo_url("https://foo.example.com"); @@ -250,7 +249,7 @@ TEST(WebRequestConditionTest, CreateConditionSet) { EXPECT_FALSE(result->IsFulfilled( -1, url_match_ids, - WebRequestRule::RequestData(&https_foo_request, ON_BEFORE_REQUEST))); + DeclarativeWebRequestData(&https_foo_request, ON_BEFORE_REQUEST))); } TEST(WebRequestConditionTest, TestPortFilter) { diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.cc deleted file mode 100644 index 896a577..0000000 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" - -#include "base/logging.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h" -#include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" -#include "chrome/browser/extensions/api/web_request/web_request_permissions.h" -#include "chrome/browser/extensions/extension_info_map.h" -#include "chrome/common/extensions/extension.h" - -namespace { -const char kInvalidActionDatatype[] = "An action of a rule set had an invalid " - "structure that should have been caught by the JSON validator."; -const char kActionCannotBeExecuted[] = "An action can never be executed " - "because there are is no time in the request life-cycle during which the " - "conditions can be checked and the action can possibly be executed."; -} // namespace - -namespace extensions { - -WebRequestRule::WebRequestRule( - const GlobalRuleId& id, - base::Time extension_installation_time, - scoped_ptr<WebRequestConditionSet> conditions, - scoped_ptr<WebRequestActionSet> actions, - Priority priority) - : id_(id), - extension_installation_time_(extension_installation_time), - conditions_(conditions.release()), - actions_(actions.release()), - priority_(priority) { - CHECK(conditions_.get()); - CHECK(actions_.get()); -} - -WebRequestRule::~WebRequestRule() {} - -// static -bool WebRequestRule::CheckConsistency( - WebRequestConditionSet* conditions, - WebRequestActionSet* actions, - std::string* error) { - // Actions and conditions can be checked and executed in specific phases - // of each web request. We consider a rule inconsistent if there is an action - // that cannot be triggered by any condition. - for (WebRequestActionSet::Actions::const_iterator action_iter = - actions->actions().begin(); - action_iter != actions->actions().end(); - ++action_iter) { - bool found_matching_condition = false; - for (WebRequestConditionSet::Conditions::const_iterator condition_iter = - conditions->conditions().begin(); - condition_iter != conditions->conditions().end() && - !found_matching_condition; - ++condition_iter) { - // Test the intersection of bit masks, this is intentionally & and not &&. - if ((*action_iter)->GetStages() & (*condition_iter)->stages()) - found_matching_condition = true; - } - if (!found_matching_condition) { - *error = kActionCannotBeExecuted; - return false; - } - } - return true; -} - -// static -scoped_ptr<WebRequestRule> WebRequestRule::Create( - URLMatcherConditionFactory* url_matcher_condition_factory, - const std::string& extension_id, - base::Time extension_installation_time, - linked_ptr<RulesRegistry::Rule> rule, - std::string* error) { - scoped_ptr<WebRequestRule> error_result; - - scoped_ptr<WebRequestConditionSet> conditions = - WebRequestConditionSet::Create( - url_matcher_condition_factory, rule->conditions, error); - if (!error->empty()) - return error_result.Pass(); - CHECK(conditions.get()); - - bool bad_message = false; - scoped_ptr<WebRequestActionSet> actions = - WebRequestActionSet::Create(rule->actions, error, &bad_message); - if (bad_message) { - // TODO(battre) Export concept of bad_message to caller, the extension - // should be killed in case it is true. - *error = kInvalidActionDatatype; - return error_result.Pass(); - } - if (!error->empty() || bad_message) - return error_result.Pass(); - CHECK(actions.get()); - - if (!CheckConsistency(conditions.get(), actions.get(), error)) { - DCHECK(!error->empty()); - return error_result.Pass(); - } - - CHECK(rule->priority.get()); - int priority = *(rule->priority); - - GlobalRuleId rule_id(extension_id, *(rule->id)); - return scoped_ptr<WebRequestRule>( - new WebRequestRule(rule_id, extension_installation_time, - conditions.Pass(), actions.Pass(), priority)); -} - -std::list<LinkedPtrEventResponseDelta> WebRequestRule::CreateDeltas( - const ExtensionInfoMap* extension_info_map, - const RequestData& request_data, - bool crosses_incognito) const { - return actions_->CreateDeltas(extension_info_map, extension_id(), - request_data, crosses_incognito, - extension_installation_time_); -} - -int WebRequestRule::GetMinimumPriority() const { - return actions_->GetMinimumPriority(); -} - -} // namespace extensions diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h deleted file mode 100644 index e7c2dcf..0000000 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_WEBREQUEST_WEBREQUEST_RULE_H_ -#define CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_WEBREQUEST_WEBREQUEST_RULE_H_ - -#include <list> -#include <vector> - -#include "base/compiler_specific.h" -#include "base/time.h" -#include "chrome/browser/extensions/api/declarative/rules_registry.h" -#include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h" - -class ExtensionInfoMap; -class WebRequestPermissions; - -namespace extensions { -class Extension; -class URLMatcherConditionFactory; -class WebRequestActionSet; -class WebRequestConditionSet; -} - -namespace extension_web_request_api_helpers { -struct EventResponseDelta; -} - -namespace net { -class HttpResponseHeaders; -class URLRequest; -} - -namespace extensions { - -typedef linked_ptr<extension_web_request_api_helpers::EventResponseDelta> - LinkedPtrEventResponseDelta; - -// Representation of a rule of the declarative Web Request API -class WebRequestRule { - public: - typedef std::string ExtensionId; - typedef std::string RuleId; - typedef std::pair<ExtensionId, RuleId> GlobalRuleId; - typedef int Priority; - - struct RequestData { - RequestData(net::URLRequest* request, RequestStage stage) - : request(request), stage(stage), - original_response_headers(NULL) {} - RequestData(net::URLRequest* request, RequestStage stage, - const net::HttpResponseHeaders* original_response_headers) - : request(request), stage(stage), - original_response_headers(original_response_headers) {} - net::URLRequest* request; - RequestStage stage; - // Additional information about requests that is not - // available in all request stages. - const net::HttpResponseHeaders* original_response_headers; - }; - - WebRequestRule(const GlobalRuleId& id, - base::Time extension_installation_time, - scoped_ptr<WebRequestConditionSet> conditions, - scoped_ptr<WebRequestActionSet> actions, - Priority priority); - virtual ~WebRequestRule(); - - // If |error| is empty, the translation was successful and the returned - // rule is internally consistent. - static scoped_ptr<WebRequestRule> Create( - URLMatcherConditionFactory* url_matcher_condition_factory, - const std::string& extension_id, - base::Time extension_installation_time, - linked_ptr<RulesRegistry::Rule> rule, - std::string* error); - - const GlobalRuleId& id() const { return id_; } - const std::string& extension_id() const { return id_.first; } - const WebRequestConditionSet& conditions() const { return *conditions_; } - const WebRequestActionSet& actions() const { return *actions_; } - Priority priority() const { return priority_; } - - // Creates all deltas resulting from the ActionSet. This function should - // only be called when the conditions_ are fulfilled (from a semantic point - // of view; no harm is done if this function is called at other times for - // testing purposes). - // If |extension| is set, deltas are suppressed if the |extension| does not - // have have sufficient permissions to modify the request. The returned list - // may be empty in this case. - std::list<LinkedPtrEventResponseDelta> CreateDeltas( - const ExtensionInfoMap* extension_info_map, - const RequestData& request_data, - bool crosses_incognito) const; - - // Returns the minimum priority of rules that may be evaluated after - // this rule. Defaults to MAX_INT. Only valid if the conditions of this rule - // are fulfilled. - Priority GetMinimumPriority() const; - - private: - // Checks whether the set of |conditions| and |actions| are consistent, - // meaning for example that we do not allow combining an |action| that needs - // to be executed before the |condition| can be fulfilled. - // Returns true in case of consistency and MUST set |error| otherwise. - static bool CheckConsistency(WebRequestConditionSet* conditions, - WebRequestActionSet* actions, - std::string* error); - - GlobalRuleId id_; - base::Time extension_installation_time_; // For precedences of rules. - scoped_ptr<WebRequestConditionSet> conditions_; - scoped_ptr<WebRequestActionSet> actions_; - Priority priority_; - - DISALLOW_COPY_AND_ASSIGN(WebRequestRule); -}; - -} // namespace extensions - -#endif // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_WEBREQUEST_WEBREQUEST_RULE_H_ diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule_unittest.cc deleted file mode 100644 index d3caa4e..0000000 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule_unittest.cc +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" - -#include "base/json/json_reader.h" -#include "base/memory/linked_ptr.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h" -#include "chrome/common/extensions/matcher/url_matcher.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace extensions { - -namespace { -const char kExtId[] = "ext1"; -} // namespace - -TEST(WebRequestRuleTest, Create) { - const char kRule[] = - "{ \n" - " \"id\": \"rule1\", \n" - " \"conditions\": [ \n" - " { \n" - " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n" - " \"url\": {\"hostSuffix\": \"foo.com\"}, \n" - " \"contentType\": [\"image/jpeg\"] \n" - " } \n" - " ], \n" - " \"actions\": [ \n" - " { \n" - " \"instanceType\": \"declarativeWebRequest.CancelRequest\" \n" - " } \n" - " ], \n" - " \"priority\": 200 \n" - "} "; - - scoped_ptr<Value> value(base::JSONReader::Read(kRule)); - ASSERT_TRUE(value.get()); - - linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule); - ASSERT_TRUE(RulesRegistry::Rule::Populate(*value, rule.get())); - - URLMatcher matcher; - std::string error; - scoped_ptr<WebRequestRule> web_request_rule( - WebRequestRule::Create(matcher.condition_factory(), kExtId, base::Time(), - rule, &error)); - ASSERT_TRUE(web_request_rule.get()); - EXPECT_TRUE(error.empty()); - - EXPECT_EQ(kExtId, web_request_rule->id().first); - EXPECT_EQ("rule1", web_request_rule->id().second); - - EXPECT_EQ(200, web_request_rule->priority()); - - const WebRequestConditionSet& condition_set = web_request_rule->conditions(); - const WebRequestConditionSet::Conditions conditions = - condition_set.conditions(); - ASSERT_EQ(1u, conditions.size()); - linked_ptr<WebRequestCondition> condition = conditions[0]; - const WebRequestConditionAttributes& condition_attributes = - condition->condition_attributes(); - ASSERT_EQ(1u, condition_attributes.size()); - EXPECT_EQ(WebRequestConditionAttribute::CONDITION_CONTENT_TYPE, - condition_attributes[0]->GetType()); - - const WebRequestActionSet& action_set = web_request_rule->actions(); - const WebRequestActionSet::Actions& actions = action_set.actions(); - ASSERT_EQ(1u, actions.size()); - EXPECT_EQ(WebRequestAction::ACTION_CANCEL_REQUEST, actions[0]->GetType()); -} - -TEST(WebRequestRuleTest, CheckConsistency) { - // The contentType condition can only be evaluated during ON_HEADERS_RECEIVED - // but the redirect action can only be executed during ON_BEFORE_REQUEST. - // Therefore, this is an inconsistent rule that needs to be flagged. - const char kRule[] = - "{ \n" - " \"id\": \"rule1\", \n" - " \"conditions\": [ \n" - " { \n" - " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n" - " \"url\": {\"hostSuffix\": \"foo.com\"}, \n" - " \"contentType\": [\"image/jpeg\"] \n" - " } \n" - " ], \n" - " \"actions\": [ \n" - " { \n" - " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n" - " \"redirectUrl\": \"http://bar.com\" \n" - " } \n" - " ], \n" - " \"priority\": 200 \n" - "} "; - - scoped_ptr<Value> value(base::JSONReader::Read(kRule)); - ASSERT_TRUE(value.get()); - - linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule); - ASSERT_TRUE(RulesRegistry::Rule::Populate(*value, rule.get())); - - URLMatcher matcher; - std::string error; - scoped_ptr<WebRequestRule> web_request_rule( - WebRequestRule::Create(matcher.condition_factory(), kExtId, base::Time(), - rule, &error)); - EXPECT_FALSE(web_request_rule.get()); - EXPECT_FALSE(error.empty()); -} - -} // namespace extensions diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc index 06477a1..0e90c2d 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc @@ -15,6 +15,12 @@ #include "chrome/browser/extensions/extension_system.h" #include "net/url_request/url_request.h" +namespace { +const char kActionCannotBeExecuted[] = "An action can never be executed " + "because there are is no time in the request life-cycle during which the " + "conditions can be checked and the action can possibly be executed."; +} // namespace + namespace extensions { WebRequestRulesRegistry::WebRequestRulesRegistry(Profile* profile, @@ -26,7 +32,7 @@ WebRequestRulesRegistry::WebRequestRulesRegistry(Profile* profile, std::set<const WebRequestRule*> WebRequestRulesRegistry::GetMatches( - const WebRequestRule::RequestData& request_data) { + const DeclarativeWebRequestData& request_data) { typedef std::set<const WebRequestRule*> RuleSet; typedef std::set<URLMatcherConditionSet::ID> URLMatches; @@ -57,7 +63,7 @@ WebRequestRulesRegistry::GetMatches( std::list<LinkedPtrEventResponseDelta> WebRequestRulesRegistry::CreateDeltas( const ExtensionInfoMap* extension_info_map, - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, bool crosses_incognito) { if (webrequest_rules_.empty()) return std::list<LinkedPtrEventResponseDelta>(); @@ -107,8 +113,12 @@ std::list<LinkedPtrEventResponseDelta> WebRequestRulesRegistry::CreateDeltas( if (priority_of_rule < current_min_priority) continue; - std::list<LinkedPtrEventResponseDelta> rule_result = - rule->CreateDeltas(extension_info_map, request_data, crosses_incognito); + + std::list<LinkedPtrEventResponseDelta> rule_result; + WebRequestAction::ApplyInfo apply_info = { + extension_info_map, request_data, crosses_incognito, &rule_result + }; + rule->Apply(&apply_info); result.splice(result.begin(), rule_result); min_priorities[extension_id] = std::max(current_min_priority, @@ -133,7 +143,8 @@ std::string WebRequestRulesRegistry::AddRulesImpl( scoped_ptr<WebRequestRule> webrequest_rule( WebRequestRule::Create(url_matcher_.condition_factory(), extension_id, - extension_installation_time, *rule, &error)); + extension_installation_time, *rule, + &CheckConsistency, &error)); if (!error.empty()) { // We don't return here, because we want to clear temporary // condition sets in the url_matcher_. @@ -259,4 +270,34 @@ void WebRequestRulesRegistry::ClearCacheOnNavigation() { extension_web_request_api_helpers::ClearCacheOnNavigation(); } +// static +bool WebRequestRulesRegistry::CheckConsistency( + const WebRequestConditionSet* conditions, + const WebRequestActionSet* actions, + std::string* error) { + // Actions and conditions can be checked and executed in specific phases + // of each web request. We consider a rule inconsistent if there is an action + // that cannot be triggered by any condition. + for (WebRequestActionSet::Actions::const_iterator action_iter = + actions->actions().begin(); + action_iter != actions->actions().end(); + ++action_iter) { + bool found_matching_condition = false; + for (WebRequestConditionSet::Conditions::const_iterator condition_iter = + conditions->conditions().begin(); + condition_iter != conditions->conditions().end() && + !found_matching_condition; + ++condition_iter) { + // Test the intersection of bit masks, this is intentionally & and not &&. + if ((*action_iter)->GetStages() & (*condition_iter)->stages()) + found_matching_condition = true; + } + if (!found_matching_condition) { + *error = kActionCannotBeExecuted; + return false; + } + } + return true; +} + } // namespace extensions diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h index 6433f5c..9746a9b 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h @@ -14,9 +14,11 @@ #include "base/time.h" #include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" +#include "chrome/browser/extensions/api/declarative/declarative_rule.h" #include "chrome/browser/extensions/api/declarative/rules_registry_with_cache.h" #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" +#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h" +#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h" #include "chrome/browser/extensions/extension_info_map.h" #include "chrome/common/extensions/matcher/url_matcher.h" @@ -35,6 +37,10 @@ namespace extensions { class RulesRegistryService; +typedef linked_ptr<extension_web_request_api_helpers::EventResponseDelta> + LinkedPtrEventResponseDelta; +typedef DeclarativeRule<WebRequestCondition, WebRequestAction> WebRequestRule; + // The WebRequestRulesRegistry is responsible for managing // the internal representation of rules for the Declarative Web Request API. // @@ -70,13 +76,13 @@ class WebRequestRulesRegistry : public RulesRegistryWithCache { // TODO(battre): This will become an implementation detail, because we need // a way to also execute the actions of the rules. std::set<const WebRequestRule*> GetMatches( - const WebRequestRule::RequestData& request_data); + const DeclarativeWebRequestData& request_data); // Returns which modifications should be executed on the network request // according to the rules registered in this registry. std::list<LinkedPtrEventResponseDelta> CreateDeltas( const ExtensionInfoMap* extension_info_map, - const WebRequestRule::RequestData& request_data, + const DeclarativeWebRequestData& request_data, bool crosses_incognito); // Implementation of RulesRegistryWithCache: @@ -107,6 +113,14 @@ class WebRequestRulesRegistry : public RulesRegistryWithCache { } private: + // Checks whether the set of |conditions| and |actions| are consistent, + // meaning for example that we do not allow combining an |action| that needs + // to be executed before the |condition| can be fulfilled. + // Returns true in case of consistency and MUST set |error| otherwise. + static bool CheckConsistency(const WebRequestConditionSet* conditions, + const WebRequestActionSet* actions, + std::string* error); + typedef std::map<URLMatcherConditionSet::ID, WebRequestRule*> RuleTriggers; typedef std::map<WebRequestRule::GlobalRuleId, linked_ptr<WebRequestRule> > RulesMap; diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc index 0b89abb..a2b8dc7 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc @@ -6,17 +6,18 @@ #include <vector> +#include "base/json/json_reader.h" #include "base/memory/linked_ptr.h" #include "base/message_loop.h" #include "base/stl_util.h" #include "base/test/values_test_util.h" #include "base/values.h" -#include "chrome/common/extensions/matcher/url_matcher_constants.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" +#include "chrome/common/extensions/matcher/url_matcher_constants.h" #include "content/public/test/test_browser_thread.h" #include "net/url_request/url_request_test_util.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -30,6 +31,8 @@ const char kRuleId4[] = "rule4"; namespace extensions { +using testing::HasSubstr; + namespace helpers = extension_web_request_api_helpers; namespace keys = declarative_webrequest_constants; namespace keys2 = url_matcher_constants; @@ -317,7 +320,7 @@ TEST_F(WebRequestRulesRegistryTest, AddRulesImpl) { net::TestURLRequestContext context; net::TestURLRequest http_request(http_url, NULL, &context); matches = registry->GetMatches( - WebRequestRule::RequestData(&http_request, ON_BEFORE_REQUEST)); + DeclarativeWebRequestData(&http_request, ON_BEFORE_REQUEST)); EXPECT_EQ(2u, matches.size()); std::set<WebRequestRule::GlobalRuleId> matches_ids; @@ -330,7 +333,7 @@ TEST_F(WebRequestRulesRegistryTest, AddRulesImpl) { GURL foobar_url("http://www.foobar.com"); net::TestURLRequest foobar_request(foobar_url, NULL, &context); matches = registry->GetMatches( - WebRequestRule::RequestData(&foobar_request, ON_BEFORE_REQUEST)); + DeclarativeWebRequestData(&foobar_request, ON_BEFORE_REQUEST)); EXPECT_EQ(1u, matches.size()); WebRequestRule::GlobalRuleId expected_pair = std::make_pair(kExtensionId, kRuleId2); @@ -458,7 +461,7 @@ TEST_F(WebRequestRulesRegistryTest, Precedences) { std::list<LinkedPtrEventResponseDelta> deltas = registry->CreateDeltas( NULL, - WebRequestRule::RequestData(&request, ON_BEFORE_REQUEST), + DeclarativeWebRequestData(&request, ON_BEFORE_REQUEST), false); // The second extension is installed later and will win for this reason @@ -508,7 +511,7 @@ TEST_F(WebRequestRulesRegistryTest, Priorities) { std::list<LinkedPtrEventResponseDelta> deltas = registry->CreateDeltas( NULL, - WebRequestRule::RequestData(&request, ON_BEFORE_REQUEST), + DeclarativeWebRequestData(&request, ON_BEFORE_REQUEST), false); // The redirect by the first extension is ignored due to the ignore rule. @@ -550,11 +553,51 @@ TEST_F(WebRequestRulesRegistryTest, GetMatchesCheckFulfilled) { net::TestURLRequestContext context; net::TestURLRequest http_request(http_url, NULL, &context); matches = registry->GetMatches( - WebRequestRule::RequestData(&http_request, ON_BEFORE_REQUEST)); + DeclarativeWebRequestData(&http_request, ON_BEFORE_REQUEST)); EXPECT_EQ(1u, matches.size()); WebRequestRule::GlobalRuleId expected_pair = std::make_pair(kExtensionId, kRuleId3); EXPECT_EQ(expected_pair, (*matches.begin())->id()); } +TEST_F(WebRequestRulesRegistryTest, CheckConsistency) { + // The contentType condition can only be evaluated during ON_HEADERS_RECEIVED + // but the redirect action can only be executed during ON_BEFORE_REQUEST. + // Therefore, this is an inconsistent rule that needs to be flagged. + const char kRule[] = + "{ \n" + " \"id\": \"rule1\", \n" + " \"conditions\": [ \n" + " { \n" + " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n" + " \"url\": {\"hostSuffix\": \"foo.com\"}, \n" + " \"contentType\": [\"image/jpeg\"] \n" + " } \n" + " ], \n" + " \"actions\": [ \n" + " { \n" + " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n" + " \"redirectUrl\": \"http://bar.com\" \n" + " } \n" + " ], \n" + " \"priority\": 200 \n" + "} "; + + scoped_ptr<Value> value(base::JSONReader::Read(kRule)); + ASSERT_TRUE(value.get()); + + std::vector<linked_ptr<RulesRegistry::Rule> > rules; + rules.push_back(make_linked_ptr(new RulesRegistry::Rule)); + ASSERT_TRUE(RulesRegistry::Rule::Populate(*value, rules.back().get())); + + scoped_refptr<WebRequestRulesRegistry> registry( + new TestWebRequestRulesRegistry()); + + URLMatcher matcher; + std::string error = registry->AddRulesImpl(kExtensionId, rules); + EXPECT_THAT(error, HasSubstr("no time in the request life-cycle")); + EXPECT_TRUE(registry->IsEmpty()); +} + + } // namespace extensions diff --git a/chrome/browser/extensions/api/web_request/web_request_api.cc b/chrome/browser/extensions/api/web_request/web_request_api.cc index b53ef97..a1e07b2 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api.cc +++ b/chrome/browser/extensions/api/web_request/web_request_api.cc @@ -19,7 +19,6 @@ #include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" -#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h" #include "chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.h" #include "chrome/browser/extensions/api/web_request/upload_data_presenter.h" @@ -1648,7 +1647,7 @@ bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules( helpers::EventResponseDeltas result = rules_registry->CreateDeltas( extension_info_map, - extensions::WebRequestRule::RequestData( + extensions::DeclarativeWebRequestData( request, request_stage, original_response_headers), i->second); diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index c7bf5d8..567dd3d 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -137,6 +137,7 @@ 'browser/extensions/api/debugger/debugger_api_constants.h', 'browser/extensions/api/declarative/declarative_api.cc', 'browser/extensions/api/declarative/declarative_api.h', + 'browser/extensions/api/declarative/declarative_rule.h', 'browser/extensions/api/declarative/initializing_rules_registry.cc', 'browser/extensions/api/declarative/initializing_rules_registry.h', 'browser/extensions/api/declarative/rules_registry.cc', @@ -159,8 +160,6 @@ 'browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h', 'browser/extensions/api/declarative_webrequest/webrequest_constants.cc', 'browser/extensions/api/declarative_webrequest/webrequest_constants.h', - 'browser/extensions/api/declarative_webrequest/webrequest_rule.cc', - 'browser/extensions/api/declarative_webrequest/webrequest_rule.h', 'browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc', 'browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h', 'browser/extensions/api/developer_private/developer_private_api.cc', @@ -774,7 +773,6 @@ ['include', '^browser/extensions/api/declarative_webrequest/webrequest_condition.cc'], ['include', '^browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc'], ['include', '^browser/extensions/api/declarative_webrequest/webrequest_constants.cc'], - ['include', '^browser/extensions/api/declarative_webrequest/webrequest_rule.cc'], ['include', '^browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc'], ['include', '^browser/extensions/api/extension_action/extension_page_actions_api_constants.cc'], ['include', '^browser/extensions/api/messaging/extension_message_port.cc'], diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 72b8d41..0312d05 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -651,13 +651,13 @@ 'browser/extensions/api/content_settings/content_settings_store_unittest.cc', 'browser/extensions/api/content_settings/content_settings_unittest.cc', 'browser/extensions/api/cookies/cookies_unittest.cc', + 'browser/extensions/api/declarative/declarative_rule_unittest.cc', 'browser/extensions/api/declarative/initializing_rules_registry_unittest.cc', 'browser/extensions/api/declarative/rules_registry_service_unittest.cc', 'browser/extensions/api/declarative/rules_registry_with_cache_unittest.cc', 'browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc', 'browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc', 'browser/extensions/api/declarative_webrequest/webrequest_condition_unittest.cc', - 'browser/extensions/api/declarative_webrequest/webrequest_rule_unittest.cc', 'browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc', 'browser/extensions/api/dial/dial_device_data_unittest.cc', 'browser/extensions/api/dial/dial_registry_unittest.cc', diff --git a/tools/json_schema_compiler/any.cc b/tools/json_schema_compiler/any.cc index b429567..cd4e5c3 100644 --- a/tools/json_schema_compiler/any.cc +++ b/tools/json_schema_compiler/any.cc @@ -12,6 +12,10 @@ namespace any { Any::Any() {} +Any::Any(scoped_ptr<base::Value> from_value) + : value_(from_value.Pass()) { +} + Any::~Any() {} void Any::Init(const base::Value& from_value) { diff --git a/tools/json_schema_compiler/any.h b/tools/json_schema_compiler/any.h index 9e44048..83b84d6 100644 --- a/tools/json_schema_compiler/any.h +++ b/tools/json_schema_compiler/any.h @@ -19,6 +19,7 @@ namespace any { class Any { public: Any(); + explicit Any(scoped_ptr<base::Value> from_value); ~Any(); // Initializes the Value in this Any. Fails if already initialized. |