diff options
author | vabr@chromium.org <vabr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-27 07:44:24 +0000 |
---|---|---|
committer | vabr@chromium.org <vabr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-27 07:44:24 +0000 |
commit | 04e4bbeda497feac5f7fdebabbb13c885294e253 (patch) | |
tree | 5ea6ffccfd04698a77b1b8f340c8892085c07620 /chrome | |
parent | 54e7e7430fe8ded2a77fead9cc436b5d568d540e (diff) | |
download | chromium_src-04e4bbeda497feac5f7fdebabbb13c885294e253.zip chromium_src-04e4bbeda497feac5f7fdebabbb13c885294e253.tar.gz chromium_src-04e4bbeda497feac5f7fdebabbb13c885294e253.tar.bz2 |
Almost all actions in Declarative Web Request require all_urls host permissions
The whitelisted actions are:
* ignoring a rule
* cancelling a request
* redirecting to a blank image or an empty document
+ SendMessageToExtension only checks the request's URL against the host permissions (does not require full permissions).
BUG=145456
Review URL: https://chromiumcodereview.appspot.com/14358004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@196959 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
31 files changed, 1064 insertions, 648 deletions
diff --git a/chrome/browser/extensions/api/declarative/declarative_rule.h b/chrome/browser/extensions/api/declarative/declarative_rule.h index e941155..a2dd1f5 100644 --- a/chrome/browser/extensions/api/declarative/declarative_rule.h +++ b/chrome/browser/extensions/api/declarative/declarative_rule.h @@ -15,6 +15,7 @@ #include <string> #include <vector> +#include "base/callback.h" #include "base/memory/linked_ptr.h" #include "base/memory/scoped_vector.h" #include "base/stl_util.h" @@ -190,9 +191,9 @@ class DeclarativeRule { // 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); + typedef base::Callback<bool(const ConditionSet* conditions, + const ActionSet* actions, + std::string* error)> ConsistencyChecker; DeclarativeRule(const GlobalRuleId& id, const Tags& tags, @@ -448,8 +449,8 @@ DeclarativeRule<ConditionT, ActionT>::Create( return error_result.Pass(); CHECK(actions.get()); - if (check_consistency && - !check_consistency(conditions.get(), actions.get(), error)) { + if (!check_consistency.is_null() && + !check_consistency.Run(conditions.get(), actions.get(), error)) { DCHECK(!error->empty()); return error_result.Pass(); } diff --git a/chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc b/chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc index 5bf39d0..13dc9d8 100644 --- a/chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc +++ b/chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc @@ -4,6 +4,7 @@ #include "chrome/browser/extensions/api/declarative/declarative_rule.h" +#include "base/bind.h" #include "base/message_loop.h" #include "base/test/values_test_util.h" #include "base/values.h" @@ -305,8 +306,12 @@ TEST(DeclarativeRuleTest, Create) { URLMatcher matcher; std::string error; - scoped_ptr<Rule> rule(Rule::Create(matcher.condition_factory(), kExtensionId, - install_time, json_rule, NULL, &error)); + scoped_ptr<Rule> rule(Rule::Create(matcher.condition_factory(), + kExtensionId, + install_time, + json_rule, + Rule::ConsistencyChecker(), + &error)); EXPECT_EQ("", error); ASSERT_TRUE(rule.get()); @@ -367,7 +372,7 @@ TEST(DeclarativeRuleTest, CheckConsistency) { json_rule.get())); scoped_ptr<Rule> rule( Rule::Create(matcher.condition_factory(), kExtensionId, base::Time(), - json_rule, &AtLeastOneCondition, &error)); + json_rule, base::Bind(AtLeastOneCondition), &error)); EXPECT_TRUE(rule); EXPECT_EQ("", error); @@ -385,7 +390,7 @@ TEST(DeclarativeRuleTest, CheckConsistency) { "}"), json_rule.get())); rule = Rule::Create(matcher.condition_factory(), kExtensionId, base::Time(), - json_rule, &AtLeastOneCondition, &error); + json_rule, base::Bind(AtLeastOneCondition), &error); EXPECT_FALSE(rule); EXPECT_EQ("No conditions", error); } diff --git a/chrome/browser/extensions/api/declarative_content/content_rules_registry.cc b/chrome/browser/extensions/api/declarative_content/content_rules_registry.cc index eb95b47..9589633 100644 --- a/chrome/browser/extensions/api/declarative_content/content_rules_registry.cc +++ b/chrome/browser/extensions/api/declarative_content/content_rules_registry.cc @@ -139,8 +139,12 @@ std::string ContentRulesRegistry::AddRulesImpl( DCHECK(content_rules_.find(rule_id) == content_rules_.end()); scoped_ptr<ContentRule> content_rule( - ContentRule::Create(url_matcher_.condition_factory(), extension_id, - extension_installation_time, *rule, NULL, &error)); + ContentRule::Create(url_matcher_.condition_factory(), + extension_id, + extension_installation_time, + *rule, + ContentRule::ConsistencyChecker(), + &error)); if (!error.empty()) { // Clean up temporary condition sets created during rule creation. url_matcher_.ClearUnusedConditionSets(); diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc index 2459ee9..5394689 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc @@ -329,10 +329,16 @@ struct WebRequestActionFactory { (* FactoryMethod)(const base::DictionaryValue* /* dict */ , std::string* /* error */, bool* /* bad_message */); + + typedef std::map<WebRequestAction::Type, const std::string> ActionNames; + // Maps the name of a declarativeWebRequest action type to the factory // function creating it. std::map<std::string, FactoryMethod> factory_methods; + // Translates action types into the corresponding JavaScript names. + ActionNames action_names; + WebRequestActionFactory() { factory_methods[keys::kAddRequestCookieType] = &CreateRequestCookieAction; @@ -369,6 +375,44 @@ struct WebRequestActionFactory { &CreateIgnoreRulesAction; factory_methods[keys::kSendMessageToExtensionType] = &CreateSendMessageToExtensionAction; + +#define INSERT_ACTION_NAME(type, name) \ + action_names.insert(ActionNames::value_type(type, name)); + std::vector<std::string> names_buffer; + names_buffer.push_back(keys::kAddRequestCookieType); + names_buffer.push_back(keys::kEditRequestCookieType); + names_buffer.push_back(keys::kRemoveRequestCookieType); + INSERT_ACTION_NAME(WebRequestAction::ACTION_MODIFY_REQUEST_COOKIE, + JoinString(names_buffer, ", ")); + names_buffer.clear(); + names_buffer.push_back(keys::kAddResponseCookieType); + names_buffer.push_back(keys::kEditResponseCookieType); + names_buffer.push_back(keys::kRemoveResponseCookieType); + INSERT_ACTION_NAME(WebRequestAction::ACTION_MODIFY_RESPONSE_COOKIE, + JoinString(names_buffer, ", ")); + INSERT_ACTION_NAME(WebRequestAction::ACTION_ADD_RESPONSE_HEADER, + keys::kAddResponseHeaderType); + INSERT_ACTION_NAME(WebRequestAction::ACTION_CANCEL_REQUEST, + keys::kCancelRequestType); + INSERT_ACTION_NAME(WebRequestAction::ACTION_REDIRECT_BY_REGEX_DOCUMENT, + keys::kRedirectByRegExType); + INSERT_ACTION_NAME(WebRequestAction::ACTION_REDIRECT_REQUEST, + keys::kRedirectRequestType); + INSERT_ACTION_NAME(WebRequestAction::ACTION_REDIRECT_TO_TRANSPARENT_IMAGE, + keys::kRedirectToTransparentImageType); + INSERT_ACTION_NAME(WebRequestAction::ACTION_REDIRECT_TO_EMPTY_DOCUMENT, + keys::kRedirectToEmptyDocumentType); + INSERT_ACTION_NAME(WebRequestAction::ACTION_SET_REQUEST_HEADER, + keys::kSetRequestHeaderType); + INSERT_ACTION_NAME(WebRequestAction::ACTION_REMOVE_REQUEST_HEADER, + keys::kRemoveRequestHeaderType); + INSERT_ACTION_NAME(WebRequestAction::ACTION_REMOVE_RESPONSE_HEADER, + keys::kRemoveResponseHeaderType); + INSERT_ACTION_NAME(WebRequestAction::ACTION_IGNORE_RULES, + keys::kIgnoreRulesType); + INSERT_ACTION_NAME(WebRequestAction::ACTION_SEND_MESSAGE_TO_EXTENSION, + keys::kSendMessageToExtensionType); +#undef INSERT_ACTION_NAME } }; @@ -381,17 +425,19 @@ base::LazyInstance<WebRequestActionFactory>::Leaky // WebRequestAction // -WebRequestAction::WebRequestAction() {} - WebRequestAction::~WebRequestAction() {} -int WebRequestAction::GetMinimumPriority() const { - return std::numeric_limits<int>::min(); +const std::string& WebRequestAction::GetName() const { + const WebRequestActionFactory::ActionNames& names = + g_web_request_action_factory.Get().action_names; + std::map<WebRequestAction::Type, const std::string>::const_iterator it = + names.find(GetType()); + CHECK(it != names.end()); + return it->second; } -WebRequestAction::HostPermissionsStrategy -WebRequestAction::GetHostPermissionsStrategy() const { - return STRATEGY_DEFAULT; +int WebRequestAction::GetMinimumPriority() const { + return std::numeric_limits<int>::min(); } bool WebRequestAction::HasPermission(const ExtensionInfoMap* extension_info_map, @@ -406,31 +452,21 @@ bool WebRequestAction::HasPermission(const ExtensionInfoMap* extension_info_map, if (!extension_info_map) return true; - HostPermissionsStrategy strategy = GetHostPermissionsStrategy(); - if (strategy == STRATEGY_NONE || strategy == STRATEGY_DEFAULT) { - bool check_host_permissions = strategy != STRATEGY_NONE; - return WebRequestPermissions::CanExtensionAccessURL( - extension_info_map, extension_id, request->url(), crosses_incognito, - check_host_permissions); - } - return true; -} - -bool WebRequestAction::DeltaHasPermission( - const ExtensionInfoMap* extension_info_map, - const std::string& extension_id, - const net::URLRequest* request, - bool crosses_incognito, - const LinkedPtrEventResponseDelta& delta) const { - if (GetHostPermissionsStrategy() == STRATEGY_ALLOW_SAME_DOMAIN) { - return - net::RegistryControlledDomainService::SameDomainOrHost( - request->url(), delta->new_url) || - WebRequestPermissions::CanExtensionAccessURL( - extension_info_map, extension_id, request->url(), crosses_incognito, - true); + WebRequestPermissions::HostPermissionsCheck permission_check = + WebRequestPermissions::REQUIRE_ALL_URLS; + switch (host_permissions_strategy()) { + case STRATEGY_DEFAULT: // Default value is already set. + break; + case STRATEGY_NONE: + permission_check = WebRequestPermissions::DO_NOT_CHECK_HOST; + break; + case STRATEGY_HOST: + permission_check = WebRequestPermissions::REQUIRE_HOST_PERMISSION; + break; } - return true; + return WebRequestPermissions::CanExtensionAccessURL( + extension_info_map, extension_id, request->url(), crosses_incognito, + permission_check); } // static @@ -468,13 +504,8 @@ void WebRequestAction::Apply(const std::string& extension_id, 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); - } + if (delta.get()) + apply_info->deltas->push_back(delta); if (GetType() == WebRequestAction::ACTION_IGNORE_RULES) { const WebRequestIgnoreRulesAction* ignore_action = static_cast<const WebRequestIgnoreRulesAction*>(this); @@ -484,12 +515,15 @@ void WebRequestAction::Apply(const std::string& extension_id, } } +WebRequestAction::WebRequestAction(HostPermissionsStrategy strategy) + : host_permissions_strategy_(strategy) {} // // WebRequestCancelAction // -WebRequestCancelAction::WebRequestCancelAction() {} +WebRequestCancelAction::WebRequestCancelAction() + : WebRequestAction(STRATEGY_NONE) {} WebRequestCancelAction::~WebRequestCancelAction() {} @@ -502,11 +536,6 @@ WebRequestAction::Type WebRequestCancelAction::GetType() const { return WebRequestAction::ACTION_CANCEL_REQUEST; } -WebRequestAction::HostPermissionsStrategy -WebRequestCancelAction::GetHostPermissionsStrategy() const { - return WebRequestAction::STRATEGY_NONE; -} - LinkedPtrEventResponseDelta WebRequestCancelAction::CreateDelta( const WebRequestData& request_data, const std::string& extension_id, @@ -523,7 +552,7 @@ LinkedPtrEventResponseDelta WebRequestCancelAction::CreateDelta( // WebRequestRedirectAction::WebRequestRedirectAction(const GURL& redirect_url) - : redirect_url_(redirect_url) {} + : WebRequestAction(STRATEGY_DEFAULT), redirect_url_(redirect_url) {} WebRequestRedirectAction::~WebRequestRedirectAction() {} @@ -535,11 +564,6 @@ WebRequestAction::Type WebRequestRedirectAction::GetType() const { return WebRequestAction::ACTION_REDIRECT_REQUEST; } -WebRequestAction::HostPermissionsStrategy -WebRequestRedirectAction::GetHostPermissionsStrategy() const { - return WebRequestAction::STRATEGY_ALLOW_SAME_DOMAIN; -} - LinkedPtrEventResponseDelta WebRequestRedirectAction::CreateDelta( const WebRequestData& request_data, const std::string& extension_id, @@ -558,7 +582,8 @@ LinkedPtrEventResponseDelta WebRequestRedirectAction::CreateDelta( // WebRequestRedirectToTransparentImageAction:: -WebRequestRedirectToTransparentImageAction() {} + WebRequestRedirectToTransparentImageAction() + : WebRequestAction(STRATEGY_NONE) {} WebRequestRedirectToTransparentImageAction:: ~WebRequestRedirectToTransparentImageAction() {} @@ -572,11 +597,6 @@ WebRequestRedirectToTransparentImageAction::GetType() const { return WebRequestAction::ACTION_REDIRECT_TO_TRANSPARENT_IMAGE; } -WebRequestAction::HostPermissionsStrategy -WebRequestRedirectToTransparentImageAction::GetHostPermissionsStrategy() const { - return WebRequestAction::STRATEGY_NONE; -} - LinkedPtrEventResponseDelta WebRequestRedirectToTransparentImageAction::CreateDelta( const WebRequestData& request_data, @@ -594,7 +614,8 @@ WebRequestRedirectToTransparentImageAction::CreateDelta( // WebRequestRedirectToEmptyDocumentAction:: -WebRequestRedirectToEmptyDocumentAction() {} + WebRequestRedirectToEmptyDocumentAction() + : WebRequestAction(STRATEGY_NONE) {} WebRequestRedirectToEmptyDocumentAction:: ~WebRequestRedirectToEmptyDocumentAction() {} @@ -608,11 +629,6 @@ WebRequestRedirectToEmptyDocumentAction::GetType() const { return WebRequestAction::ACTION_REDIRECT_TO_EMPTY_DOCUMENT; } -WebRequestAction::HostPermissionsStrategy -WebRequestRedirectToEmptyDocumentAction::GetHostPermissionsStrategy() const { - return WebRequestAction::STRATEGY_NONE; -} - LinkedPtrEventResponseDelta WebRequestRedirectToEmptyDocumentAction::CreateDelta( const WebRequestData& request_data, @@ -632,7 +648,8 @@ WebRequestRedirectToEmptyDocumentAction::CreateDelta( WebRequestRedirectByRegExAction::WebRequestRedirectByRegExAction( scoped_ptr<RE2> from_pattern, const std::string& to_pattern) - : from_pattern_(from_pattern.Pass()), + : WebRequestAction(STRATEGY_DEFAULT), + from_pattern_(from_pattern.Pass()), to_pattern_(to_pattern.data(), to_pattern.size()) {} WebRequestRedirectByRegExAction::~WebRequestRedirectByRegExAction() {} @@ -698,11 +715,6 @@ WebRequestAction::Type WebRequestRedirectByRegExAction::GetType() const { return WebRequestAction::ACTION_REDIRECT_BY_REGEX_DOCUMENT; } -WebRequestAction::HostPermissionsStrategy -WebRequestRedirectByRegExAction::GetHostPermissionsStrategy() const { - return WebRequestAction::STRATEGY_ALLOW_SAME_DOMAIN; -} - LinkedPtrEventResponseDelta WebRequestRedirectByRegExAction::CreateDelta( const WebRequestData& request_data, const std::string& extension_id, @@ -731,9 +743,7 @@ LinkedPtrEventResponseDelta WebRequestRedirectByRegExAction::CreateDelta( WebRequestSetRequestHeaderAction::WebRequestSetRequestHeaderAction( const std::string& name, const std::string& value) - : name_(name), - value_(value) { -} + : WebRequestAction(STRATEGY_DEFAULT), name_(name), value_(value) {} WebRequestSetRequestHeaderAction::~WebRequestSetRequestHeaderAction() {} @@ -764,8 +774,7 @@ WebRequestSetRequestHeaderAction::CreateDelta( WebRequestRemoveRequestHeaderAction::WebRequestRemoveRequestHeaderAction( const std::string& name) - : name_(name) { -} + : WebRequestAction(STRATEGY_DEFAULT), name_(name) {} WebRequestRemoveRequestHeaderAction::~WebRequestRemoveRequestHeaderAction() {} @@ -797,9 +806,7 @@ WebRequestRemoveRequestHeaderAction::CreateDelta( WebRequestAddResponseHeaderAction::WebRequestAddResponseHeaderAction( const std::string& name, const std::string& value) - : name_(name), - value_(value) { -} + : WebRequestAction(STRATEGY_DEFAULT), name_(name), value_(value) {} WebRequestAddResponseHeaderAction::~WebRequestAddResponseHeaderAction() {} @@ -841,10 +848,10 @@ WebRequestRemoveResponseHeaderAction::WebRequestRemoveResponseHeaderAction( const std::string& name, const std::string& value, bool has_value) - : name_(name), + : WebRequestAction(STRATEGY_DEFAULT), + name_(name), value_(value), - has_value_(has_value) { -} + has_value_(has_value) {} WebRequestRemoveResponseHeaderAction::~WebRequestRemoveResponseHeaderAction() {} @@ -892,9 +899,9 @@ WebRequestRemoveResponseHeaderAction::CreateDelta( WebRequestIgnoreRulesAction::WebRequestIgnoreRulesAction( int minimum_priority, const std::string& ignore_tag) - : minimum_priority_(minimum_priority), - ignore_tag_(ignore_tag) { -} + : WebRequestAction(STRATEGY_NONE), + minimum_priority_(minimum_priority), + ignore_tag_(ignore_tag) {} WebRequestIgnoreRulesAction::~WebRequestIgnoreRulesAction() {} @@ -911,11 +918,6 @@ int WebRequestIgnoreRulesAction::GetMinimumPriority() const { return minimum_priority_; } -WebRequestAction::HostPermissionsStrategy -WebRequestIgnoreRulesAction::GetHostPermissionsStrategy() const { - return WebRequestAction::STRATEGY_NONE; -} - LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::CreateDelta( const WebRequestData& request_data, const std::string& extension_id, @@ -930,7 +932,8 @@ LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::CreateDelta( WebRequestRequestCookieAction::WebRequestRequestCookieAction( linked_ptr<RequestCookieModification> request_cookie_modification) - : request_cookie_modification_(request_cookie_modification) { + : WebRequestAction(STRATEGY_DEFAULT), + request_cookie_modification_(request_cookie_modification) { CHECK(request_cookie_modification_.get()); } @@ -963,7 +966,8 @@ LinkedPtrEventResponseDelta WebRequestRequestCookieAction::CreateDelta( WebRequestResponseCookieAction::WebRequestResponseCookieAction( linked_ptr<ResponseCookieModification> response_cookie_modification) - : response_cookie_modification_(response_cookie_modification) { + : WebRequestAction(STRATEGY_DEFAULT), + response_cookie_modification_(response_cookie_modification) { CHECK(response_cookie_modification_.get()); } @@ -996,8 +1000,7 @@ LinkedPtrEventResponseDelta WebRequestResponseCookieAction::CreateDelta( WebRequestSendMessageToExtensionAction::WebRequestSendMessageToExtensionAction( const std::string& message) - : message_(message) { -} + : WebRequestAction(STRATEGY_HOST), message_(message) {} WebRequestSendMessageToExtensionAction:: ~WebRequestSendMessageToExtensionAction() {} diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h index 2785cfc..41c3639 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h @@ -51,7 +51,10 @@ typedef linked_ptr<extension_web_request_api_helpers::EventResponseDelta> // Base class for all WebRequestActions of the declarative Web Request API. class WebRequestAction { public: - // Type identifiers for concrete WebRequestActions. + // Type identifiers for concrete WebRequestActions. If you add a new type, + // also update |action_names| in WebRequestActionFactory, update the + // unittest WebRequestActionTest.GetName, and add a + // WebRequestActionWithThreadsTest.Permission* unittest. enum Type { ACTION_CANCEL_REQUEST, ACTION_REDIRECT_REQUEST, @@ -70,13 +73,11 @@ class WebRequestAction { // Strategies for checking host permissions. enum HostPermissionsStrategy { - STRATEGY_NONE, // Do not check host permissions. - STRATEGY_DEFAULT, // Check host permissions in HasPermission, + STRATEGY_NONE, // Do not check host permissions. + STRATEGY_DEFAULT, // Check for host permissions for all URLs // before creating the delta. - STRATEGY_ALLOW_SAME_DOMAIN, // Skip host permission checks if the request - // URL and new URL have the same domain. - // Do these checks in DeltaHasPermission, - // after creating the delta. + STRATEGY_HOST, // Check that host permissions match the URL + // of the request. }; // Information necessary to decide how to apply a WebRequestAction @@ -90,7 +91,6 @@ class WebRequestAction { std::set<std::string>* ignored_tags; }; - WebRequestAction(); virtual ~WebRequestAction(); // Returns a bit vector representing extensions::RequestStage. The bit vector @@ -100,15 +100,17 @@ class WebRequestAction { virtual Type GetType() const = 0; + // Return the JavaScript type name corresponding to GetType(). If there are + // more names, they are returned separated by a colon. + const std::string& GetName() const; + // Returns the minimum priority of rules that may be evaluated after // this rule. Defaults to MIN_INT. virtual int GetMinimumPriority() const; - // Returns whether host permissions checks depend on the resulting delta - // and therefore must be checked in DeltaHasPermission, after the delta - // is created, rather than in HasPermission, before it is created. - // Defaults to STRATEGY_DEFAULT. - virtual HostPermissionsStrategy GetHostPermissionsStrategy() const; + HostPermissionsStrategy host_permissions_strategy() const { + return host_permissions_strategy_; + } // Returns whether the specified extension has permission to execute this // action on |request|. Checks the host permission if the host permissions @@ -122,19 +124,6 @@ class WebRequestAction { const net::URLRequest* request, bool crosses_incognito) const; - // Returns whether the specified extension has permission to modify the - // |request| with this |delta|. This check is in addition to HasPermission; - // if either fails, the request will not be modified. Unlike HasPermission, - // it runs after the change is created, so it can use the full information - // about what the change would be. Checks the host permission if the strategy - // is STRATEGY_ALLOW_SAME_DOMAIN. - virtual bool DeltaHasPermission( - const ExtensionInfoMap* extension_info_map, - const std::string& extension_id, - const net::URLRequest* request, - bool crosses_incognito, - const LinkedPtrEventResponseDelta& delta) const; - // Factory method that instantiates a concrete WebRequestAction // implementation according to |json_action|, the representation of the // WebRequestAction as received from the extension API. @@ -157,6 +146,13 @@ class WebRequestAction { void Apply(const std::string& extension_id, base::Time extension_install_time, ApplyInfo* apply_info) const; + + protected: + explicit WebRequestAction(HostPermissionsStrategy strategy); + + private: + // Defaults to STRATEGY_DEFAULT. + const HostPermissionsStrategy host_permissions_strategy_; }; typedef DeclarativeActionSet<WebRequestAction> WebRequestActionSet; @@ -174,7 +170,6 @@ class WebRequestCancelAction : public WebRequestAction { // Implementation of WebRequestAction: virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; - virtual HostPermissionsStrategy GetHostPermissionsStrategy() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( const WebRequestData& request_data, const std::string& extension_id, @@ -193,7 +188,6 @@ class WebRequestRedirectAction : public WebRequestAction { // Implementation of WebRequestAction: virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; - virtual HostPermissionsStrategy GetHostPermissionsStrategy() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( const WebRequestData& request_data, const std::string& extension_id, @@ -214,7 +208,6 @@ class WebRequestRedirectToTransparentImageAction : public WebRequestAction { // Implementation of WebRequestAction: virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; - virtual HostPermissionsStrategy GetHostPermissionsStrategy() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( const WebRequestData& request_data, const std::string& extension_id, @@ -234,7 +227,6 @@ class WebRequestRedirectToEmptyDocumentAction : public WebRequestAction { // Implementation of WebRequestAction: virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; - virtual HostPermissionsStrategy GetHostPermissionsStrategy() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( const WebRequestData& request_data, const std::string& extension_id, @@ -260,7 +252,6 @@ class WebRequestRedirectByRegExAction : public WebRequestAction { // Implementation of WebRequestAction: virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; - virtual HostPermissionsStrategy GetHostPermissionsStrategy() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( const WebRequestData& request_data, const std::string& extension_id, @@ -368,7 +359,6 @@ class WebRequestIgnoreRulesAction : public WebRequestAction { virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; virtual int GetMinimumPriority() const OVERRIDE; - virtual HostPermissionsStrategy GetHostPermissionsStrategy() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( const WebRequestData& request_data, const std::string& extension_id, 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 77a0a46..6abc921 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc @@ -4,23 +4,175 @@ #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h" +#include "base/files/file_path.h" +#include "base/json/json_file_value_serializer.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/message_loop.h" +#include "base/path_service.h" +#include "base/test/values_test_util.h" +#include "base/time.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/extension_info_map.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" +#include "chrome/common/extensions/extension_test_util.h" +#include "content/public/test/test_browser_thread.h" +#include "net/http/http_response_headers.h" #include "net/url_request/url_request_test_util.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using base::DictionaryValue; +using base::ListValue; +using extension_test_util::LoadManifestUnchecked; +using testing::HasSubstr; + +namespace extensions { + namespace { + const char kUnknownActionType[] = "unknownType"; -} // namespace -namespace extensions { +scoped_ptr<WebRequestActionSet> CreateSetOfActions(const char* json) { + scoped_ptr<Value> parsed_value(base::test::ParseJson(json)); + const ListValue* parsed_list; + CHECK(parsed_value->GetAsList(&parsed_list)); + + WebRequestActionSet::AnyVector actions; + for (ListValue::const_iterator it = parsed_list->begin(); + it != parsed_list->end(); + ++it) { + const DictionaryValue* dict; + CHECK((*it)->GetAsDictionary(&dict)); + actions.push_back(linked_ptr<base::Value>(dict->DeepCopy())); + } + + std::string error; + bool bad_message = false; + + scoped_ptr<WebRequestActionSet> action_set( + WebRequestActionSet::Create(actions, &error, &bad_message)); + EXPECT_EQ("", error); + EXPECT_FALSE(bad_message); + CHECK(action_set); + return action_set.Pass(); +} + +} // namespace namespace keys = declarative_webrequest_constants; +class WebRequestActionWithThreadsTest : public testing::Test { + public: + WebRequestActionWithThreadsTest() + : io_thread_(content::BrowserThread::IO, &message_loop_) {} + + protected: + virtual void SetUp() OVERRIDE; + + // Creates a URL request for URL |url_string|, and applies the actions from + // |action_set| as if they were triggered by the extension with + // |extension_id| during |stage|. + bool ActionWorksOnRequest(const char* url_string, + const std::string& extension_id, + const WebRequestActionSet* action_set, + RequestStage stage); + + // Expects a JSON description of an |action| requiring <all_urls> host + // permission, and checks that only an extensions with full host permissions + // can execute that action at |stage|. Also checks that the action is not + // executable for http://clients1.google.com. + void CheckActionNeedsAllUrls(const char* action, RequestStage stage); + + net::TestURLRequestContext context_; + + // An extension with *.com host permissions and the DWR permission. + scoped_refptr<Extension> extension_; + // An extension with host permissions for all URLs and the DWR permission. + scoped_refptr<Extension> extension_all_urls_; + scoped_refptr<ExtensionInfoMap> extension_info_map_; + + private: + MessageLoopForIO message_loop_; + content::TestBrowserThread io_thread_; +}; + +void WebRequestActionWithThreadsTest::SetUp() { + testing::Test::SetUp(); + + std::string error; + extension_ = LoadManifestUnchecked("permissions", + "web_request_com_host_permissions.json", + Manifest::INVALID_LOCATION, + Extension::NO_FLAGS, + "ext_id_1", + &error); + ASSERT_TRUE(extension_) << error; + extension_all_urls_ = + LoadManifestUnchecked("permissions", + "web_request_all_host_permissions.json", + Manifest::INVALID_LOCATION, + Extension::NO_FLAGS, + "ext_id_2", + &error); + ASSERT_TRUE(extension_all_urls_) << error; + extension_info_map_ = new ExtensionInfoMap; + ASSERT_TRUE(extension_info_map_); + extension_info_map_->AddExtension( + extension_.get(), base::Time::Now(), false /*incognito_enabled*/); + extension_info_map_->AddExtension(extension_all_urls_.get(), + base::Time::Now(), + false /*incognito_enabled*/); +} + +bool WebRequestActionWithThreadsTest::ActionWorksOnRequest( + const char* url_string, + const std::string& extension_id, + const WebRequestActionSet* action_set, + RequestStage stage) { + net::TestURLRequest regular_request(GURL(url_string), NULL, &context_, NULL); + std::list<LinkedPtrEventResponseDelta> deltas; + scoped_refptr<net::HttpResponseHeaders> headers( + new net::HttpResponseHeaders("")); + WebRequestData request_data(®ular_request, stage, headers); + std::set<std::string> ignored_tags; + WebRequestAction::ApplyInfo apply_info = { + extension_info_map_, request_data, false /*crosses_incognito*/, &deltas, + &ignored_tags + }; + action_set->Apply(extension_id, base::Time(), &apply_info); + return (1u == deltas.size() || 0u < ignored_tags.size()); +} + +void WebRequestActionWithThreadsTest::CheckActionNeedsAllUrls( + const char* action, + RequestStage stage) { + scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(action)); + + // Although |extension_| has matching *.com host permission, |action| + // is intentionally forbidden -- in Declarative WR, host permission + // for less than all URLs are ignored (except in SendMessageToExtension). + EXPECT_FALSE(ActionWorksOnRequest( + "http://test.com", extension_->id(), action_set.get(), stage)); + // With the "<all_urls>" host permission they are allowed. + EXPECT_TRUE(ActionWorksOnRequest( + "http://test.com", extension_all_urls_->id(), action_set.get(), stage)); + + // The protected URLs should not be touched at all. + EXPECT_FALSE(ActionWorksOnRequest( + "http://clients1.google.com", extension_->id(), action_set.get(), stage)); + EXPECT_FALSE(ActionWorksOnRequest("http://clients1.google.com", + extension_all_urls_->id(), + action_set.get(), + stage)); +} + TEST(WebRequestActionTest, CreateAction) { std::string error; bool bad_message = false; @@ -115,45 +267,288 @@ TEST(WebRequestActionTest, PerlToRe2Style) { #undef CallPerlToRe2Style } -TEST(WebRequestActionTest, TestPermissions) { - // Necessary for TestURLRequest. - MessageLoop message_loop(MessageLoop::TYPE_IO); - net::TestURLRequestContext context; +TEST_F(WebRequestActionWithThreadsTest, PermissionsToRedirect) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.RedirectRequest\"," + " \"redirectUrl\": \"http://www.foobar.com\"" + "}]"; + CheckActionNeedsAllUrls(kAction, ON_BEFORE_REQUEST); +} - std::string error; - bool bad_message = false; - scoped_ptr<WebRequestActionSet> action_set; +TEST_F(WebRequestActionWithThreadsTest, PermissionsToRedirectByRegEx) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.RedirectByRegEx\"," + " \"from\": \".*\"," + " \"to\": \"http://www.foobar.com\"" + "}]"; + CheckActionNeedsAllUrls(kAction, ON_BEFORE_REQUEST); +} - // Setup redirect to http://www.foobar.com. - base::DictionaryValue redirect; - redirect.SetString(keys::kInstanceTypeKey, keys::kRedirectRequestType); - redirect.SetString(keys::kRedirectUrlKey, "http://www.foobar.com"); +TEST_F(WebRequestActionWithThreadsTest, PermissionsToSetRequestHeader) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.SetRequestHeader\"," + " \"name\": \"testname\"," + " \"value\": \"testvalue\"" + "}]"; + CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS); +} - WebRequestActionSet::AnyVector actions; - actions.push_back(linked_ptr<base::Value>(redirect.DeepCopy())); +TEST_F(WebRequestActionWithThreadsTest, PermissionsToRemoveRequestHeader) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.RemoveRequestHeader\"," + " \"name\": \"testname\"" + "}]"; + CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS); +} - action_set = WebRequestActionSet::Create(actions, &error, &bad_message); - EXPECT_EQ("", error); - EXPECT_FALSE(bad_message); +TEST_F(WebRequestActionWithThreadsTest, PermissionsToAddResponseHeader) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.AddResponseHeader\"," + " \"name\": \"testname\"," + " \"value\": \"testvalue\"" + "}]"; + CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED); +} - // Check that redirect works on regular URLs but not on protected URLs. - net::TestURLRequest regular_request( - GURL("http://test.com"), NULL, &context, NULL); - std::list<LinkedPtrEventResponseDelta> deltas; - WebRequestData 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, NULL); - deltas.clear(); - request_data = WebRequestData(&protected_request, ON_BEFORE_REQUEST); - // Note that we just updated the request_data reference in apply_info. - action_set->Apply("ext1", base::Time(), &apply_info); - EXPECT_EQ(0u, deltas.size()); +TEST_F(WebRequestActionWithThreadsTest, PermissionsToRemoveResponseHeader) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.RemoveResponseHeader\"," + " \"name\": \"testname\"" + "}]"; + CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED); +} + +TEST_F(WebRequestActionWithThreadsTest, PermissionsToSendMessageToExtension) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.SendMessageToExtension\"," + " \"message\": \"testtext\"" + "}]"; + scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction)); + + // For sending messages, specific host permissions actually matter. + EXPECT_TRUE(ActionWorksOnRequest("http://test.com", + extension_->id(), + action_set.get(), + ON_BEFORE_REQUEST)); + // With the "<all_urls>" host permission they are allowed. + EXPECT_TRUE(ActionWorksOnRequest("http://test.com", + extension_all_urls_->id(), + action_set.get(), + ON_BEFORE_REQUEST)); + + // The protected URLs should not be touched at all. + EXPECT_FALSE(ActionWorksOnRequest("http://clients1.google.com", + extension_->id(), + action_set.get(), + ON_BEFORE_REQUEST)); + EXPECT_FALSE(ActionWorksOnRequest("http://clients1.google.com", + extension_all_urls_->id(), + action_set.get(), + ON_BEFORE_REQUEST)); +} + +TEST_F(WebRequestActionWithThreadsTest, PermissionsToAddRequestCookie) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.AddRequestCookie\"," + " \"cookie\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" + "}]"; + CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS); +} + +TEST_F(WebRequestActionWithThreadsTest, PermissionsToAddResponseCookie) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.AddResponseCookie\"," + " \"cookie\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" + "}]"; + CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED); +} + +TEST_F(WebRequestActionWithThreadsTest, PermissionsToEditRequestCookie) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.EditRequestCookie\"," + " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }," + " \"modification\": { \"name\": \"name2\", \"value\": \"value2\" }" + "}]"; + CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS); +} + +TEST_F(WebRequestActionWithThreadsTest, PermissionsToEditResponseCookie) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.EditResponseCookie\"," + " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }," + " \"modification\": { \"name\": \"name2\", \"value\": \"value2\" }" + "}]"; + CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED); +} + +TEST_F(WebRequestActionWithThreadsTest, PermissionsToRemoveRequestCookie) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.RemoveRequestCookie\"," + " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" + "}]"; + CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS); +} + +TEST_F(WebRequestActionWithThreadsTest, PermissionsToRemoveResponseCookie) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.RemoveResponseCookie\"," + " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" + "}]"; + CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED); +} + +TEST_F(WebRequestActionWithThreadsTest, PermissionsToCancel) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.CancelRequest\"" + "}]"; + scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction)); + + // Cancelling requests works without full host permissions. + EXPECT_TRUE(ActionWorksOnRequest("http://test.org", + extension_->id(), + action_set.get(), + ON_BEFORE_REQUEST)); +} + +TEST_F(WebRequestActionWithThreadsTest, + PermissionsToRedirectToTransparentImage) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.RedirectToTransparentImage\"" + "}]"; + scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction)); + + // Redirecting to transparent images works without full host permissions. + EXPECT_TRUE(ActionWorksOnRequest("http://test.org", + extension_->id(), + action_set.get(), + ON_BEFORE_REQUEST)); +} + +TEST_F(WebRequestActionWithThreadsTest, PermissionsToRedirectToEmptyDocument) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.RedirectToEmptyDocument\"" + "}]"; + scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction)); + + // Redirecting to the empty document works without full host permissions. + EXPECT_TRUE(ActionWorksOnRequest("http://test.org", + extension_->id(), + action_set.get(), + ON_BEFORE_REQUEST)); +} + +TEST_F(WebRequestActionWithThreadsTest, PermissionsToIgnore) { + const char kAction[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.IgnoreRules\"," + " \"lowerPriorityThan\": 123," + " \"hasTag\": \"some_tag\"" + "}]"; + scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction)); + + // Ignoring rules works without full host permissions. + EXPECT_TRUE(ActionWorksOnRequest("http://test.org", + extension_->id(), + action_set.get(), + ON_BEFORE_REQUEST)); +} + +TEST(WebRequestActionTest, GetName) { + const char kActions[] = + "[{" + " \"instanceType\": \"declarativeWebRequest.RedirectRequest\"," + " \"redirectUrl\": \"http://www.foobar.com\"" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.RedirectByRegEx\"," + " \"from\": \".*\"," + " \"to\": \"http://www.foobar.com\"" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.SetRequestHeader\"," + " \"name\": \"testname\"," + " \"value\": \"testvalue\"" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.RemoveRequestHeader\"," + " \"name\": \"testname\"" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.AddResponseHeader\"," + " \"name\": \"testname\"," + " \"value\": \"testvalue\"" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.RemoveResponseHeader\"," + " \"name\": \"testname\"" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.SendMessageToExtension\"," + " \"message\": \"testtext\"" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.AddRequestCookie\"," + " \"cookie\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.AddResponseCookie\"," + " \"cookie\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.EditRequestCookie\"," + " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }," + " \"modification\": { \"name\": \"name2\", \"value\": \"value2\" }" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.EditResponseCookie\"," + " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }," + " \"modification\": { \"name\": \"name2\", \"value\": \"value2\" }" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.RemoveRequestCookie\"," + " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.RemoveResponseCookie\"," + " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.CancelRequest\"" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.RedirectToTransparentImage\"" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.RedirectToEmptyDocument\"" + "}," + "{" + " \"instanceType\": \"declarativeWebRequest.IgnoreRules\"," + " \"lowerPriorityThan\": 123," + " \"hasTag\": \"some_tag\"" + "}]"; + scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kActions)); + for (WebRequestActionSet::Actions::const_iterator it = + action_set->actions().begin(); + it != action_set->actions().end(); + ++it) { + EXPECT_THAT((*it)->GetName(), HasSubstr("declarativeWebRequest.")); + } } } // 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 0a0cc71..2fdee62 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc @@ -8,17 +8,26 @@ #include <limits> #include <utility> +#include "base/bind.h" #include "base/stl_util.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_system.h" +#include "chrome/common/extensions/extension.h" +#include "extensions/common/error_utils.h" #include "net/url_request/url_request.h" namespace { -const char kActionCannotBeExecuted[] = "An action can never be executed " + +const char kActionCannotBeExecuted[] = "The 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."; + +const char kAllURLsPermissionNeeded[] = + "To execute the action '*', you need to request host permission for all " + "hosts."; + } // namespace namespace extensions { @@ -145,16 +154,19 @@ std::string WebRequestRulesRegistry::AddRulesImpl( std::string error; RulesMap new_webrequest_rules; + const Extension* extension = + extension_info_map_->extensions().GetByID(extension_id); for (std::vector<linked_ptr<RulesRegistry::Rule> >::const_iterator rule = rules.begin(); rule != rules.end(); ++rule) { WebRequestRule::GlobalRuleId rule_id(extension_id, *(*rule)->id); DCHECK(webrequest_rules_.find(rule_id) == webrequest_rules_.end()); - scoped_ptr<WebRequestRule> webrequest_rule( - WebRequestRule::Create(url_matcher_.condition_factory(), extension_id, - extension_installation_time, *rule, - &CheckConsistency, &error)); + scoped_ptr<WebRequestRule> webrequest_rule(WebRequestRule::Create( + url_matcher_.condition_factory(), + extension_id, extension_installation_time, *rule, + base::Bind(&Checker, base::Unretained(extension)), + &error)); if (!error.empty()) { // We don't return here, because we want to clear temporary // condition sets in the url_matcher_. @@ -200,9 +212,6 @@ std::string WebRequestRulesRegistry::AddRulesImpl( ClearCacheOnNavigation(); if (profile_id_ && !webrequest_rules_.empty()) { - const Extension* extension = - extension_info_map_->extensions().GetByID(extension_id); - BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&extension_web_request_api_helpers::NotifyWebRequestAPIUsed, @@ -280,9 +289,6 @@ WebRequestRulesRegistry::~WebRequestRulesRegistry() {} base::Time WebRequestRulesRegistry::GetExtensionInstallationTime( const std::string& extension_id) const { - if (!extension_info_map_.get()) // May be NULL during testing. - return base::Time(); - return extension_info_map_->GetInstallTime(extension_id); } @@ -291,35 +297,70 @@ void WebRequestRulesRegistry::ClearCacheOnNavigation() { } // static -bool WebRequestRulesRegistry::CheckConsistency( - const WebRequestConditionSet* conditions, +bool WebRequestRulesRegistry::Checker(const Extension* extension, + const WebRequestConditionSet* conditions, + const WebRequestActionSet* actions, + std::string* error) { + return (StageChecker(conditions, actions, error) && + HostPermissionsChecker(extension, actions, error)); +} + +// static +bool WebRequestRulesRegistry::HostPermissionsChecker( + const Extension* extension, 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. + if (extension->HasEffectiveAccessToAllHosts()) + return true; + + // Without the permission for all URLs, actions with the STRATEGY_DEFAULT + // should not be registered, they would never be able to execute. 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; + if ((*action_iter)->host_permissions_strategy() == + WebRequestAction::STRATEGY_DEFAULT) { + *error = ErrorUtils::FormatErrorMessage(kAllURLsPermissionNeeded, + (*action_iter)->GetName()); return false; } } return true; } +// static +bool WebRequestRulesRegistry::StageChecker( + const WebRequestConditionSet* conditions, + const WebRequestActionSet* actions, + std::string* error) { + // Actions and conditions can be checked and executed in specific stages + // of each web request. A rule is inconsistent if there is an action that + // can only be triggered in stages in which no condition can be evaluated. + + // In which stages there are conditions to evaluate. + int condition_stages = 0; + for (WebRequestConditionSet::Conditions::const_iterator condition_iter = + conditions->conditions().begin(); + condition_iter != conditions->conditions().end(); + ++condition_iter) { + condition_stages |= (*condition_iter)->stages(); + } + + for (WebRequestActionSet::Actions::const_iterator action_iter = + actions->actions().begin(); + action_iter != actions->actions().end(); + ++action_iter) { + // Test the intersection of bit masks, this is intentionally & and not &&. + if ((*action_iter)->GetStages() & condition_stages) + continue; + // We only get here if no matching condition was found. + *error = ErrorUtils::FormatErrorMessage(kActionCannotBeExecuted, + (*action_iter)->GetName()); + return false; + } + return true; +} void WebRequestRulesRegistry::AddTriggeredRules( const URLMatches& url_matches, const WebRequestCondition::MatchData& request_data, 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 91d0cdf..99dbd3d 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h @@ -11,6 +11,7 @@ #include <string> #include <vector> +#include "base/gtest_prod_util.h" #include "base/time.h" #include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" @@ -107,19 +108,20 @@ class WebRequestRulesRegistry : public RulesRegistryWithCache { const std::string& extension_id) const; virtual void ClearCacheOnNavigation(); + void SetExtensionInfoMapForTesting( + scoped_refptr<ExtensionInfoMap> extension_info_map) { + extension_info_map_ = extension_info_map; + } + const std::set<const WebRequestRule*>& rules_with_untriggered_conditions_for_test() const { return rules_with_untriggered_conditions_; } 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); + FRIEND_TEST_ALL_PREFIXES(WebRequestRulesRegistrySimpleTest, StageChecker); + FRIEND_TEST_ALL_PREFIXES(WebRequestRulesRegistrySimpleTest, + HostPermissionsChecker); typedef std::map<URLMatcherConditionSet::ID, WebRequestRule*> RuleTriggers; typedef std::map<WebRequestRule::GlobalRuleId, linked_ptr<WebRequestRule> > @@ -127,6 +129,25 @@ class WebRequestRulesRegistry : public RulesRegistryWithCache { typedef std::set<URLMatcherConditionSet::ID> URLMatches; typedef std::set<const WebRequestRule*> RuleSet; + // This bundles all consistency checkers. Returns true in case of consistency + // and MUST set |error| otherwise. + static bool Checker(const Extension* extension, + const WebRequestConditionSet* conditions, + const WebRequestActionSet* actions, + std::string* error); + + // Check that the |extension| has host permissions for all URLs if actions + // requiring them are present. + static bool HostPermissionsChecker(const Extension* extension, + const WebRequestActionSet* actions, + std::string* error); + + // Check that every action is applicable in the same request stage as at + // least one condition. + static bool StageChecker(const WebRequestConditionSet* conditions, + const WebRequestActionSet* actions, + std::string* error); + // This is a helper function to GetMatches. Rules triggered by |url_matches| // get added to |result| if one of their conditions is fulfilled. // |request_data| gets passed to IsFulfilled of the rules' condition sets. 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 250d2c8..22a34c9 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 @@ -16,6 +16,7 @@ #include "base/values.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_test_util.h" #include "content/public/test/test_browser_thread.h" #include "extensions/common/matcher/url_matcher_constants.h" #include "net/url_request/url_request_test_util.h" @@ -34,6 +35,9 @@ const char kRuleId4[] = "rule4"; namespace extensions { +using base::Value; +using extension_test_util::LoadManifest; +using extension_test_util::LoadManifestUnchecked; using testing::HasSubstr; namespace helpers = extension_web_request_api_helpers; @@ -42,9 +46,11 @@ namespace keys2 = url_matcher_constants; class TestWebRequestRulesRegistry : public WebRequestRulesRegistry { public: - TestWebRequestRulesRegistry() - : WebRequestRulesRegistry(NULL, NULL), - num_clear_cache_calls_(0) {} + explicit TestWebRequestRulesRegistry( + scoped_refptr<ExtensionInfoMap> extension_info_map) + : WebRequestRulesRegistry(NULL, NULL), num_clear_cache_calls_(0) { + SetExtensionInfoMapForTesting(extension_info_map); + } // Returns how often the in-memory caches of the renderers were instructed // to be cleared. @@ -59,16 +65,6 @@ class TestWebRequestRulesRegistry : public WebRequestRulesRegistry { protected: virtual ~TestWebRequestRulesRegistry() {} - virtual base::Time GetExtensionInstallationTime( - const std::string& extension_id) const OVERRIDE { - if (extension_id == kExtensionId) - return base::Time() + base::TimeDelta::FromDays(1); - else if (extension_id == kExtensionId2) - return base::Time() + base::TimeDelta::FromDays(2); - else - return base::Time(); - } - virtual void ClearCacheOnNavigation() OVERRIDE { ++num_clear_cache_calls_; } @@ -86,6 +82,8 @@ class WebRequestRulesRegistryTest : public testing::Test { virtual ~WebRequestRulesRegistryTest() {} + virtual void SetUp() OVERRIDE; + virtual void TearDown() OVERRIDE { // Make sure that deletion traits of all registries are executed. message_loop.RunUntilIdle(); @@ -223,11 +221,47 @@ class WebRequestRulesRegistryTest : public testing::Test { MessageLoop message_loop; content::TestBrowserThread ui; content::TestBrowserThread io; + // Two extensions with host permissions for all URLs and the DWR permission. + // Installation times will be so that |extension_| is older than + // |extension2_|. + scoped_refptr<Extension> extension_; + scoped_refptr<Extension> extension2_; + scoped_refptr<ExtensionInfoMap> extension_info_map_; }; +void WebRequestRulesRegistryTest::SetUp() { + testing::Test::SetUp(); + + std::string error; + extension_ = LoadManifestUnchecked("permissions", + "web_request_all_host_permissions.json", + Manifest::INVALID_LOCATION, + Extension::NO_FLAGS, + kExtensionId, + &error); + ASSERT_TRUE(extension_) << error; + extension2_ = + LoadManifestUnchecked("permissions", + "web_request_all_host_permissions.json", + Manifest::INVALID_LOCATION, + Extension::NO_FLAGS, + kExtensionId2, + &error); + ASSERT_TRUE(extension2_) << error; + extension_info_map_ = new ExtensionInfoMap; + ASSERT_TRUE(extension_info_map_); + extension_info_map_->AddExtension(extension_.get(), + base::Time() + base::TimeDelta::FromDays(1), + false /*incognito_enabled*/); + extension_info_map_->AddExtension(extension2_.get(), + base::Time() + base::TimeDelta::FromDays(2), + false /*incognito_enabled*/); +} + + TEST_F(WebRequestRulesRegistryTest, AddRulesImpl) { scoped_refptr<TestWebRequestRulesRegistry> registry( - new TestWebRequestRulesRegistry()); + new TestWebRequestRulesRegistry(extension_info_map_)); std::string error; std::vector<linked_ptr<RulesRegistry::Rule> > rules; @@ -266,7 +300,7 @@ TEST_F(WebRequestRulesRegistryTest, AddRulesImpl) { TEST_F(WebRequestRulesRegistryTest, RemoveRulesImpl) { scoped_refptr<TestWebRequestRulesRegistry> registry( - new TestWebRequestRulesRegistry()); + new TestWebRequestRulesRegistry(extension_info_map_)); std::string error; // Setup RulesRegistry to contain two rules. @@ -314,7 +348,7 @@ TEST_F(WebRequestRulesRegistryTest, RemoveRulesImpl) { TEST_F(WebRequestRulesRegistryTest, RemoveAllRulesImpl) { scoped_refptr<TestWebRequestRulesRegistry> registry( - new TestWebRequestRulesRegistry()); + new TestWebRequestRulesRegistry(extension_info_map_)); std::string error; // Setup RulesRegistry to contain two rules, one for each extension. @@ -366,7 +400,7 @@ TEST_F(WebRequestRulesRegistryTest, RemoveAllRulesImpl) { // Test precedences between extensions. TEST_F(WebRequestRulesRegistryTest, Precedences) { scoped_refptr<WebRequestRulesRegistry> registry( - new TestWebRequestRulesRegistry()); + new TestWebRequestRulesRegistry(extension_info_map_)); std::string error; std::vector<linked_ptr<RulesRegistry::Rule> > rules_to_add_1(1); @@ -409,7 +443,7 @@ TEST_F(WebRequestRulesRegistryTest, Precedences) { // Test priorities of rules within one extension. TEST_F(WebRequestRulesRegistryTest, Priorities) { scoped_refptr<WebRequestRulesRegistry> registry( - new TestWebRequestRulesRegistry()); + new TestWebRequestRulesRegistry(extension_info_map_)); std::string error; std::vector<linked_ptr<RulesRegistry::Rule> > rules_to_add_1(1); @@ -495,7 +529,7 @@ TEST_F(WebRequestRulesRegistryTest, IgnoreRulesByTag) { ASSERT_TRUE(RulesRegistry::Rule::Populate(*value2, rules[1].get())); scoped_refptr<WebRequestRulesRegistry> registry( - new TestWebRequestRulesRegistry()); + new TestWebRequestRulesRegistry(extension_info_map_)); std::string error = registry->AddRulesImpl(kExtensionId, rules); EXPECT_EQ("", error); EXPECT_FALSE(registry->IsEmpty()); @@ -517,7 +551,7 @@ TEST_F(WebRequestRulesRegistryTest, IgnoreRulesByTag) { // GetMatches. TEST_F(WebRequestRulesRegistryTest, GetMatchesCheckFulfilled) { scoped_refptr<TestWebRequestRulesRegistry> registry( - new TestWebRequestRulesRegistry()); + new TestWebRequestRulesRegistry(extension_info_map_)); const std::string kMatchingUrlAttribute( "\"url\": { \"pathContains\": \"\" }, \n"); const std::string kNonMatchingNonUrlAttribute( @@ -565,7 +599,7 @@ TEST_F(WebRequestRulesRegistryTest, GetMatchesCheckFulfilled) { // differ. TEST_F(WebRequestRulesRegistryTest, GetMatchesDifferentUrls) { scoped_refptr<TestWebRequestRulesRegistry> registry( - new TestWebRequestRulesRegistry()); + new TestWebRequestRulesRegistry(extension_info_map_)); const std::string kUrlAttribute( "\"url\": { \"hostContains\": \"url\" }, \n"); const std::string kFirstPartyUrlAttribute( @@ -622,7 +656,7 @@ TEST_F(WebRequestRulesRegistryTest, GetMatchesDifferentUrls) { } } -TEST_F(WebRequestRulesRegistryTest, CheckConsistency) { +TEST(WebRequestRulesRegistrySimpleTest, StageChecker) { // 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. @@ -646,19 +680,73 @@ TEST_F(WebRequestRulesRegistryTest, CheckConsistency) { "} "; scoped_ptr<Value> value(base::JSONReader::Read(kRule)); - ASSERT_TRUE(value.get()); + ASSERT_TRUE(value); - 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()); + RulesRegistry::Rule rule; + ASSERT_TRUE(RulesRegistry::Rule::Populate(*value, &rule)); + std::string error; URLMatcher matcher; - std::string error = registry->AddRulesImpl(kExtensionId, rules); + scoped_ptr<WebRequestConditionSet> conditions = + WebRequestConditionSet::Create( + matcher.condition_factory(), rule.conditions, &error); + ASSERT_TRUE(error.empty()) << error; + ASSERT_TRUE(conditions); + + bool bad_message = false; + scoped_ptr<WebRequestActionSet> actions = + WebRequestActionSet::Create(rule.actions, &error, &bad_message); + ASSERT_TRUE(error.empty()) << error; + ASSERT_FALSE(bad_message); + ASSERT_TRUE(actions); + + EXPECT_FALSE(WebRequestRulesRegistry::StageChecker( + conditions.get(), actions.get(), &error)); EXPECT_THAT(error, HasSubstr("no time in the request life-cycle")); - EXPECT_TRUE(registry->IsEmpty()); + EXPECT_THAT(error, HasSubstr(actions->actions().back()->GetName())); +} + +TEST(WebRequestRulesRegistrySimpleTest, HostPermissionsChecker) { + const char kAction[] = // This action requires all URLs host permission. + "{ \n" + " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n" + " \"redirectUrl\": \"http://bar.com\" \n" + "} "; + scoped_ptr<Value> action_value(base::JSONReader::Read(kAction)); + ASSERT_TRUE(action_value); + + WebRequestActionSet::AnyVector actions; + actions.push_back(linked_ptr<base::Value>(action_value.release())); + ASSERT_TRUE(actions.back().get()); + + std::string error; + bool bad_message = false; + scoped_ptr<WebRequestActionSet> action_set( + WebRequestActionSet::Create(actions, &error, &bad_message)); + ASSERT_TRUE(error.empty()) << error; + ASSERT_FALSE(bad_message); + ASSERT_TRUE(action_set); + + scoped_refptr<Extension> extension_no_url( + LoadManifest("permissions", "web_request_no_host.json")); + scoped_refptr<Extension> extension_some_urls( + LoadManifest("permissions", "web_request_com_host_permissions.json")); + scoped_refptr<Extension> extension_all_urls( + LoadManifest("permissions", "web_request_all_host_permissions.json")); + + EXPECT_TRUE(WebRequestRulesRegistry::HostPermissionsChecker( + extension_all_urls.get(), action_set.get(), &error)); + EXPECT_TRUE(error.empty()) << error; + + EXPECT_FALSE(WebRequestRulesRegistry::HostPermissionsChecker( + extension_some_urls.get(), action_set.get(), &error)); + EXPECT_THAT(error, HasSubstr("permission for all")); + EXPECT_THAT(error, HasSubstr(action_set->actions().back()->GetName())); + + EXPECT_FALSE(WebRequestRulesRegistry::HostPermissionsChecker( + extension_no_url.get(), action_set.get(), &error)); + EXPECT_THAT(error, HasSubstr("permission for all")); + EXPECT_THAT(error, HasSubstr(action_set->actions().back()->GetName())); } TEST_F(WebRequestRulesRegistryTest, CheckOriginAndPathRegEx) { @@ -688,7 +776,7 @@ TEST_F(WebRequestRulesRegistryTest, CheckOriginAndPathRegEx) { ASSERT_TRUE(RulesRegistry::Rule::Populate(*value, rules.back().get())); scoped_refptr<WebRequestRulesRegistry> registry( - new TestWebRequestRulesRegistry()); + new TestWebRequestRulesRegistry(extension_info_map_)); URLMatcher matcher; std::string error = registry->AddRulesImpl(kExtensionId, rules); 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 27ef5a3..260bff4 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api.cc +++ b/chrome/browser/extensions/api/web_request/web_request_api.cc @@ -1288,7 +1288,8 @@ void ExtensionWebRequestEventRouter::GetMatchingListenersImpl( continue; if (!WebRequestPermissions::CanExtensionAccessURL( - extension_info_map, it->extension_id, url, crosses_incognito, true)) + extension_info_map, it->extension_id, url, crosses_incognito, + WebRequestPermissions::REQUIRE_HOST_PERMISSION)) continue; bool blocking_listener = diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc index 2f53bb5..200e12d 100644 --- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc @@ -159,17 +159,6 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, << message_; } -IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, - WebRequestDeclarativePermissions) { - ExtensionTestMessageListener listener("rules all registered", false); - ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII( - "webrequest/permissionless"))); - EXPECT_TRUE(listener.WaitUntilSatisfied()); - ASSERT_TRUE(RunExtensionSubtest( - "webrequest", "test_declarative_permissions.html")) << - message_; -} - void ExtensionWebRequestApiTest::RunPermissionTest( const char* extension_directory, bool load_extension_with_incognito_permission, diff --git a/chrome/browser/extensions/api/web_request/web_request_permissions.cc b/chrome/browser/extensions/api/web_request/web_request_permissions.cc index 9baaef4..cf981c9 100644 --- a/chrome/browser/extensions/api/web_request/web_request_permissions.cc +++ b/chrome/browser/extensions/api/web_request/web_request_permissions.cc @@ -97,7 +97,7 @@ bool WebRequestPermissions::CanExtensionAccessURL( const std::string& extension_id, const GURL& url, bool crosses_incognito, - bool enforce_host_permissions) { + HostPermissionsCheck host_permissions_check) { // extension_info_map can be NULL in testing. if (!extension_info_map) return true; @@ -111,13 +111,21 @@ bool WebRequestPermissions::CanExtensionAccessURL( if (crosses_incognito && !extension_info_map->CanCrossIncognito(extension)) return false; - if (enforce_host_permissions) { - // about: URLs are not covered in host permissions, but are allowed anyway. - bool host_permissions_ok = (url.SchemeIs(chrome::kAboutScheme) || - extension->HasHostPermission(url) || - url.GetOrigin() == extension->url()); - if (!host_permissions_ok) - return false; + switch (host_permissions_check) { + case DO_NOT_CHECK_HOST: + break; + case REQUIRE_HOST_PERMISSION: + // about: URLs are not covered in host permissions, but are allowed + // anyway. + if (!((url.SchemeIs(chrome::kAboutScheme) || + extension->HasHostPermission(url) || + url.GetOrigin() == extension->url()))) + return false; + break; + case REQUIRE_ALL_URLS: + if (!extension->HasEffectiveAccessToAllHosts()) + return false; + break; } return true; diff --git a/chrome/browser/extensions/api/web_request/web_request_permissions.h b/chrome/browser/extensions/api/web_request/web_request_permissions.h index 1d1297c..6ff0f43 100644 --- a/chrome/browser/extensions/api/web_request/web_request_permissions.h +++ b/chrome/browser/extensions/api/web_request/web_request_permissions.h @@ -20,15 +20,25 @@ class URLRequest; // This class is used to test whether extensions may modify web requests. class WebRequestPermissions { public: + // Different host permission checking modes for CanExtensionAccessURL. + enum HostPermissionsCheck { + DO_NOT_CHECK_HOST = 0, // No check. + REQUIRE_HOST_PERMISSION, // Permission needed for given URL. + REQUIRE_ALL_URLS // Permission needed for <all_urls>. + }; + // Returns true if the request shall not be reported to extensions. static bool HideRequest(const ExtensionInfoMap* extension_info_map, const net::URLRequest* request); - static bool CanExtensionAccessURL(const ExtensionInfoMap* extension_info_map, - const std::string& extension_id, - const GURL& url, - bool crosses_incognito, - bool enforce_host_permissions); + // |host_permission_check| controls how permissions are checked with regard to + // |url|. + static bool CanExtensionAccessURL( + const ExtensionInfoMap* extension_info_map, + const std::string& extension_id, + const GURL& url, + bool crosses_incognito, + HostPermissionsCheck host_permissions_check); private: DISALLOW_IMPLICIT_CONSTRUCTORS(WebRequestPermissions); diff --git a/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc index 0a59184..357c0d5 100644 --- a/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc @@ -7,12 +7,67 @@ #include "base/message_loop.h" #include "chrome/browser/extensions/extension_info_map.h" #include "chrome/common/extensions/extension_constants.h" +#include "chrome/common/extensions/extension_manifest_constants.h" +#include "chrome/common/extensions/extension_test_util.h" #include "chrome/test/base/testing_profile.h" #include "content/public/browser/resource_request_info.h" +#include "content/public/test/test_browser_thread.h" #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" using content::ResourceRequestInfo; +using extensions::Extension; +using extensions::Manifest; +using extension_test_util::LoadManifestUnchecked; + +class ExtensionWebRequestHelpersTestWithThreadsTest : public testing::Test { + public: + ExtensionWebRequestHelpersTestWithThreadsTest() + : io_thread_(content::BrowserThread::IO, &message_loop_) {} + + protected: + virtual void SetUp() OVERRIDE; + + protected: + net::TestURLRequestContext context; + + // This extension has Web Request permissions, but no host permission. + scoped_refptr<Extension> permissionless_extension_; + // This extension has Web Request permissions, and *.com a host permission. + scoped_refptr<Extension> com_extension_; + scoped_refptr<ExtensionInfoMap> extension_info_map_; + + private: + MessageLoopForIO message_loop_; + content::TestBrowserThread io_thread_; +}; + +void ExtensionWebRequestHelpersTestWithThreadsTest::SetUp() { + testing::Test::SetUp(); + + std::string error; + permissionless_extension_ = LoadManifestUnchecked("permissions", + "web_request_no_host.json", + Manifest::INVALID_LOCATION, + Extension::NO_FLAGS, + "ext_id_1", + &error); + ASSERT_TRUE(permissionless_extension_) << error; + com_extension_ = + LoadManifestUnchecked("permissions", + "web_request_com_host_permissions.json", + Manifest::INVALID_LOCATION, + Extension::NO_FLAGS, + "ext_id_2", + &error); + ASSERT_TRUE(com_extension_) << error; + extension_info_map_ = new ExtensionInfoMap; + extension_info_map_->AddExtension(permissionless_extension_.get(), + base::Time::Now(), + false /*incognito_enabled*/); + extension_info_map_->AddExtension( + com_extension_.get(), base::Time::Now(), false /*incognito_enabled*/); +} TEST(ExtensionWebRequestHelpersTest, TestHideRequestForURL) { MessageLoopForIO message_loop; @@ -71,3 +126,34 @@ TEST(ExtensionWebRequestHelpersTest, TestHideRequestForURL) { EXPECT_TRUE(WebRequestPermissions::HideRequest(extension_info_map.get(), &sensitive_request)); } + +TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest, + TestCanExtensionAccessURL_HostPermissions) { + net::TestURLRequest request( + GURL("http://example.com"), NULL, &context, NULL); + + EXPECT_TRUE(WebRequestPermissions::CanExtensionAccessURL( + extension_info_map_, + permissionless_extension_->id(), + request.url(), + false /*crosses_incognito*/, + WebRequestPermissions::DO_NOT_CHECK_HOST)); + EXPECT_FALSE(WebRequestPermissions::CanExtensionAccessURL( + extension_info_map_, + permissionless_extension_->id(), + request.url(), + false /*crosses_incognito*/, + WebRequestPermissions::REQUIRE_HOST_PERMISSION)); + EXPECT_TRUE(WebRequestPermissions::CanExtensionAccessURL( + extension_info_map_, + com_extension_->id(), + request.url(), + false /*crosses_incognito*/, + WebRequestPermissions::REQUIRE_HOST_PERMISSION)); + EXPECT_FALSE(WebRequestPermissions::CanExtensionAccessURL( + extension_info_map_, + com_extension_->id(), + request.url(), + false /*crosses_incognito*/, + WebRequestPermissions::REQUIRE_ALL_URLS)); +} diff --git a/chrome/browser/extensions/permissions_updater_unittest.cc b/chrome/browser/extensions/permissions_updater_unittest.cc index ea5c48f..8552b61 100644 --- a/chrome/browser/extensions/permissions_updater_unittest.cc +++ b/chrome/browser/extensions/permissions_updater_unittest.cc @@ -14,6 +14,7 @@ #include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_test_util.h" #include "chrome/common/extensions/permissions/permission_set.h" #include "chrome/test/base/testing_profile.h" #include "content/public/browser/notification_observer.h" @@ -21,6 +22,8 @@ #include "content/public/browser/notification_service.h" #include "testing/gtest/include/gtest/gtest.h" +using extension_test_util::LoadManifest; + namespace extensions { namespace { @@ -87,24 +90,15 @@ class PermissionsUpdaterListener : public content::NotificationObserver { class PermissionsUpdaterTest : public ExtensionServiceTestBase { }; -scoped_refptr<Extension> LoadManifest(std::string* error) { +scoped_refptr<Extension> LoadOurManifest() { base::FilePath path; - PathService::Get(chrome::DIR_TEST_DATA, &path); - path = path.AppendASCII("extensions") - .AppendASCII("api_test") + path = path.AppendASCII("api_test") .AppendASCII("permissions") - .AppendASCII("optional") - .AppendASCII("manifest.json"); - - JSONFileValueSerializer serializer(path); - scoped_ptr<Value> result(serializer.Deserialize(NULL, error)); - if (!result) - return NULL; - - scoped_refptr<Extension> extension = Extension::Create( - path.DirName(), Manifest::INTERNAL, - *static_cast<DictionaryValue*>(result.get()), Extension::NO_FLAGS, error); - return extension; + .AppendASCII("optional"); + return LoadManifest(path.AsUTF8Unsafe(), + "manifest.json", + Manifest::INTERNAL, + Extension::NO_FLAGS); } void AddPattern(URLPatternSet* extent, const std::string& pattern) { @@ -122,9 +116,8 @@ TEST_F(PermissionsUpdaterTest, AddAndRemovePermissions) { InitializeEmptyExtensionService(); // Load the test extension. - std::string error; - scoped_refptr<Extension> extension = LoadManifest(&error); - ASSERT_TRUE(error.empty()) << error; + scoped_refptr<Extension> extension = LoadOurManifest(); + ASSERT_TRUE(extension.get()); APIPermissionSet default_apis; default_apis.insert(APIPermission::kManagement); diff --git a/chrome/common/extensions/docs/templates/intros/declarativeWebRequest.html b/chrome/common/extensions/docs/templates/intros/declarativeWebRequest.html index c9a295f..154699d 100644 --- a/chrome/common/extensions/docs/templates/intros/declarativeWebRequest.html +++ b/chrome/common/extensions/docs/templates/intros/declarativeWebRequest.html @@ -14,8 +14,7 @@ efficiency. <p> You must declare the "declarativeWebRequest" permission in the <a href="manifest.html">extension manifest</a> to use this API, -along with <a href="declare_permissions.html">host permissions</a> for any -hosts whose network requests you want to access. +along with <a href="declare_permissions.html">host permissions</a>. </p> <pre>{ @@ -29,18 +28,33 @@ hosts whose network requests you want to access. }</pre> <p> -Note that certain types of non-sensitive requests do not require host +Note that certain types of non-sensitive actions do not require host permissions: <ul> <li><code>CancelRequest</code> <li><code>IgnoreRules</code> <li><code>RedirectToEmptyDocument</code> <li><code>RedirectToTransparentImage</code> - <li><code>RedirectByRegEx</code> when the redirect destination has - the same domain as the original request - <li><code>RedirectRequest</code> when the redirect destination has - the same domain as the original request </ul> +</p> +<p> +The <code>SendMessageToExtension</code> action requires host permissions +for any hosts whose network requests you want to trigger a message. +</p> +<p> +All other actions require host permissions to all URLs. +</p> +<p> +As an example, if <code>"*://*.google.com"</code> is the only host permission an +extension has, than such an extension may set up a rule to +<ul> + <li> cancel a request to "http://www.google.com" or "http://anything.else.com" + <li> send a message when navigating to "http://www.google.com" but not to +"http://something.else.com" +</ul> +The extension cannot set up a rule to redirect "http://www.google.com" to +"http://mail.google.com". +</p> <h2 id="rules">Rules</h2> diff --git a/chrome/common/extensions/extension_test_util.cc b/chrome/common/extensions/extension_test_util.cc index 621db1e..b9b0425 100644 --- a/chrome/common/extensions/extension_test_util.cc +++ b/chrome/common/extensions/extension_test_util.cc @@ -2,13 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/common/extensions/extension_test_util.h" + +#include "base/files/file_path.h" +#include "base/json/json_file_value_serializer.h" +#include "base/path_service.h" #include "base/values.h" +#include "chrome/common/chrome_paths.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_manifest_constants.h" -#include "chrome/common/extensions/extension_test_util.h" #include "testing/gtest/include/gtest/gtest.h" using extensions::Extension; +using extensions::Manifest; namespace extension_test_util { @@ -21,4 +27,65 @@ scoped_refptr<Extension> CreateExtensionWithID(std::string id) { values, Extension::NO_FLAGS, id, &error); } +scoped_refptr<Extension> LoadManifestUnchecked(const std::string& dir, + const std::string& test_file, + Manifest::Location location, + int extra_flags, + const std::string& id, + std::string* error) { + base::FilePath path; + PathService::Get(chrome::DIR_TEST_DATA, &path); + path = path.AppendASCII("extensions") + .AppendASCII(dir) + .AppendASCII(test_file); + + JSONFileValueSerializer serializer(path); + scoped_ptr<Value> result(serializer.Deserialize(NULL, error)); + if (!result) + return NULL; + const DictionaryValue* dict; + CHECK(result->GetAsDictionary(&dict)); + + scoped_refptr<Extension> extension = Extension::Create( + path.DirName(), location, *dict, extra_flags, id, error); + return extension; +} + +scoped_refptr<Extension> LoadManifestUnchecked(const std::string& dir, + const std::string& test_file, + Manifest::Location location, + int extra_flags, + std::string* error) { + return LoadManifestUnchecked( + dir, test_file, location, extra_flags, std::string(), error); +} + +scoped_refptr<Extension> LoadManifest(const std::string& dir, + const std::string& test_file, + Manifest::Location location, + int extra_flags) { + std::string error; + scoped_refptr<Extension> extension = + LoadManifestUnchecked(dir, test_file, location, extra_flags, &error); + + EXPECT_TRUE(extension) << test_file << ":" << error; + return extension; +} + +scoped_refptr<Extension> LoadManifest(const std::string& dir, + const std::string& test_file, + int extra_flags) { + return LoadManifest(dir, test_file, Manifest::INVALID_LOCATION, extra_flags); +} + +scoped_refptr<Extension> LoadManifestStrict(const std::string& dir, + const std::string& test_file) { + return LoadManifest(dir, test_file, Extension::NO_FLAGS); +} + +scoped_refptr<Extension> LoadManifest(const std::string& dir, + const std::string& test_file) { + return LoadManifest(dir, test_file, Extension::NO_FLAGS); +} + } // namespace extension_test_util diff --git a/chrome/common/extensions/extension_test_util.h b/chrome/common/extensions/extension_test_util.h index a549d98..278f514 100644 --- a/chrome/common/extensions/extension_test_util.h +++ b/chrome/common/extensions/extension_test_util.h @@ -8,6 +8,7 @@ #include <string> #include "base/memory/ref_counted.h" +#include "chrome/common/extensions/manifest.h" namespace extensions { class Extension; @@ -21,6 +22,40 @@ std::string MakeId(std::string seed); // Return a very simple extension with id |id|. scoped_refptr<extensions::Extension> CreateExtensionWithID(std::string id); +// Helpers for loading manifests, |dir| is relative to chrome::DIR_TEST_DATA +// followed by "extensions". +scoped_refptr<extensions::Extension> LoadManifestUnchecked( + const std::string& dir, + const std::string& test_file, + extensions::Manifest::Location location, + int extra_flags, + const std::string& id, + std::string* error); + +scoped_refptr<extensions::Extension> LoadManifestUnchecked( + const std::string& dir, + const std::string& test_file, + extensions::Manifest::Location location, + int extra_flags, + std::string* error); + +scoped_refptr<extensions::Extension> LoadManifest( + const std::string& dir, + const std::string& test_file, + extensions::Manifest::Location location, + int extra_flags); + +scoped_refptr<extensions::Extension> LoadManifest(const std::string& dir, + const std::string& test_file, + int extra_flags); + +scoped_refptr<extensions::Extension> LoadManifestStrict( + const std::string& dir, + const std::string& test_file); + +scoped_refptr<extensions::Extension> LoadManifest(const std::string& dir, + const std::string& test_file); + } // namespace extension_test_util #endif // CHROME_COMMON_EXTENSIONS_EXTENSION_TEST_UTIL_H_ diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc index c426c2a..62ef7eb 100644 --- a/chrome/common/extensions/extension_unittest.cc +++ b/chrome/common/extensions/extension_unittest.cc @@ -6,9 +6,7 @@ #include "base/command_line.h" #include "base/file_util.h" -#include "base/files/file_path.h" #include "base/format_macros.h" -#include "base/json/json_file_value_serializer.h" #include "base/path_service.h" #include "base/stringprintf.h" #include "base/strings/string_number_conversions.h" @@ -21,6 +19,7 @@ #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_file_util.h" #include "chrome/common/extensions/extension_manifest_constants.h" +#include "chrome/common/extensions/extension_test_util.h" #include "chrome/common/extensions/features/feature.h" #include "chrome/common/extensions/incognito_handler.h" #include "chrome/common/extensions/manifest.h" @@ -45,67 +44,15 @@ #include "ui/gfx/codec/png_codec.h" using content::SocketPermissionRequest; +using extension_test_util::LoadManifest; +using extension_test_util::LoadManifestUnchecked; +using extension_test_util::LoadManifestStrict; namespace keys = extension_manifest_keys; namespace values = extension_manifest_values; namespace errors = extension_manifest_errors; namespace extensions { -namespace { - -scoped_refptr<Extension> LoadManifestUnchecked( - const std::string& dir, - const std::string& test_file, - Manifest::Location location, - int extra_flags, - std::string* error) { - base::FilePath path; - PathService::Get(chrome::DIR_TEST_DATA, &path); - path = path.AppendASCII("extensions") - .AppendASCII(dir) - .AppendASCII(test_file); - - JSONFileValueSerializer serializer(path); - scoped_ptr<Value> result(serializer.Deserialize(NULL, error)); - if (!result.get()) - return NULL; - - scoped_refptr<Extension> extension = Extension::Create( - path.DirName(), location, *static_cast<DictionaryValue*>(result.get()), - extra_flags, error); - return extension; -} - -static scoped_refptr<Extension> LoadManifest(const std::string& dir, - const std::string& test_file, - Manifest::Location location, - int extra_flags) { - std::string error; - scoped_refptr<Extension> extension = LoadManifestUnchecked(dir, test_file, - location, extra_flags, &error); - - EXPECT_TRUE(extension) << test_file << ":" << error; - return extension; -} - -static scoped_refptr<Extension> LoadManifest(const std::string& dir, - const std::string& test_file, - int extra_flags) { - return LoadManifest(dir, test_file, Manifest::INVALID_LOCATION, extra_flags); -} - -static scoped_refptr<Extension> LoadManifest(const std::string& dir, - const std::string& test_file) { - return LoadManifest(dir, test_file, Extension::NO_FLAGS); -} - -static scoped_refptr<Extension> LoadManifestStrict( - const std::string& dir, - const std::string& test_file) { - return LoadManifest(dir, test_file, Extension::NO_FLAGS); -} - -} // namespace ExtensionTest::ExtensionTest() : permissions_info_(ChromeAPIPermissions()) {} diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc index 73cef12..2b99187 100644 --- a/chrome/common/extensions/permissions/permission_set_unittest.cc +++ b/chrome/common/extensions/permissions/permission_set_unittest.cc @@ -11,6 +11,7 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/api/plugins/plugins_handler.h" #include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_test_util.h" #include "chrome/common/extensions/extension_unittest.h" #include "chrome/common/extensions/features/feature.h" #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h" @@ -20,39 +21,12 @@ #include "extensions/common/error_utils.h" #include "testing/gtest/include/gtest/gtest.h" +using extension_test_util::LoadManifest; + namespace extensions { namespace { -scoped_refptr<Extension> LoadManifest(const std::string& dir, - const std::string& test_file, - int extra_flags) { - base::FilePath path; - PathService::Get(chrome::DIR_TEST_DATA, &path); - path = path.AppendASCII("extensions") - .AppendASCII(dir) - .AppendASCII(test_file); - - JSONFileValueSerializer serializer(path); - std::string error; - scoped_ptr<Value> result(serializer.Deserialize(NULL, &error)); - if (!result.get()) { - EXPECT_EQ("", error); - return NULL; - } - - scoped_refptr<Extension> extension = Extension::Create( - path.DirName(), Manifest::INVALID_LOCATION, - *static_cast<DictionaryValue*>(result.get()), extra_flags, &error); - EXPECT_TRUE(extension) << error; - return extension; -} - -scoped_refptr<Extension> LoadManifest(const std::string& dir, - const std::string& test_file) { - return LoadManifest(dir, test_file, Extension::NO_FLAGS); -} - static void AddPattern(URLPatternSet* extent, const std::string& pattern) { int schemes = URLPattern::SCHEME_ALL; extent->AddPattern(URLPattern(schemes, pattern)); diff --git a/chrome/test/data/extensions/api_test/declarative/api/manifest.json b/chrome/test/data/extensions/api_test/declarative/api/manifest.json index 3e0f3fd..8c1bbd9 100644 --- a/chrome/test/data/extensions/api_test/declarative/api/manifest.json +++ b/chrome/test/data/extensions/api_test/declarative/api/manifest.json @@ -7,6 +7,6 @@ "scripts": ["background.js"] }, "permissions": [ - "declarativeWebRequest" + "declarativeWebRequest", "<all_urls>" ] } diff --git a/chrome/test/data/extensions/api_test/webrequest/manifest.json b/chrome/test/data/extensions/api_test/webrequest/manifest.json index 6cf7d40..3ecf7a3 100644 --- a/chrome/test/data/extensions/api_test/webrequest/manifest.json +++ b/chrome/test/data/extensions/api_test/webrequest/manifest.json @@ -4,8 +4,7 @@ "manifest_version": 2, "description": "Tests the webRequest API.", "permissions": ["webRequest", "webRequestBlocking", "tabs", - "declarativeWebRequest", "http://*.a.com/*", "https://*.a.com/*", - "http://non_existing_third_party.com/image.png"], + "declarativeWebRequest", "<all_urls>"], "web_accessible_resources": [ "simpleLoad/a.html", "complexLoad/a.html", diff --git a/chrome/test/data/extensions/api_test/webrequest/permissionless/manifest.json b/chrome/test/data/extensions/api_test/webrequest/permissionless/manifest.json deleted file mode 100644 index c0f2c25..0000000 --- a/chrome/test/data/extensions/api_test/webrequest/permissionless/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "declarativeWebRequest rules without host permissions", - "description": "Helper test extension for declarative webRequest; declare rules affecting hosts without having permissions on them.", - "version": "1", - "manifest_version": 2, - "permissions": ["declarativeWebRequest", "http://*.c.com/*"], - "background": { - "scripts": ["rules.js"] - } -} diff --git a/chrome/test/data/extensions/api_test/webrequest/permissionless/rules.js b/chrome/test/data/extensions/api_test/webrequest/permissionless/rules.js deleted file mode 100644 index 32b0ff8..0000000 --- a/chrome/test/data/extensions/api_test/webrequest/permissionless/rules.js +++ /dev/null @@ -1,50 +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. - -// See ../test_declarative_permissions.js for the tests that use these rules. - -var onRequest = chrome.declarativeWebRequest.onRequest; -var RequestMatcher = chrome.declarativeWebRequest.RequestMatcher; - -chrome.test.getConfig(function(config) { - addRules(config.testServer.port); -}); - -function addRules(testServerPort) { - onRequest.addRules( - [{conditions: [new RequestMatcher({ - url: {hostSuffix: '.a.com', - schemes: ['https']}})], - actions: [new chrome.declarativeWebRequest.RedirectRequest({ - redirectUrl: 'http://www.a.com:' + testServerPort + - '/files/nonexistent/redirected' })] - }, - {conditions: [new RequestMatcher({ - url: {hostSuffix: '.a.com', - pathSuffix: '/b.html'}})], - actions: [new chrome.declarativeWebRequest.RedirectRequest({ - redirectUrl: 'http://www.c.com:' + testServerPort + - '/files/nonexistent/redirected' })] - }, - {conditions: [new RequestMatcher({ - url: {hostSuffix: '.a.com', - pathSuffix: '/fake.html'}})], - actions: [new chrome.declarativeWebRequest.RedirectByRegEx({ - from: '(.*)fake(.*)', to: '$1b$2' - })] - }, - - {conditions: [new RequestMatcher({url: {pathContains: 'blank'}})], - actions: [new chrome.declarativeWebRequest.RedirectToEmptyDocument()] - }, - {conditions: [new RequestMatcher({url: {pathContains: 'cancel'}})], - actions: [new chrome.declarativeWebRequest.CancelRequest()] - }], - function(rules) { - if (chrome.runtime.lastError) - chrome.test.fail(chrome.runtime.lastError); - chrome.test.sendMessage("rules all registered"); - } - ); -} diff --git a/chrome/test/data/extensions/api_test/webrequest/test_declarative2.js b/chrome/test/data/extensions/api_test/webrequest/test_declarative2.js index be4b114..b2c9609 100644 --- a/chrome/test/data/extensions/api_test/webrequest/test_declarative2.js +++ b/chrome/test/data/extensions/api_test/webrequest/test_declarative2.js @@ -254,42 +254,6 @@ runTests([ ); }, - function testPermission() { - // Test that a redirect is ignored if the extension has no permission. - // we load a.html from a.com and issue an XHR to b.com, which is not - // contained in the extension's host permissions. Therefore, we cannot - // redirect the XHR from b.com to a.com, and the request returns the - // original file from b.com. - ignoreUnexpected = true; - expect(); - onRequest.addRules( - [ {'conditions': [new RequestMatcher({'url': {'pathContains': ".json"}})], - 'actions': [ - new RedirectRequest({'redirectUrl': getURLHttpSimple()})]} - ], - function() { - var callback = chrome.test.callbackAdded(); - navigateAndWait(getURL("simpleLoad/a.html"), function() { - var asynchronous = false; - var req = new XMLHttpRequest(); - req.onreadystatechange = function() { - if (this.readyState != this.DONE) - return; - // "{}" is the contents of the file at getURLHttpXHRData(). - if (this.status == 200 && this.responseText == "{}\n") { - callback(); - } else { - chrome.test.fail("Redirect was not prevented. Status: " + - this.status + ", responseText: " + this.responseText); - } - }; - req.open("GET", getURLHttpXHRData(), asynchronous); - req.send(); - }); - } - ); - }, - function testRequestHeaders() { ignoreUnexpected = true; expect( diff --git a/chrome/test/data/extensions/api_test/webrequest/test_declarative_permissions.html b/chrome/test/data/extensions/api_test/webrequest/test_declarative_permissions.html deleted file mode 100644 index 9300144..0000000 --- a/chrome/test/data/extensions/api_test/webrequest/test_declarative_permissions.html +++ /dev/null @@ -1,2 +0,0 @@ -<script src="framework.js"></script> -<script src="test_declarative_permissions.js"></script> diff --git a/chrome/test/data/extensions/api_test/webrequest/test_declarative_permissions.js b/chrome/test/data/extensions/api_test/webrequest/test_declarative_permissions.js deleted file mode 100644 index 9609a34..0000000 --- a/chrome/test/data/extensions/api_test/webrequest/test_declarative_permissions.js +++ /dev/null @@ -1,126 +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. - -// See permissionless/rules.js for the rules that this test uses. - -runTests([ - // Test that it's possible to redirect within the same domain and port - // (ignoring the scheme) without host permissions. - function testRedirectSameDomain() { - ignoreUnexpected = true; - var testURL = getServerURL( - 'files/extensions/api_test/webrequest/simpleLoad/a.html', - 'www.a.com', 'https'); - expect( - [ - { label: 'onBeforeRedirect', - event: 'onBeforeRedirect', - details: { - url: testURL, - redirectUrl: getServerURL('files/nonexistent/redirected'), - statusCode: -1, - statusLine: '', - fromCache: false, - } - }, - ], - [ ['onBeforeRedirect'] ] - ); - navigateAndWait(testURL); - }, - - // Test that it's not possible to redirect to a different domain - // without host permissions on the original domain. We should still - // load the original URL. - function testCannotRedirectDifferentDomains() { - ignoreUnexpected = true; - var testURL = getServerURL( - 'files/extensions/api_test/webrequest/simpleLoad/b.html'); - expect( - [ - { label: 'onCompleted', - event: 'onCompleted', - details: { - url: testURL, - fromCache: false, - ip: '127.0.0.1', - statusCode: 200, - statusLine: 'HTTP/1.0 200 OK', - } - }, - ], - [ ['onCompleted'] ] - ); - navigateAndWait(testURL); - }, - - // Test that it's possible to redirect by regex within the same - // domain and port (ignoring the scheme) without host permissions. - function testRedirectByRegexSameDomain() { - ignoreUnexpected = true; - var testURL = getServerURL( - 'files/extensions/api_test/webrequest/simpleLoad/fake.html'); - expect( - [ - { label: 'onBeforeRedirect', - event: 'onBeforeRedirect', - details: { - url: testURL, - redirectUrl: getServerURL( - 'files/extensions/api_test/webrequest/simpleLoad/b.html'), - statusCode: -1, - statusLine: '', - fromCache: false, - } - }, - ], - [ ['onBeforeRedirect'] ] - ); - navigateAndWait(testURL); - }, - - // Test that it's possible to redirect to a blank page/image - // without host permissions. - function testRedirectToEmpty() { - var testURL = getServerURL('files/nonexistent/blank.html'); - ignoreUnexpected = true; - expect( - [ - { label: 'onBeforeRedirect', - event: 'onBeforeRedirect', - details: { - url: testURL, - redirectUrl: 'data:text/html,', - statusCode: -1, - statusLine: '', - fromCache: false, - } - }, - ], - [ ['onBeforeRedirect'] ] - ); - navigateAndWait(testURL); - }, - - // Test that it's possible to cancel a request without host permissions. - function testCancelRequest() { - ignoreUnexpected = true; - var testURL = getServerURL('files/nonexistent/cancel.html'); - expect( - [ - { label: 'onErrorOccurred', - event: 'onErrorOccurred', - details: { - url: testURL, - fromCache: false, - error: 'net::ERR_BLOCKED_BY_CLIENT' - } - }, - ], - [ ['onErrorOccurred'] ] - ); - navigateAndWait(testURL); - }, - -]); diff --git a/chrome/test/data/extensions/api_test/webrequest/test_simple.js b/chrome/test/data/extensions/api_test/webrequest/test_simple.js index b3a1a08..0db4373 100644 --- a/chrome/test/data/extensions/api_test/webrequest/test_simple.js +++ b/chrome/test/data/extensions/api_test/webrequest/test_simple.js @@ -11,12 +11,6 @@ function getURLHttpSimpleLoadRedirect() { return getServerURL('server-redirect?'+getURLHttpSimpleLoad()); } -// A URL from b.com, which we don't have permission to access. -function getURLNotVisible() { - return getServerURL('files/extensions/api_test/webrequest/simpleLoad/b.html', - 'b.com'); -} - runTests([ // Navigates to a blank page. function simpleLoad() { @@ -188,44 +182,4 @@ runTests([ ["onBeforeRequest", "onErrorOccurred"] ]); navigateAndWait(getURL("does_not_exist.html")); }, - - // Navigates to a page that we don't have access to, then a blank page. - // We should not see the first navigation. - function simpleLoadNonVisible() { - expect( - [ // events - { label: "a-onBeforeRequest", - event: "onBeforeRequest", - details: { - url: getURL("simpleLoad/a.html"), - frameUrl: getURL("simpleLoad/a.html") - } - }, - { label: "a-onResponseStarted", - event: "onResponseStarted", - details: { - url: getURL("simpleLoad/a.html"), - statusCode: 200, - fromCache: false, - statusLine: "HTTP/1.1 200 OK", - // Request to chrome-extension:// url has no IP. - } - }, - { label: "a-onCompleted", - event: "onCompleted", - details: { - url: getURL("simpleLoad/a.html"), - statusCode: 200, - fromCache: false, - statusLine: "HTTP/1.1 200 OK", - // Request to chrome-extension:// url has no IP. - } - }, - ], - [ // event order - ["a-onBeforeRequest", "a-onResponseStarted", "a-onCompleted"] ]); - navigateAndWait(getURLNotVisible(), function() { - navigateAndWait(getURL("simpleLoad/a.html")); - }); - }, ]); diff --git a/chrome/test/data/extensions/permissions/web_request_all_host_permissions.json b/chrome/test/data/extensions/permissions/web_request_all_host_permissions.json new file mode 100644 index 0000000..bdd0eae --- /dev/null +++ b/chrome/test/data/extensions/permissions/web_request_all_host_permissions.json @@ -0,0 +1,5 @@ +{ + "name": "Extension without full host permissions", + "version": "1.0", + "permissions": ["declarativeWebRequest", "webRequest", "webRequestBlocking", "*://*/*" ] +} diff --git a/chrome/test/data/extensions/permissions/web_request_com_host_permissions.json b/chrome/test/data/extensions/permissions/web_request_com_host_permissions.json new file mode 100644 index 0000000..c035c4c --- /dev/null +++ b/chrome/test/data/extensions/permissions/web_request_com_host_permissions.json @@ -0,0 +1,5 @@ +{ + "name": "Extension without full host permissions", + "version": "1.0", + "permissions": ["declarativeWebRequest", "webRequest", "webRequestBlocking", "*://*.com/*" ] +} diff --git a/chrome/test/data/extensions/permissions/web_request_no_host.json b/chrome/test/data/extensions/permissions/web_request_no_host.json new file mode 100644 index 0000000..9564dc1 --- /dev/null +++ b/chrome/test/data/extensions/permissions/web_request_no_host.json @@ -0,0 +1,5 @@ +{ + "name": "Extension without host permissions but with full (D)WR permissions.", + "version": "1.0", + "permissions": ["declarativeWebRequest", "webRequest", "webRequestBlocking" ] +} |