diff options
author | battre@chromium.org <battre@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-30 17:21:41 +0000 |
---|---|---|
committer | battre@chromium.org <battre@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-30 17:21:41 +0000 |
commit | 3dfa4c08bd73745edd13e38b9d832eac0dabd925 (patch) | |
tree | a7c16fbfdc08f8d7e7d85f8402bc49ca12f8f249 | |
parent | 9a80715bd54cf030c89a9b0941551fe8bc028df9 (diff) | |
download | chromium_src-3dfa4c08bd73745edd13e38b9d832eac0dabd925.zip chromium_src-3dfa4c08bd73745edd13e38b9d832eac0dabd925.tar.gz chromium_src-3dfa4c08bd73745edd13e38b9d832eac0dabd925.tar.bz2 |
Refactor and fix declarative webRequest API permissions
This CL introduces proper host permission checking for the declarative webRequest API. It moves the permission checking code from web_request_api.cc into a separate class that is shared with the declarative WebRequest API.
BUG=112155
TEST=no
TBR=mirandac@chromium.org,akalin@chromium.org,ben@chromium.org
Review URL: https://chromiumcodereview.appspot.com/10831008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@148965 0039d316-1c4b-4281-b951-d872f2087c98
37 files changed, 662 insertions, 280 deletions
diff --git a/chrome/browser/extensions/api/declarative/rules_registry_service.cc b/chrome/browser/extensions/api/declarative/rules_registry_service.cc index aead2a9..24e7f32 100644 --- a/chrome/browser/extensions/api/declarative/rules_registry_service.cc +++ b/chrome/browser/extensions/api/declarative/rules_registry_service.cc @@ -22,15 +22,20 @@ namespace extensions { namespace { // Returns the key to use for storing declarative rules in the state store. -std::string GetDeclarativeRuleStorageKey(const std::string& event_name) { - return "declarative_rules." + event_name; +std::string GetDeclarativeRuleStorageKey(const std::string& event_name, + bool incognito) { + if (incognito) + return "declarative_rules.incognito." + event_name; + else + return "declarative_rules." + event_name; } // Registers |web_request_rules_registry| on the IO thread. void RegisterToExtensionWebRequestEventRouterOnIO( + void* profile, scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry) { ExtensionWebRequestEventRouter::GetInstance()->RegisterRulesRegistry( - web_request_rules_registry); + profile, web_request_rules_registry); } } // namespace @@ -39,7 +44,7 @@ RulesRegistryService::RulesRegistryService(Profile* profile) : profile_(profile) { if (profile) { registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, - content::Source<Profile>(profile)); + content::Source<Profile>(profile->GetOriginalProfile())); } } @@ -54,7 +59,8 @@ void RulesRegistryService::RegisterDefaultRulesRegistries() { new WebRequestRulesRegistry(profile_, delegate)); delegate->InitOnUIThread(profile_, web_request_rules_registry, GetDeclarativeRuleStorageKey( - declarative_webrequest_constants::kOnRequest)); + declarative_webrequest_constants::kOnRequest, + profile_->IsOffTheRecord())); delegates_.push_back(delegate); RegisterRulesRegistry(declarative_webrequest_constants::kOnRequest, @@ -62,14 +68,14 @@ void RulesRegistryService::RegisterDefaultRulesRegistries() { content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO, - web_request_rules_registry)); + profile_, web_request_rules_registry)); } void RulesRegistryService::Shutdown() { content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO, - scoped_refptr<WebRequestRulesRegistry>(NULL))); + profile_, scoped_refptr<WebRequestRulesRegistry>(NULL))); } void RulesRegistryService::RegisterRulesRegistry( diff --git a/chrome/browser/extensions/api/declarative/rules_registry_storage_delegate.cc b/chrome/browser/extensions/api/declarative/rules_registry_storage_delegate.cc index 010e140..41e51a1 100644 --- a/chrome/browser/extensions/api/declarative/rules_registry_storage_delegate.cc +++ b/chrome/browser/extensions/api/declarative/rules_registry_storage_delegate.cc @@ -5,8 +5,11 @@ #include "chrome/browser/extensions/api/declarative/rules_registry_storage_delegate.h" #include "base/bind.h" +#include "chrome/browser/extensions/extension_info_map.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_system.h" #include "chrome/browser/extensions/state_store.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/extensions/extension.h" #include "content/public/browser/browser_thread.h" @@ -64,6 +67,10 @@ class RulesRegistryStorageDelegate::Inner ~Inner(); + // Initialization of the storage delegate if it is used in the context of + // an incognito profile. + void InitForOTRProfile(); + // NotificationObserver virtual void Observe( int type, @@ -164,16 +171,35 @@ RulesRegistryStorageDelegate::Inner::Inner( rules_registry_thread_(rules_registry->GetOwnerThread()), rules_registry_(rules_registry), ready_(false) { - registrar_->Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, - content::Source<Profile>(profile)); - registrar_->Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, - content::Source<Profile>(profile)); + if (!profile_->IsOffTheRecord()) { + registrar_->Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, + content::Source<Profile>(profile)); + registrar_->Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, + content::Source<Profile>(profile)); + } else { + registrar_->Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, + content::Source<Profile>(profile->GetOriginalProfile())); + InitForOTRProfile(); + } } RulesRegistryStorageDelegate::Inner::~Inner() { DCHECK(!registrar_.get()); } +void RulesRegistryStorageDelegate::Inner::InitForOTRProfile() { + ExtensionService* extension_service = + extensions::ExtensionSystem::Get(profile_)->extension_service(); + const ExtensionSet* extensions = extension_service->extensions(); + for (ExtensionSet::const_iterator i = extensions->begin(); + i != extensions->end(); ++i) { + if ((*i)->HasAPIPermission(APIPermission::kDeclarativeWebRequest) && + extension_service->IsIncognitoEnabled((*i)->id())) + ReadFromStorage((*i)->id()); + } + ready_ = true; +} + void RulesRegistryStorageDelegate::Inner::Observe( int type, const content::NotificationSource& source, @@ -186,7 +212,14 @@ void RulesRegistryStorageDelegate::Inner::Observe( // declarative rules, not just webRequest. if (extension->HasAPIPermission( APIPermission::kDeclarativeWebRequest)) { - ReadFromStorage(extension->id()); + ExtensionInfoMap* extension_info_map = + ExtensionSystem::Get(profile_)->info_map(); + if (profile_->IsOffTheRecord() && + !extension_info_map->IsIncognitoEnabled(extension->id())) { + // Ignore this extension. + } else { + ReadFromStorage(extension->id()); + } } } else if (type == chrome::NOTIFICATION_EXTENSIONS_READY) { CheckIfReady(); diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc index 4a01ff0..9301dc0 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc @@ -15,6 +15,7 @@ #include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" +#include "chrome/browser/extensions/api/web_request/web_request_permissions.h" #include "chrome/browser/extensions/extension_info_map.h" #include "chrome/common/extensions/extension.h" #include "net/url_request/url_request.h" @@ -198,19 +199,24 @@ int WebRequestAction::GetMinimumPriority() const { return std::numeric_limits<int>::min(); } -bool WebRequestAction::HasPermission(const extensions::Extension* extension, - const net::URLRequest* request) const { - // TODO(battre): Consider the permission to access requests from the incognito - // profile. - // TODO(battre): There should be a single place to check permissions for both - // the WebRequest API and the Declarative WebRequest API. - if (helpers::HideRequest(request)) +bool WebRequestAction::HasPermission(const ExtensionInfoMap* extension_info_map, + const std::string& extension_id, + const net::URLRequest* request, + bool crosses_incognito) const { + if (WebRequestPermissions::HideRequest(request)) return false; - if (extension && !helpers::CanExtensionAccessURL(extension, request->url())) - return false; - // System requests are passed to extensions without host permissions. - // This is the same behavior as found in - // ExtensionWebRequestEventRouter::GetMatchingListenersImpl. + + // In unit tests we don't have an extension_info_map object here and skip host + // permission checks. + if (!extension_info_map) + return true; + + return WebRequestPermissions::CanExtensionAccessURL( + extension_info_map, extension_id, request->url(), crosses_incognito, + ShouldEnforceHostPermissions()); +} + +bool WebRequestAction::ShouldEnforceHostPermissions() const { return true; } @@ -272,15 +278,17 @@ scoped_ptr<WebRequestActionSet> WebRequestActionSet::Create( } std::list<LinkedPtrEventResponseDelta> WebRequestActionSet::CreateDeltas( - const extensions::Extension* extension, + const ExtensionInfoMap* extension_info_map, + const std::string& extension_id, net::URLRequest* request, + bool crosses_incognito, RequestStages request_stage, const WebRequestRule::OptionalRequestData& optional_request_data, - const std::string& extension_id, const base::Time& extension_install_time) const { std::list<LinkedPtrEventResponseDelta> result; for (Actions::const_iterator i = actions_.begin(); i != actions_.end(); ++i) { - if (!(*i)->HasPermission(extension, request)) + if (!(*i)->HasPermission(extension_info_map, extension_id, request, + crosses_incognito)) continue; if ((*i)->GetStages() & request_stage) { LinkedPtrEventResponseDelta delta = (*i)->CreateDelta(request, @@ -382,12 +390,9 @@ WebRequestRedirectToTransparentImageAction::GetType() const { return WebRequestAction::ACTION_REDIRECT_TO_TRANSPARENT_IMAGE; } -bool WebRequestRedirectToTransparentImageAction::HasPermission( - const extensions::Extension* extension, - const net::URLRequest* request) const { - // TODO(battre): Consider the permission to access requests from the incognito - // profile. - return true; +bool WebRequestRedirectToTransparentImageAction::ShouldEnforceHostPermissions() + const { + return false; } LinkedPtrEventResponseDelta @@ -423,10 +428,9 @@ WebRequestRedirectToEmptyDocumentAction::GetType() const { return WebRequestAction::ACTION_REDIRECT_TO_EMPTY_DOCUMENT; } -bool WebRequestRedirectToEmptyDocumentAction::HasPermission( - const extensions::Extension* extension, - const net::URLRequest* request) const { - return true; +bool +WebRequestRedirectToEmptyDocumentAction::ShouldEnforceHostPermissions() const { + return false; } LinkedPtrEventResponseDelta @@ -744,10 +748,8 @@ int WebRequestIgnoreRulesAction::GetMinimumPriority() const { return minimum_priority_; } -bool WebRequestIgnoreRulesAction::HasPermission( - const extensions::Extension* extension, - const net::URLRequest* request) const { - return true; +bool WebRequestIgnoreRulesAction::ShouldEnforceHostPermissions() const { + return false; } LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::CreateDelta( diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h index 01f7e4a..96d0a3d 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h @@ -17,6 +17,8 @@ #include "googleurl/src/gurl.h" #include "unicode/regex.h" +class WebRequestPermission; + namespace base { class DictionaryValue; class Time; @@ -72,12 +74,21 @@ class WebRequestAction { // this rule. Defaults to MIN_INT. virtual int GetMinimumPriority() const; - // Returns whether |extension| has permission to execute this action - // on |request|. Defaults to checking the host permission. - // |extension| may only be NULL for during testing, in which case - // host permissions are ignored. - virtual bool HasPermission(const extensions::Extension* extension, - const net::URLRequest* request) const; + // Returns whether the specified extension has permission to execute this + // action on |request|. Checks the host permission if + // ShouldEnforceHostPermissions instructs to do that. + // |extension_info_map| may only be NULL for during testing, in which case + // host permissions are ignored. |crosses_incognito| specifies + // whether the request comes from a different profile than |extension_id| + // but was processed because the extension is in spanning mode. + virtual bool HasPermission(const ExtensionInfoMap* extension_info_map, + const std::string& extension_id, + const net::URLRequest* request, + bool crosses_incognito) const; + + // Returns whether host permissions shall be enforced by this actions. + // Used by the standard implementation of HasPermission. Defaults to true. + virtual bool ShouldEnforceHostPermissions() const; // Factory method that instantiates a concrete WebRequestAction // implementation according to |json_action|, the representation of the @@ -123,11 +134,12 @@ class WebRequestActionSet { // |actions_| that can be executed at |request_stage|. If |extension| // is not NULL, permissions of extensions are checked. std::list<LinkedPtrEventResponseDelta> CreateDeltas( - const extensions::Extension* extension, + const ExtensionInfoMap* extension_info_map, + const std::string& extension_id, net::URLRequest* request, + bool crosses_incognito, RequestStages request_stage, const WebRequestRule::OptionalRequestData& optional_request_data, - const std::string& extension_id, const base::Time& extension_install_time) const; // Returns the minimum priority of rules that may be evaluated after @@ -197,8 +209,7 @@ class WebRequestRedirectToTransparentImageAction : public WebRequestAction { // Implementation of WebRequestAction: virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; - virtual bool HasPermission(const extensions::Extension* extension, - const net::URLRequest* request) const OVERRIDE; + virtual bool ShouldEnforceHostPermissions() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( net::URLRequest* request, RequestStages request_stage, @@ -220,8 +231,7 @@ class WebRequestRedirectToEmptyDocumentAction : public WebRequestAction { // Implementation of WebRequestAction: virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; - virtual bool HasPermission(const extensions::Extension* extension, - const net::URLRequest* request) const OVERRIDE; + virtual bool ShouldEnforceHostPermissions() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( net::URLRequest* request, RequestStages request_stage, @@ -366,8 +376,7 @@ class WebRequestIgnoreRulesAction : public WebRequestAction { virtual int GetStages() const OVERRIDE; virtual Type GetType() const OVERRIDE; virtual int GetMinimumPriority() const OVERRIDE; - virtual bool HasPermission(const extensions::Extension* extension, - const net::URLRequest* request) const OVERRIDE; + virtual bool ShouldEnforceHostPermissions() const OVERRIDE; virtual LinkedPtrEventResponseDelta CreateDelta( net::URLRequest* request, RequestStages request_stage, 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 bb95594..1161258 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc @@ -148,14 +148,16 @@ TEST(WebRequestActionTest, TestPermissions) { // Check that redirect works on regular URLs but not on protected URLs. TestURLRequest regular_request(GURL("http://test.com"), NULL, &context); std::list<LinkedPtrEventResponseDelta> deltas = - action_set->CreateDeltas(NULL, ®ular_request, ON_BEFORE_REQUEST, - WebRequestRule::OptionalRequestData(), "ext1", base::Time()); + action_set->CreateDeltas(NULL, "ext1", ®ular_request, false, + ON_BEFORE_REQUEST, WebRequestRule::OptionalRequestData(), + base::Time()); EXPECT_EQ(1u, deltas.size()); TestURLRequest protected_request(GURL(extension_urls::kGalleryBrowsePrefix), NULL, &context); - deltas = action_set->CreateDeltas(NULL, &protected_request, ON_BEFORE_REQUEST, - WebRequestRule::OptionalRequestData(), "ext1", base::Time()); + deltas = action_set->CreateDeltas(NULL, "ext1", &protected_request, false, + ON_BEFORE_REQUEST, WebRequestRule::OptionalRequestData(), + base::Time()); EXPECT_EQ(0u, deltas.size()); } diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.cc index 1b5ccb747..b7fb22b 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.cc @@ -8,6 +8,8 @@ #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h" #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" +#include "chrome/browser/extensions/api/web_request/web_request_permissions.h" +#include "chrome/browser/extensions/extension_info_map.h" #include "chrome/common/extensions/extension.h" namespace { @@ -87,12 +89,14 @@ scoped_ptr<WebRequestRule> WebRequestRule::Create( } std::list<LinkedPtrEventResponseDelta> WebRequestRule::CreateDeltas( - const extensions::Extension* extension, + const ExtensionInfoMap* extension_info_map, net::URLRequest* request, + bool crosses_incognito, RequestStages request_stage, const OptionalRequestData& optional_request_data) const { - return actions_->CreateDeltas(extension, request, request_stage, - optional_request_data, id_.first, extension_installation_time_); + return actions_->CreateDeltas(extension_info_map, extension_id(), request, + crosses_incognito, request_stage, optional_request_data, + extension_installation_time_); } int WebRequestRule::GetMinimumPriority() const { diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h index 40ddae6..d590de7 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h @@ -13,11 +13,14 @@ #include "chrome/browser/extensions/api/declarative/rules_registry.h" #include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h" +class ExtensionInfoMap; +class WebRequestPermissions; + namespace extensions { class Extension; class URLMatcherConditionFactory; -class WebRequestConditionSet; class WebRequestActionSet; +class WebRequestConditionSet; } namespace extension_web_request_api_helpers { @@ -66,6 +69,7 @@ class WebRequestRule { std::string* error); const GlobalRuleId& id() const { return id_; } + const std::string& extension_id() const { return id_.first; } const WebRequestConditionSet& conditions() const { return *conditions_; } const WebRequestActionSet& actions() const { return *actions_; } Priority priority() const { return priority_; } @@ -78,8 +82,9 @@ class WebRequestRule { // have have sufficient permissions to modify the |request|. The returned list // may be empty in this case. std::list<LinkedPtrEventResponseDelta> CreateDeltas( - const extensions::Extension* extension, + const ExtensionInfoMap* extension_info_map, net::URLRequest* request, + bool crosses_incognito, RequestStages request_stage, const OptionalRequestData& optional_request_data) const; 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 ce978b2..ad0348b 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc @@ -8,6 +8,7 @@ #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 "net/url_request/url_request.h" @@ -46,6 +47,7 @@ WebRequestRulesRegistry::GetMatches(net::URLRequest* request, std::list<LinkedPtrEventResponseDelta> WebRequestRulesRegistry::CreateDeltas( const ExtensionInfoMap* extension_info_map, net::URLRequest* request, + bool crosses_incognito, RequestStages request_stage, const WebRequestRule::OptionalRequestData& optional_request_data) { if (webrequest_rules_.empty()) @@ -92,9 +94,6 @@ std::list<LinkedPtrEventResponseDelta> WebRequestRulesRegistry::CreateDeltas( const ExtensionId& extension_id = rule_id.first; const WebRequestRule* rule = webrequest_rules_[rule_id].get(); CHECK(rule); - const extensions::Extension* extension = NULL; - if (extension_info_map) - extension = extension_info_map->extensions().GetByID(extension_id); // Skip rule if a previous rule of this extension instructed to ignore // all rules with a lower priority than min_priorities[extension_id]. @@ -103,8 +102,8 @@ std::list<LinkedPtrEventResponseDelta> WebRequestRulesRegistry::CreateDeltas( continue; std::list<LinkedPtrEventResponseDelta> rule_result = - rule->CreateDeltas(extension, request, request_stage, - optional_request_data); + rule->CreateDeltas(extension_info_map, request, crosses_incognito, + request_stage, optional_request_data); result.splice(result.begin(), rule_result); min_priorities[extension_id] = std::max(current_min_priority, 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 55f0083..cb01240 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h @@ -20,6 +20,7 @@ #include "chrome/common/extensions/matcher/url_matcher.h" class Profile; +class WebRequestPermissions; namespace extension_web_request_api_helpers { struct EventResponseDelta; @@ -76,6 +77,7 @@ class WebRequestRulesRegistry : public RulesRegistryWithCache { std::list<LinkedPtrEventResponseDelta> CreateDeltas( const ExtensionInfoMap* extension_info_map, net::URLRequest* request, + bool crosses_incognito, RequestStages request_stage, const WebRequestRule::OptionalRequestData& optional_request_data); 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 9253137..9a8f4a1 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 @@ -338,7 +338,7 @@ TEST_F(WebRequestRulesRegistryTest, Precedences) { TestURLRequestContext context; TestURLRequest request(url, NULL, &context); std::list<LinkedPtrEventResponseDelta> deltas = - registry->CreateDeltas(NULL, &request, ON_BEFORE_REQUEST, + registry->CreateDeltas(NULL, &request, false, ON_BEFORE_REQUEST, WebRequestRule::OptionalRequestData()); // The second extension is installed later and will win for this reason @@ -386,7 +386,7 @@ TEST_F(WebRequestRulesRegistryTest, Priorities) { TestURLRequestContext context; TestURLRequest request(url, NULL, &context); std::list<LinkedPtrEventResponseDelta> deltas = - registry->CreateDeltas(NULL, &request, ON_BEFORE_REQUEST, + registry->CreateDeltas(NULL, &request, false, ON_BEFORE_REQUEST, WebRequestRule::OptionalRequestData()); // The redirect by the first extension is ignored due to the ignore rule. 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 10f1d58..7c2f278 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api.cc +++ b/chrome/browser/extensions/api/web_request/web_request_api.cc @@ -455,8 +455,12 @@ ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() { } void ExtensionWebRequestEventRouter::RegisterRulesRegistry( + void* profile, scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry) { - rules_registry_ = rules_registry; + if (rules_registry.get()) + rules_registries_[profile] = rules_registry; + else + rules_registries_.erase(profile); } int ExtensionWebRequestEventRouter::OnBeforeRequest( @@ -466,7 +470,7 @@ int ExtensionWebRequestEventRouter::OnBeforeRequest( const net::CompletionCallback& callback, GURL* new_url) { // We hide events from the system context as well as sensitive requests. - if (!profile || helpers::HideRequest(request)) + if (!profile || WebRequestPermissions::HideRequest(request)) return net::OK; if (IsPageLoad(request)) @@ -525,7 +529,7 @@ int ExtensionWebRequestEventRouter::OnBeforeSendHeaders( const net::CompletionCallback& callback, net::HttpRequestHeaders* headers) { // We hide events from the system context as well as sensitive requests. - if (!profile || helpers::HideRequest(request)) + if (!profile || WebRequestPermissions::HideRequest(request)) return net::OK; bool initialize_blocked_requests = false; @@ -577,7 +581,7 @@ void ExtensionWebRequestEventRouter::OnSendHeaders( net::URLRequest* request, const net::HttpRequestHeaders& headers) { // We hide events from the system context as well as sensitive requests. - if (!profile || helpers::HideRequest(request)) + if (!profile || WebRequestPermissions::HideRequest(request)) return; if (GetAndSetSignaled(request->identifier(), kOnSendHeaders)) @@ -610,7 +614,7 @@ int ExtensionWebRequestEventRouter::OnHeadersReceived( net::HttpResponseHeaders* original_response_headers, scoped_refptr<net::HttpResponseHeaders>* override_response_headers) { // We hide events from the system context as well as sensitive requests. - if (!profile || helpers::HideRequest(request)) + if (!profile || WebRequestPermissions::HideRequest(request)) return net::OK; bool initialize_blocked_requests = false; @@ -675,7 +679,7 @@ ExtensionWebRequestEventRouter::OnAuthRequired( net::AuthCredentials* credentials) { // No profile means that this is for authentication challenges in the // system context. Skip in that case. Also skip sensitive requests. - if (!profile || helpers::HideRequest(request)) + if (!profile || WebRequestPermissions::HideRequest(request)) return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION; int extra_info_spec = 0; @@ -720,7 +724,7 @@ void ExtensionWebRequestEventRouter::OnBeforeRedirect( net::URLRequest* request, const GURL& new_location) { // We hide events from the system context as well as sensitive requests. - if (!profile || helpers::HideRequest(request)) + if (!profile || WebRequestPermissions::HideRequest(request)) return; if (GetAndSetSignaled(request->identifier(), kOnBeforeRedirect)) @@ -765,7 +769,7 @@ void ExtensionWebRequestEventRouter::OnResponseStarted( ExtensionInfoMap* extension_info_map, net::URLRequest* request) { // We hide events from the system context as well as sensitive requests. - if (!profile || helpers::HideRequest(request)) + if (!profile || WebRequestPermissions::HideRequest(request)) return; // OnResponseStarted is even triggered, when the request was cancelled. @@ -808,7 +812,7 @@ void ExtensionWebRequestEventRouter::OnCompleted( ExtensionInfoMap* extension_info_map, net::URLRequest* request) { // We hide events from the system context as well as sensitive requests. - if (!profile || helpers::HideRequest(request)) + if (!profile || WebRequestPermissions::HideRequest(request)) return; request_time_tracker_->LogRequestEndTime(request->identifier(), @@ -857,7 +861,7 @@ void ExtensionWebRequestEventRouter::OnErrorOccurred( net::URLRequest* request, bool started) { // We hide events from the system context as well as sensitive requests. - if (!profile || helpers::HideRequest(request)) + if (!profile || WebRequestPermissions::HideRequest(request)) return; request_time_tracker_->LogRequestEndTime(request->identifier(), @@ -1087,6 +1091,14 @@ void ExtensionWebRequestEventRouter::NotifyPageLoad() { callbacks_for_page_load_.clear(); } +void* ExtensionWebRequestEventRouter::GetCrossProfile(void* profile) const { + CrossProfileMap::const_iterator cross_profile = + cross_profile_map_.find(profile); + if (cross_profile == cross_profile_map_.end()) + return NULL; + return cross_profile->second; +} + void ExtensionWebRequestEventRouter::GetMatchingListenersImpl( void* profile, ExtensionInfoMap* extension_info_map, @@ -1120,36 +1132,26 @@ void ExtensionWebRequestEventRouter::GetMatchingListenersImpl( resource_type) == it->filter.types.end()) continue; - // extension_info_map can be NULL if this is a system-level request. - if (extension_info_map) { - const Extension* extension = - extension_info_map->extensions().GetByID(it->extension_id); - - // Check if this event crosses incognito boundaries when it shouldn't. - if (!extension || - (crosses_incognito && - !extension_info_map->CanCrossIncognito(extension))) - continue; - - bool blocking_listener = - (it->extra_info_spec & - (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0; - - // We do not want to notify extensions about XHR requests that are - // triggered by themselves. This is a workaround to prevent deadlocks - // in case of synchronous XHR requests that block the extension renderer - // and therefore prevent the extension from processing the request - // handler. This is only a problem for blocking listeners. - // http://crbug.com/105656 - bool possibly_synchronous_xhr_from_extension = - is_request_from_extension && resource_type == ResourceType::XHR; - - // Only send webRequest events for URLs the extension has access to. - if (!helpers::CanExtensionAccessURL(extension, url) || - (blocking_listener && possibly_synchronous_xhr_from_extension)) { - continue; - } - } + if (!WebRequestPermissions::CanExtensionAccessURL( + extension_info_map, it->extension_id, url, crosses_incognito, true)) + continue; + + bool blocking_listener = + (it->extra_info_spec & + (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0; + + // We do not want to notify extensions about XHR requests that are + // triggered by themselves. This is a workaround to prevent deadlocks + // in case of synchronous XHR requests that block the extension renderer + // and therefore prevent the extension from processing the request + // handler. This is only a problem for blocking listeners. + // http://crbug.com/105656 + bool possibly_synchronous_xhr_from_extension = + is_request_from_extension && resource_type == ResourceType::XHR; + + // Only send webRequest events for URLs the extension has access to. + if (blocking_listener && possibly_synchronous_xhr_from_extension) + continue; matching_listeners->push_back(&(*it)); *extra_info_spec |= it->extra_info_spec; @@ -1189,13 +1191,12 @@ ExtensionWebRequestEventRouter::GetMatchingListeners( profile, extension_info_map, false, event_name, url, tab_id, window_id, resource_type, is_request_from_extension, extra_info_spec, &matching_listeners); - CrossProfileMap::const_iterator cross_profile = - cross_profile_map_.find(profile); - if (cross_profile != cross_profile_map_.end()) { + void* cross_profile = GetCrossProfile(profile); + if (cross_profile) { GetMatchingListenersImpl( - cross_profile->second, extension_info_map, true, event_name, url, - tab_id, window_id, resource_type, is_request_from_extension, - extra_info_spec, &matching_listeners); + cross_profile, extension_info_map, true, event_name, url, tab_id, + window_id, resource_type, is_request_from_extension, extra_info_spec, + &matching_listeners); } return matching_listeners; @@ -1401,51 +1402,83 @@ bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules( net::URLRequest* request, extensions::RequestStages request_stage, net::HttpResponseHeaders* original_response_headers) { - if (!rules_registry_.get()) - return false; + // Rules of the current |profile| may apply but we need to check also whether + // there are applicable rules from extensions whose background page + // spans from regular to incognito mode. + + // First parameter identifies the registry, the second indicates whether the + // registry belongs to the cross profile. + typedef std::pair<extensions::WebRequestRulesRegistry*, bool> + RelevantRegistry; + typedef std::vector<RelevantRegistry> RelevantRegistries; + RelevantRegistries relevant_registries; + + if (rules_registries_.find(profile) != rules_registries_.end()) { + relevant_registries.push_back( + std::make_pair(rules_registries_[profile].get(), false)); + } + + void* cross_profile = GetCrossProfile(profile); + if (cross_profile && + rules_registries_.find(cross_profile) != rules_registries_.end()) { + relevant_registries.push_back( + std::make_pair(rules_registries_[cross_profile].get(), true)); + } // TODO(mpcomplete): Eventually we'll want to turn this on, but for now, // we won't block startup for declarative webrequest. I want to measure // its effect first. #if defined(BLOCK_STARTUP_ON_DECLARATIVE_RULES) - if (!rules_registry_->IsReady()) { - // The rules registry is still loading. Block this request until it - // finishes. - rules_registry_->AddReadyCallback( - base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady, - AsWeakPtr(), profile, event_name, request->identifier(), - request_stage)); - blocked_requests_[request->identifier()].num_handlers_blocking++; - blocked_requests_[request->identifier()].request = request; - blocked_requests_[request->identifier()].blocking_time = base::Time::Now(); - blocked_requests_[request->identifier()].original_response_headers = - original_response_headers; - blocked_requests_[request->identifier()].extension_info_map = - extension_info_map; - return true; + for (RelevantRegistries::iterator i = relevant_registries.begin(); + i != relevant_registries.end(); ++i) { + extensions::WebRequestRulesRegistry* rules_registry = i->first; + if (!rules_registry->IsReady()) { + // The rules registry is still loading. Block this request until it + // finishes. + rules_registry->AddReadyCallback( + base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady, + AsWeakPtr(), profile, event_name, request->identifier(), + request_stage)); + blocked_requests_[request->identifier()].num_handlers_blocking++; + blocked_requests_[request->identifier()].request = request; + blocked_requests_[request->identifier()].blocking_time = + base::Time::Now(); + blocked_requests_[request->identifier()].original_response_headers = + original_response_headers; + blocked_requests_[request->identifier()].extension_info_map = + extension_info_map; + return true; + } } #endif base::Time start = base::Time::Now(); - extensions::WebRequestRule::OptionalRequestData optional_request_data; - optional_request_data.original_response_headers = - original_response_headers; - helpers::EventResponseDeltas result = - rules_registry_->CreateDeltas(extension_info_map, request, - request_stage, optional_request_data); + bool deltas_created = false; + for (RelevantRegistries::iterator i = relevant_registries.begin(); + i != relevant_registries.end(); ++i) { + extensions::WebRequestRulesRegistry* rules_registry = + i->first; + extensions::WebRequestRule::OptionalRequestData optional_request_data; + optional_request_data.original_response_headers = + original_response_headers; + helpers::EventResponseDeltas result = + rules_registry->CreateDeltas(extension_info_map, request, + i->second, request_stage, optional_request_data); + + if (!result.empty()) { + helpers::EventResponseDeltas& deltas = + blocked_requests_[request->identifier()].response_deltas; + deltas.insert(deltas.end(), result.begin(), result.end()); + deltas_created = true; + } + } base::TimeDelta elapsed_time = start - base::Time::Now(); UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay", elapsed_time); - if (result.empty()) - return false; - - helpers::EventResponseDeltas& deltas = - blocked_requests_[request->identifier()].response_deltas; - deltas.insert(deltas.end(), result.begin(), result.end()); - return true; + return deltas_created; } void ExtensionWebRequestEventRouter::OnRulesRegistryReady( diff --git a/chrome/browser/extensions/api/web_request/web_request_api.h b/chrome/browser/extensions/api/web_request/web_request_api.h index 4142a38..e392599 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api.h +++ b/chrome/browser/extensions/api/web_request/web_request_api.h @@ -16,6 +16,7 @@ #include "base/time.h" #include "chrome/browser/extensions/api/declarative_webrequest/request_stages.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_function.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/url_pattern_set.h" @@ -132,7 +133,10 @@ class ExtensionWebRequestEventRouter static ExtensionWebRequestEventRouter* GetInstance(); + // Registers a rule registry. Pass null for |rules_registry| to unregister + // the rule registry for |profile|. void RegisterRulesRegistry( + void* profile, scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry); // Dispatches the OnBeforeRequest event to any extensions whose filters match @@ -363,6 +367,10 @@ class ExtensionWebRequestEventRouter // Called on a page load to process all registered callbacks. void NotifyPageLoad(); + // Returns the matching cross profile (the regular profile if |profile| is + // OTR and vice versa). + void* GetCrossProfile(void* profile) const; + // A map for each profile that maps an event name to a set of extensions that // are listening to that event. ListenerMap listeners_; @@ -385,7 +393,9 @@ class ExtensionWebRequestEventRouter CallbacksForPageLoad callbacks_for_page_load_; - scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry_; + // Maps each profile (and OTRProfile) to its respective rules registry. + std::map<void*, scoped_refptr<extensions::WebRequestRulesRegistry> > + rules_registries_; DISALLOW_COPY_AND_ASSIGN(ExtensionWebRequestEventRouter); }; diff --git a/chrome/browser/extensions/api/web_request/web_request_api_helpers.cc b/chrome/browser/extensions/api/web_request/web_request_api_helpers.cc index da74647..b7c8831 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api_helpers.cc +++ b/chrome/browser/extensions/api/web_request/web_request_api_helpers.cc @@ -537,64 +537,6 @@ bool MergeOnAuthRequiredResponses( return credentials_set; } -namespace { - -// Returns true if the URL is sensitive and requests to this URL must not be -// modified/canceled by extensions, e.g. because it is targeted to the webstore -// to check for updates, extension blacklisting, etc. -bool IsSensitiveURL(const GURL& url) { - // TODO(battre) Merge this, CanExtensionAccessURL of web_request_api.cc and - // Extension::CanExecuteScriptOnPage into one function. - bool is_webstore_gallery_url = - StartsWithASCII(url.spec(), extension_urls::kGalleryBrowsePrefix, true); - bool sensitive_chrome_url = false; - if (EndsWith(url.host(), "google.com", true)) { - sensitive_chrome_url |= (url.host() == "www.google.com") && - StartsWithASCII(url.path(), "/chrome", true); - sensitive_chrome_url |= (url.host() == "chrome.google.com"); - if (StartsWithASCII(url.host(), "client", true)) { - for (int i = 0; i < 10; ++i) { - sensitive_chrome_url |= - (StringPrintf("client%d.google.com", i) == url.host()); - } - } - } - GURL::Replacements replacements; - replacements.ClearQuery(); - replacements.ClearRef(); - GURL url_without_query = url.ReplaceComponents(replacements); - return is_webstore_gallery_url || sensitive_chrome_url || - extension_urls::IsWebstoreUpdateUrl(url_without_query) || - extension_urls::IsBlacklistUpdateUrl(url); -} - -// Returns true if the scheme is one we want to allow extensions to have access -// to. Extensions still need specific permissions for a given URL, which is -// covered by CanExtensionAccessURL. -bool HasWebRequestScheme(const GURL& url) { - return (url.SchemeIs(chrome::kAboutScheme) || - url.SchemeIs(chrome::kFileScheme) || - url.SchemeIs(chrome::kFileSystemScheme) || - url.SchemeIs(chrome::kFtpScheme) || - url.SchemeIs(chrome::kHttpScheme) || - url.SchemeIs(chrome::kHttpsScheme) || - url.SchemeIs(chrome::kExtensionScheme)); -} - -} // namespace - -bool HideRequest(const net::URLRequest* request) { - const GURL& url = request->url(); - const GURL& first_party_url = request->first_party_for_cookies(); - bool hide = false; - if (first_party_url.is_valid()) { - hide = IsSensitiveURL(first_party_url) || - !HasWebRequestScheme(first_party_url); - } - if (!hide) - hide = IsSensitiveURL(url) || !HasWebRequestScheme(url); - return hide; -} #define ARRAYEND(array) (array + arraysize(array)) diff --git a/chrome/browser/extensions/api/web_request/web_request_api_helpers.h b/chrome/browser/extensions/api/web_request/web_request_api_helpers.h index ea748e4..7487ca7 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api_helpers.h +++ b/chrome/browser/extensions/api/web_request/web_request_api_helpers.h @@ -172,9 +172,6 @@ bool MergeOnAuthRequiredResponses( std::set<std::string>* conflicting_extensions, const net::BoundNetLog* net_log); -// Returns true if the request shall not be reported to extensions. -bool HideRequest(const net::URLRequest* request); - // Returns whether |type| is a ResourceType that is handled by the web request // API. bool IsRelevantResourceType(ResourceType::Type type); diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc index 7797be5..756566a 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc @@ -1487,48 +1487,3 @@ TEST(ExtensionWebRequestHelpersTest, TestMergeOnAuthRequiredResponses) { EXPECT_EQ(3u, capturing_net_log.GetSize()); } -TEST(ExtensionWebRequestHelpersTest, TestHideRequestForURL) { - MessageLoopForIO message_loop; - TestURLRequestContext context; - const char* sensitive_urls[] = { - "http://www.google.com/chrome", - "https://www.google.com/chrome", - "http://www.google.com/chrome/foobar", - "https://www.google.com/chrome/foobar", - "http://chrome.google.com", - "https://chrome.google.com", - "http://client2.google.com", - "https://client2.google.com", - // No http version of webstore. - "https://chrome.google.com/webstore", - "http://clients2.google.com/service/update2/crx", - "https://clients2.google.com/service/update2/crx", - "http://www.gstatic.com/chrome/extensions/blacklist", - "https://www.gstatic.com/chrome/extensions/blacklist", - "notregisteredscheme://www.foobar.com" - }; - const char* non_sensitive_urls[] = { - "http://www.google.com/" - }; - // Check that requests are rejected based on the destination - for (size_t i = 0; i < arraysize(sensitive_urls); ++i) { - GURL sensitive_url(sensitive_urls[i]); - TestURLRequest request(sensitive_url, NULL, &context); - EXPECT_TRUE(helpers::HideRequest(&request)) << sensitive_urls[i]; - } - // Check that requests are accepted if they don't touch sensitive urls. - for (size_t i = 0; i < arraysize(non_sensitive_urls); ++i) { - GURL non_sensitive_url(non_sensitive_urls[i]); - TestURLRequest request(non_sensitive_url, NULL, &context); - EXPECT_FALSE(helpers::HideRequest(&request)) << non_sensitive_urls[i]; - } - // Check that requests are rejected if their first party url is sensitive. - ASSERT_GE(arraysize(non_sensitive_urls), 1u); - GURL non_sensitive_url(non_sensitive_urls[0]); - for (size_t i = 0; i < arraysize(sensitive_urls); ++i) { - TestURLRequest request(non_sensitive_url, NULL, &context); - GURL sensitive_url(sensitive_urls[i]); - request.set_first_party_for_cookies(sensitive_url); - EXPECT_TRUE(helpers::HideRequest(&request)) << sensitive_urls[i]; - } -} 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 0ad09f0..55220b9 100644 --- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc @@ -6,6 +6,7 @@ #include "chrome/browser/extensions/api/web_request/web_request_api.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_test_message_listener.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_tabstrip.h" @@ -62,6 +63,13 @@ class ExtensionWebRequestApiTest : public ExtensionApiTest { host_resolver()->AddRule("*", "127.0.0.1"); ASSERT_TRUE(StartTestServer()); } + + void RunPermissionTest( + const char* extension_directory, + bool load_extension_with_incognito_permission, + bool wait_for_extension_loaded_in_incognito, + const char* expected_content_regular_window, + const char* exptected_content_incognito_window); }; IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestApi) { @@ -132,3 +140,88 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestDeclarative) { ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_declarative.html")) << message_; } + +void ExtensionWebRequestApiTest::RunPermissionTest( + const char* extension_directory, + bool load_extension_with_incognito_permission, + bool wait_for_extension_loaded_in_incognito, + const char* expected_content_regular_window, + const char* exptected_content_incognito_window) { + ResultCatcher catcher; + catcher.RestrictToProfile(browser()->profile()); + ResultCatcher catcher_incognito; + catcher_incognito.RestrictToProfile( + browser()->profile()->GetOffTheRecordProfile()); + + ExtensionTestMessageListener listener("done", true); + ExtensionTestMessageListener listener_incognito("done_incognito", true); + + ASSERT_TRUE(LoadExtensionWithOptions( + test_data_dir_.AppendASCII("webrequest_permissions") + .AppendASCII(extension_directory), + load_extension_with_incognito_permission, + false)); + + // Test that navigation in regular window is properly redirected. + EXPECT_TRUE(listener.WaitUntilSatisfied()); + + // This navigation should be redirected. + ui_test_utils::NavigateToURL( + browser(), + test_server()->GetURL("files/extensions/test_file.html")); + + std::string body; + WebContents* tab = chrome::GetActiveWebContents(browser()); + ASSERT_TRUE(content::ExecuteJavaScriptAndExtractString( + tab->GetRenderViewHost(), L"", + L"window.domAutomationController.send(document.body.textContent)", + &body)); + EXPECT_EQ(expected_content_regular_window, body); + + // Test that navigation in OTR window is properly redirected. + Browser* otr_browser = ui_test_utils::OpenURLOffTheRecord( + browser()->profile(), GURL("about:blank")); + + if (wait_for_extension_loaded_in_incognito) + EXPECT_TRUE(listener_incognito.WaitUntilSatisfied()); + + // This navigation should be redirected if + // load_extension_with_incognito_permission is true. + ui_test_utils::NavigateToURL( + otr_browser, + test_server()->GetURL("files/extensions/test_file.html")); + + body.clear(); + WebContents* otr_tab = chrome::GetActiveWebContents(otr_browser); + ASSERT_TRUE(content::ExecuteJavaScriptAndExtractString( + otr_tab->GetRenderViewHost(), L"", + L"window.domAutomationController.send(document.body.textContent)", + &body)); + EXPECT_EQ(exptected_content_incognito_window, body); +} + +IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, + WebRequestDeclarativePermissionSpanning1) { + // Test spanning with incognito permission. + RunPermissionTest("spanning", true, false, "redirected1", "redirected1"); +} + +IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, + WebRequestDeclarativePermissionSpanning2) { + // Test spanning without incognito permission. + RunPermissionTest("spanning", false, false, "redirected1", ""); +} + + +IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, + WebRequestDeclarativePermissionSplit1) { + // Test split with incognito permission. + RunPermissionTest("split", true, true, "redirected1", "redirected2"); +} + +IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, + WebRequestDeclarativePermissionSplit2) { + // Test split without incognito permission. + RunPermissionTest("split", false, false, "redirected1", ""); +} + diff --git a/chrome/browser/extensions/api/web_request/web_request_permissions.cc b/chrome/browser/extensions/api/web_request/web_request_permissions.cc new file mode 100644 index 0000000..ca84616 --- /dev/null +++ b/chrome/browser/extensions/api/web_request/web_request_permissions.cc @@ -0,0 +1,105 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/web_request/web_request_permissions.h" + +#include "base/string_util.h" +#include "base/stringprintf.h" +#include "chrome/browser/extensions/extension_info_map.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/url_constants.h" +#include "googleurl/src/gurl.h" +#include "net/url_request/url_request.h" + +namespace { + +// Returns true if the URL is sensitive and requests to this URL must not be +// modified/canceled by extensions, e.g. because it is targeted to the webstore +// to check for updates, extension blacklisting, etc. +bool IsSensitiveURL(const GURL& url) { + // TODO(battre) Merge this, CanExtensionAccessURL of web_request_api.cc and + // Extension::CanExecuteScriptOnPage into one function. + bool is_webstore_gallery_url = + StartsWithASCII(url.spec(), extension_urls::kGalleryBrowsePrefix, true); + bool sensitive_chrome_url = false; + if (EndsWith(url.host(), "google.com", true)) { + sensitive_chrome_url |= (url.host() == "www.google.com") && + StartsWithASCII(url.path(), "/chrome", true); + sensitive_chrome_url |= (url.host() == "chrome.google.com"); + if (StartsWithASCII(url.host(), "client", true)) { + for (int i = 0; i < 10; ++i) { + sensitive_chrome_url |= + (StringPrintf("client%d.google.com", i) == url.host()); + } + } + } + GURL::Replacements replacements; + replacements.ClearQuery(); + replacements.ClearRef(); + GURL url_without_query = url.ReplaceComponents(replacements); + return is_webstore_gallery_url || sensitive_chrome_url || + extension_urls::IsWebstoreUpdateUrl(url_without_query) || + extension_urls::IsBlacklistUpdateUrl(url); +} + +// Returns true if the scheme is one we want to allow extensions to have access +// to. Extensions still need specific permissions for a given URL, which is +// covered by CanExtensionAccessURL. +bool HasWebRequestScheme(const GURL& url) { + return (url.SchemeIs(chrome::kAboutScheme) || + url.SchemeIs(chrome::kFileScheme) || + url.SchemeIs(chrome::kFileSystemScheme) || + url.SchemeIs(chrome::kFtpScheme) || + url.SchemeIs(chrome::kHttpScheme) || + url.SchemeIs(chrome::kHttpsScheme) || + url.SchemeIs(chrome::kExtensionScheme)); +} + +} // namespace + +// static +bool WebRequestPermissions::HideRequest(const net::URLRequest* request) { + const GURL& url = request->url(); + const GURL& first_party_url = request->first_party_for_cookies(); + bool hide = false; + if (first_party_url.is_valid()) { + hide = IsSensitiveURL(first_party_url) || + !HasWebRequestScheme(first_party_url); + } + if (!hide) + hide = IsSensitiveURL(url) || !HasWebRequestScheme(url); + return hide; +} + +// static +bool WebRequestPermissions::CanExtensionAccessURL( + const ExtensionInfoMap* extension_info_map, + const std::string& extension_id, + const GURL& url, + bool crosses_incognito, + bool enforce_host_permissions) { + // extension_info_map can be NULL in testing. + if (!extension_info_map) + return true; + + const extensions::Extension* extension = + extension_info_map->extensions().GetByID(extension_id); + if (!extension) + return false; + + // Check if this event crosses incognito boundaries when it shouldn't. + 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; + } + + 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 new file mode 100644 index 0000000..d7923b9 --- /dev/null +++ b/chrome/browser/extensions/api/web_request/web_request_permissions.h @@ -0,0 +1,36 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_WEB_REQUEST_WEB_REQUEST_PERMISSIONS_H_ +#define CHROME_BROWSER_EXTENSIONS_API_WEB_REQUEST_WEB_REQUEST_PERMISSIONS_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" + +class ExtensionInfoMap; +class GURL; + +namespace net { +class URLRequest; +} + +// This class is used to test whether extensions may modify web requests. +class WebRequestPermissions { + public: + // Returns true if the request shall not be reported to extensions. + static bool HideRequest(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); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(WebRequestPermissions); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_API_WEB_REQUEST_WEB_REQUEST_PERMISSIONS_H_ 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 new file mode 100644 index 0000000..7a83e58 --- /dev/null +++ b/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc @@ -0,0 +1,59 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/web_request/web_request_permissions.h" + +#include "base/message_loop.h" +#include "chrome/test/base/testing_profile.h" +#include "net/url_request/url_request_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(ExtensionWebRequestHelpersTest, TestHideRequestForURL) { + MessageLoopForIO message_loop; + TestURLRequestContext context; + const char* sensitive_urls[] = { + "http://www.google.com/chrome", + "https://www.google.com/chrome", + "http://www.google.com/chrome/foobar", + "https://www.google.com/chrome/foobar", + "http://chrome.google.com", + "https://chrome.google.com", + "http://client2.google.com", + "https://client2.google.com", + // No http version of webstore. + "https://chrome.google.com/webstore", + "http://clients2.google.com/service/update2/crx", + "https://clients2.google.com/service/update2/crx", + "http://www.gstatic.com/chrome/extensions/blacklist", + "https://www.gstatic.com/chrome/extensions/blacklist", + "notregisteredscheme://www.foobar.com" + }; + const char* non_sensitive_urls[] = { + "http://www.google.com/" + }; + // Check that requests are rejected based on the destination + for (size_t i = 0; i < arraysize(sensitive_urls); ++i) { + GURL sensitive_url(sensitive_urls[i]); + TestURLRequest request(sensitive_url, NULL, &context); + EXPECT_TRUE(WebRequestPermissions::HideRequest(&request)) + << sensitive_urls[i]; + } + // Check that requests are accepted if they don't touch sensitive urls. + for (size_t i = 0; i < arraysize(non_sensitive_urls); ++i) { + GURL non_sensitive_url(non_sensitive_urls[i]); + TestURLRequest request(non_sensitive_url, NULL, &context); + EXPECT_FALSE(WebRequestPermissions::HideRequest(&request)) + << non_sensitive_urls[i]; + } + // Check that requests are rejected if their first party url is sensitive. + ASSERT_GE(arraysize(non_sensitive_urls), 1u); + GURL non_sensitive_url(non_sensitive_urls[0]); + for (size_t i = 0; i < arraysize(sensitive_urls); ++i) { + TestURLRequest request(non_sensitive_url, NULL, &context); + GURL sensitive_url(sensitive_urls[i]); + request.set_first_party_for_cookies(sensitive_url); + EXPECT_TRUE(WebRequestPermissions::HideRequest(&request)) + << sensitive_urls[i]; + } +} diff --git a/chrome/browser/extensions/extension_info_map.cc b/chrome/browser/extensions/extension_info_map.cc index 3f9bb73..c9b072d 100644 --- a/chrome/browser/extensions/extension_info_map.cc +++ b/chrome/browser/extensions/extension_info_map.cc @@ -93,7 +93,7 @@ bool ExtensionInfoMap::IsIncognitoEnabled( return false; } -bool ExtensionInfoMap::CanCrossIncognito(const Extension* extension) { +bool ExtensionInfoMap::CanCrossIncognito(const Extension* extension) const { // This is duplicated from ExtensionService :(. return IsIncognitoEnabled(extension->id()) && !extension->incognito_split_mode(); diff --git a/chrome/browser/extensions/extension_info_map.h b/chrome/browser/extensions/extension_info_map.h index 42798bf3..5fdb154 100644 --- a/chrome/browser/extensions/extension_info_map.h +++ b/chrome/browser/extensions/extension_info_map.h @@ -52,7 +52,7 @@ class ExtensionInfoMap : public base::RefCountedThreadSafe<ExtensionInfoMap> { // Returns true if the given extension can see events and data from another // sub-profile (incognito to original profile, or vice versa). - bool CanCrossIncognito(const extensions::Extension* extension); + bool CanCrossIncognito(const extensions::Extension* extension) const; // Adds an entry to process_map_. void RegisterExtensionProcess(const std::string& extension_id, diff --git a/chrome/browser/extensions/extension_system.cc b/chrome/browser/extensions/extension_system.cc index e5ca663..b451ab0 100644 --- a/chrome/browser/extensions/extension_system.cc +++ b/chrome/browser/extensions/extension_system.cc @@ -73,8 +73,6 @@ ExtensionSystemImpl::Shared::Shared(Profile* profile) } ExtensionSystemImpl::Shared::~Shared() { - if (rules_registry_service_.get()) - rules_registry_service_->Shutdown(); } void ExtensionSystemImpl::Shared::InitPrefs() { @@ -134,9 +132,6 @@ void ExtensionSystemImpl::Shared::Init(bool extensions_enabled) { // These services must be registered before the ExtensionService tries to // load any extensions. { - rules_registry_service_.reset(new RulesRegistryService(profile_)); - rules_registry_service_->RegisterDefaultRulesRegistries(); - management_policy_.reset(new ManagementPolicy); RegisterManagementPolicyProviders(); } @@ -236,10 +231,6 @@ EventRouter* ExtensionSystemImpl::Shared::event_router() { return extension_event_router_.get(); } -RulesRegistryService* ExtensionSystemImpl::Shared::rules_registry_service() { - return rules_registry_service_.get(); -} - // // ExtensionSystemImpl // @@ -257,13 +248,15 @@ ExtensionSystemImpl::ExtensionSystemImpl(Profile* profile) } ExtensionSystemImpl::~ExtensionSystemImpl() { + if (rules_registry_service_.get()) + rules_registry_service_->Shutdown(); } void ExtensionSystemImpl::Shutdown() { extension_process_manager_.reset(); } -void ExtensionSystemImpl::Init(bool extensions_enabled) { +void ExtensionSystemImpl::InitForRegularProfile(bool extensions_enabled) { DCHECK(!profile_->IsOffTheRecord()); if (user_script_master() || extension_service()) return; // Already initialized. @@ -285,9 +278,23 @@ void ExtensionSystemImpl::Init(bool extensions_enabled) { usb_device_resource_manager_.reset( new ApiResourceManager<UsbDeviceResource>(BrowserThread::IO)); + rules_registry_service_.reset(new RulesRegistryService(profile_)); + rules_registry_service_->RegisterDefaultRulesRegistries(); + shared_->Init(extensions_enabled); } +void ExtensionSystemImpl::InitForOTRProfile() { + // Only initialize the RulesRegistryService of the OTR ExtensionSystem if the + // regular ExtensionSystem has been initialized properly, as we depend on it. + // Some ChromeOS browser tests don't initialize the regular ExtensionSystem + // in login-tests. + if (extension_service()) { + rules_registry_service_.reset(new RulesRegistryService(profile_)); + rules_registry_service_->RegisterDefaultRulesRegistries(); + } +} + ExtensionService* ExtensionSystemImpl::extension_service() { return shared_->extension_service(); } @@ -335,7 +342,7 @@ EventRouter* ExtensionSystemImpl::event_router() { } RulesRegistryService* ExtensionSystemImpl::rules_registry_service() { - return shared_->rules_registry_service(); + return rules_registry_service_.get(); } ApiResourceManager<SerialConnection>* @@ -343,7 +350,7 @@ ExtensionSystemImpl::serial_connection_manager() { return serial_connection_manager_.get(); } -ApiResourceManager<Socket>*ExtensionSystemImpl::socket_manager() { +ApiResourceManager<Socket>* ExtensionSystemImpl::socket_manager() { return socket_manager_.get(); } diff --git a/chrome/browser/extensions/extension_system.h b/chrome/browser/extensions/extension_system.h index bf225c0..9cf70bd 100644 --- a/chrome/browser/extensions/extension_system.h +++ b/chrome/browser/extensions/extension_system.h @@ -58,7 +58,9 @@ class ExtensionSystem : public ProfileKeyedService { // Initializes extensions machinery. // Component extensions are always enabled, external and user extensions // are controlled by |extensions_enabled|. - virtual void Init(bool extensions_enabled) = 0; + virtual void InitForRegularProfile(bool extensions_enabled) = 0; + + virtual void InitForOTRProfile() = 0; // The ExtensionService is created at startup. virtual ExtensionService* extension_service() = 0; @@ -139,7 +141,8 @@ class ExtensionSystemImpl : public ExtensionSystem { // ProfileKeyedService implementation. virtual void Shutdown() OVERRIDE; - virtual void Init(bool extensions_enabled) OVERRIDE; + virtual void InitForRegularProfile(bool extensions_enabled) OVERRIDE; + virtual void InitForOTRProfile() OVERRIDE; virtual ExtensionService* extension_service() OVERRIDE; // shared virtual ManagementPolicy* management_policy() OVERRIDE; // shared @@ -193,7 +196,6 @@ class ExtensionSystemImpl : public ExtensionSystem { LazyBackgroundTaskQueue* lazy_background_task_queue(); MessageService* message_service(); EventRouter* event_router(); - RulesRegistryService* rules_registry_service(); private: Profile* profile_; @@ -213,7 +215,6 @@ class ExtensionSystemImpl : public ExtensionSystem { scoped_ptr<MessageService> message_service_; scoped_ptr<EventRouter> extension_event_router_; scoped_ptr<ExtensionNavigationObserver> extension_navigation_observer_; - scoped_ptr<RulesRegistryService> rules_registry_service_; }; Profile* profile_; @@ -232,6 +233,7 @@ class ExtensionSystemImpl : public ExtensionSystem { scoped_ptr<ApiResourceManager<Socket> > socket_manager_; scoped_ptr<ApiResourceManager< UsbDeviceResource> > usb_device_resource_manager_; + scoped_ptr<RulesRegistryService> rules_registry_service_; DISALLOW_COPY_AND_ASSIGN(ExtensionSystemImpl); }; diff --git a/chrome/browser/extensions/test_extension_system.h b/chrome/browser/extensions/test_extension_system.h index d27f3b0..0f0daf5 100644 --- a/chrome/browser/extensions/test_extension_system.h +++ b/chrome/browser/extensions/test_extension_system.h @@ -41,7 +41,8 @@ class TestExtensionSystem : public ExtensionSystem { // Creates an AlarmManager. Will be NULL otherwise. void CreateAlarmManager(base::Time (*now)()); - virtual void Init(bool extensions_enabled) OVERRIDE {} + virtual void InitForRegularProfile(bool extensions_enabled) OVERRIDE {} + virtual void InitForOTRProfile() OVERRIDE {} void SetExtensionService(ExtensionService* service); virtual ExtensionService* extension_service() OVERRIDE; virtual ManagementPolicy* management_policy() OVERRIDE; diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc index ddf21ed..94f3bab 100644 --- a/chrome/browser/profiles/off_the_record_profile_impl.cc +++ b/chrome/browser/profiles/off_the_record_profile_impl.cc @@ -89,6 +89,8 @@ OffTheRecordProfileImpl::OffTheRecordProfileImpl(Profile* real_profile) void OffTheRecordProfileImpl::Init() { ProfileDependencyManager::GetInstance()->CreateProfileServices(this, false); + extensions::ExtensionSystem::Get(this)->InitForOTRProfile(); + DCHECK_NE(IncognitoModePrefs::DISABLED, IncognitoModePrefs::GetAvailability(profile_->GetPrefs())); diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index f8a375b..57c5c0a 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc @@ -688,7 +688,8 @@ void ProfileManager::DoFinalInit(Profile* profile, bool go_off_the_record) { void ProfileManager::DoFinalInitForServices(Profile* profile, bool go_off_the_record) { const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - extensions::ExtensionSystem::Get(profile)->Init(!go_off_the_record); + extensions::ExtensionSystem::Get(profile)->InitForRegularProfile( + !go_off_the_record); // During tests, when |profile| is an instance of TestingProfile, // ExtensionSystem might not create an ExtensionService. if (extensions::ExtensionSystem::Get(profile)->extension_service()) { diff --git a/chrome/browser/sync/glue/extension_data_type_controller.cc b/chrome/browser/sync/glue/extension_data_type_controller.cc index 599e741..e6c8674 100644 --- a/chrome/browser/sync/glue/extension_data_type_controller.cc +++ b/chrome/browser/sync/glue/extension_data_type_controller.cc @@ -26,7 +26,7 @@ ExtensionDataTypeController::ExtensionDataTypeController( ExtensionDataTypeController::~ExtensionDataTypeController() {} bool ExtensionDataTypeController::StartModels() { - extensions::ExtensionSystem::Get(profile_)->Init(true); + extensions::ExtensionSystem::Get(profile_)->InitForRegularProfile(true); return true; } diff --git a/chrome/browser/sync/glue/extension_setting_data_type_controller.cc b/chrome/browser/sync/glue/extension_setting_data_type_controller.cc index 2df76b9..b02afcf 100644 --- a/chrome/browser/sync/glue/extension_setting_data_type_controller.cc +++ b/chrome/browser/sync/glue/extension_setting_data_type_controller.cc @@ -53,7 +53,7 @@ bool ExtensionSettingDataTypeController::PostTaskOnBackendThread( bool ExtensionSettingDataTypeController::StartModels() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - extensions::ExtensionSystem::Get(profile_)->Init(true); + extensions::ExtensionSystem::Get(profile_)->InitForRegularProfile(true); return true; } diff --git a/chrome/browser/sync/glue/theme_data_type_controller.cc b/chrome/browser/sync/glue/theme_data_type_controller.cc index 7133805..244f9d0 100644 --- a/chrome/browser/sync/glue/theme_data_type_controller.cc +++ b/chrome/browser/sync/glue/theme_data_type_controller.cc @@ -27,7 +27,7 @@ syncer::ModelType ThemeDataTypeController::type() const { ThemeDataTypeController::~ThemeDataTypeController() {} bool ThemeDataTypeController::StartModels() { - extensions::ExtensionSystem::Get(profile_)->Init(true); + extensions::ExtensionSystem::Get(profile_)->InitForRegularProfile(true); return true; } diff --git a/chrome/browser/sync/test/integration/sync_app_helper.cc b/chrome/browser/sync/test/integration/sync_app_helper.cc index 51a2083..256c1ac 100644 --- a/chrome/browser/sync/test/integration/sync_app_helper.cc +++ b/chrome/browser/sync/test/integration/sync_app_helper.cc @@ -93,9 +93,11 @@ void SyncAppHelper::SetupIfNecessary(SyncTest* test) { return; for (int i = 0; i < test->num_clients(); ++i) { - extensions::ExtensionSystem::Get(test->GetProfile(i))->Init(true); + extensions::ExtensionSystem::Get( + test->GetProfile(i))->InitForRegularProfile(true); } - extensions::ExtensionSystem::Get(test->verifier())->Init(true); + extensions::ExtensionSystem::Get( + test->verifier())->InitForRegularProfile(true); setup_completed_ = true; } diff --git a/chrome/browser/sync/test/integration/sync_extension_helper.cc b/chrome/browser/sync/test/integration/sync_extension_helper.cc index 0621664..b4c0f1d 100644 --- a/chrome/browser/sync/test/integration/sync_extension_helper.cc +++ b/chrome/browser/sync/test/integration/sync_extension_helper.cc @@ -243,7 +243,7 @@ bool SyncExtensionHelper::ExtensionStatesMatch( } void SyncExtensionHelper::SetupProfile(Profile* profile) { - extensions::ExtensionSystem::Get(profile)->Init(true); + extensions::ExtensionSystem::Get(profile)->InitForRegularProfile(true); profile_extensions_.insert(make_pair(profile, ExtensionNameMap())); } diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index dbabd94..3e83db9 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -226,6 +226,8 @@ 'browser/extensions/api/web_request/web_request_api_constants.h', 'browser/extensions/api/web_request/web_request_api_helpers.cc', 'browser/extensions/api/web_request/web_request_api_helpers.h', + 'browser/extensions/api/web_request/web_request_permissions.cc', + 'browser/extensions/api/web_request/web_request_permissions.h', 'browser/extensions/api/web_request/web_request_time_tracker.cc', 'browser/extensions/api/web_request/web_request_time_tracker.h', 'browser/extensions/app_notification.cc', @@ -625,6 +627,7 @@ ['include', '^browser/extensions/api/web_request/web_request_api.cc'], ['include', '^browser/extensions/api/web_request/web_request_api_constants.cc'], ['include', '^browser/extensions/api/web_request/web_request_api_helpers.cc'], + ['include', '^browser/extensions/api/web_request/web_request_permissions.cc'], ['include', '^browser/extensions/api/web_request/web_request_time_tracker.cc'], ], }], diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 144632c..bae35e2 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1221,6 +1221,7 @@ 'browser/extensions/api/socket/tcp_socket_unittest.cc', 'browser/extensions/api/web_navigation/frame_navigation_state_unittest.cc', 'browser/extensions/api/web_request/web_request_api_unittest.cc', + 'browser/extensions/api/web_request/web_request_permissions_unittest.cc', 'browser/extensions/api/web_request/web_request_time_tracker_unittest.cc', 'browser/extensions/app_notification_manager_sync_unittest.cc', 'browser/extensions/app_notification_manager_unittest.cc', diff --git a/chrome/test/data/extensions/api_test/webrequest_permissions/spanning/background.js b/chrome/test/data/extensions/api_test/webrequest_permissions/spanning/background.js new file mode 100644 index 0000000..66a1f8e --- /dev/null +++ b/chrome/test/data/extensions/api_test/webrequest_permissions/spanning/background.js @@ -0,0 +1,19 @@ +// 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. + +chrome.declarativeWebRequest.onRequest.removeRules(); +var rule = { + conditions: [ + new chrome.declarativeWebRequest.RequestMatcher( + {url: {pathContains: '.html'}}), + ], + actions: [ + new chrome.declarativeWebRequest.RedirectRequest( + {'redirectUrl': 'data:text/plain,redirected1'}) + ], +} +function notifyDone() { + chrome.test.sendMessage("done"); +} +chrome.declarativeWebRequest.onRequest.addRules([rule], notifyDone); diff --git a/chrome/test/data/extensions/api_test/webrequest_permissions/spanning/manifest.json b/chrome/test/data/extensions/api_test/webrequest_permissions/spanning/manifest.json new file mode 100644 index 0000000..f638a48 --- /dev/null +++ b/chrome/test/data/extensions/api_test/webrequest_permissions/spanning/manifest.json @@ -0,0 +1,11 @@ +{ + "name": "webRequest", + "version": "1.0", + "manifest_version": 2, + "description": "Tests the permissions of declarative webRequest API.", + "permissions": ["declarativeWebRequest", "<all_urls>"], + "incognito": "spanning", + "background": { + "scripts": ["background.js"] + } +} diff --git a/chrome/test/data/extensions/api_test/webrequest_permissions/split/background.js b/chrome/test/data/extensions/api_test/webrequest_permissions/split/background.js new file mode 100644 index 0000000..b1df796 --- /dev/null +++ b/chrome/test/data/extensions/api_test/webrequest_permissions/split/background.js @@ -0,0 +1,30 @@ +// 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. + +chrome.declarativeWebRequest.onRequest.removeRules(); +var rule = { + conditions: [ + new chrome.declarativeWebRequest.RequestMatcher( + {url: {pathContains: '.html'}}), + ], + actions: [], +} +if (chrome.extension.inIncognitoContext) { + rule.actions = [ + new chrome.declarativeWebRequest.RedirectRequest( + {'redirectUrl': 'data:text/plain,redirected2'}) + ]; +} else { + rule.actions = [ + new chrome.declarativeWebRequest.RedirectRequest( + {'redirectUrl': 'data:text/plain,redirected1'}) + ]; +} +function notifyDone() { + if (chrome.extension.inIncognitoContext) + chrome.test.sendMessage("done_incognito"); + else + chrome.test.sendMessage("done"); +} +chrome.declarativeWebRequest.onRequest.addRules([rule], notifyDone); diff --git a/chrome/test/data/extensions/api_test/webrequest_permissions/split/manifest.json b/chrome/test/data/extensions/api_test/webrequest_permissions/split/manifest.json new file mode 100644 index 0000000..f1d3f9e --- /dev/null +++ b/chrome/test/data/extensions/api_test/webrequest_permissions/split/manifest.json @@ -0,0 +1,11 @@ +{ + "name": "webRequest", + "version": "1.0", + "manifest_version": 2, + "description": "Tests the permissions of declarative webRequest API.", + "permissions": ["declarativeWebRequest", "<all_urls>"], + "incognito": "split", + "background": { + "scripts": ["background.js"] + } +} |