diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 6 | ||||
-rw-r--r-- | chrome/browser/extensions/active_script_controller.cc | 41 | ||||
-rw-r--r-- | chrome/browser/extensions/active_script_controller.h | 7 | ||||
-rw-r--r-- | chrome/browser/extensions/active_script_controller_unittest.cc | 100 | ||||
-rw-r--r-- | chrome/browser/extensions/active_tab_permission_granter.cc | 8 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_context_menu_model.cc | 28 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_context_menu_model.h | 10 | ||||
-rw-r--r-- | chrome/browser/extensions/permissions_updater.cc | 46 | ||||
-rw-r--r-- | extensions/common/url_pattern.cc | 6 | ||||
-rw-r--r-- | extensions/common/url_pattern.h | 4 | ||||
-rw-r--r-- | extensions/common/url_pattern_set.cc | 12 | ||||
-rw-r--r-- | extensions/common/url_pattern_set.h | 3 | ||||
-rw-r--r-- | extensions/common/url_pattern_set_unittest.cc | 18 | ||||
-rw-r--r-- | extensions/common/url_pattern_unittest.cc | 31 |
14 files changed, 289 insertions, 31 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 2a4b8ee..8368303 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4844,6 +4844,9 @@ Make sure you do not expose any sensitive information. Show button </message> <if expr="not use_titlecase"> + <message name="IDS_EXTENSIONS_ALWAYS_RUN" desc="The text for the 'always run' item in context menus (sentence case)."> + Always run + </message> <message name="IDS_EXTENSIONS_OPTIONS_MENU_ITEM" desc="The text for the options menu item in context menus (sentence case)."> Options </message> @@ -4861,6 +4864,9 @@ Make sure you do not expose any sensitive information. </message> </if> <if expr="use_titlecase"> + <message name="IDS_EXTENSIONS_ALWAYS_RUN" desc="The text for the 'always run' item in context menus (title case)."> + Always Run + </message> <message name="IDS_EXTENSIONS_OPTIONS_MENU_ITEM" desc="The text for the options menu item in context menus (title case)."> Options </message> diff --git a/chrome/browser/extensions/active_script_controller.cc b/chrome/browser/extensions/active_script_controller.cc index 60dce03..64de769 100644 --- a/chrome/browser/extensions/active_script_controller.cc +++ b/chrome/browser/extensions/active_script_controller.cc @@ -13,6 +13,8 @@ #include "chrome/browser/extensions/extension_action.h" #include "chrome/browser/extensions/extension_action_manager.h" #include "chrome/browser/extensions/extension_util.h" +#include "chrome/browser/extensions/location_bar_controller.h" +#include "chrome/browser/extensions/permissions_updater.h" #include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/session_id.h" @@ -27,6 +29,7 @@ #include "extensions/common/extension_set.h" #include "extensions/common/feature_switch.h" #include "extensions/common/manifest.h" +#include "extensions/common/permissions/permission_set.h" #include "extensions/common/permissions/permissions_data.h" #include "ipc/ipc_message_macros.h" @@ -101,6 +104,44 @@ void ActiveScriptController::OnAdInjectionDetected( ad_injectors.size() - num_preventable_ad_injectors); } +void ActiveScriptController::AlwaysRunOnVisibleOrigin( + const Extension* extension) { + const GURL& url = web_contents()->GetVisibleURL(); + URLPatternSet new_explicit_hosts; + URLPatternSet new_scriptable_hosts; + + scoped_refptr<const PermissionSet> withheld_permissions = + extension->permissions_data()->withheld_permissions(); + if (withheld_permissions->explicit_hosts().MatchesURL(url)) { + new_explicit_hosts.AddOrigin(UserScript::ValidUserScriptSchemes(), + url.GetOrigin()); + } + if (withheld_permissions->scriptable_hosts().MatchesURL(url)) { + new_scriptable_hosts.AddOrigin(UserScript::ValidUserScriptSchemes(), + url.GetOrigin()); + } + + scoped_refptr<PermissionSet> new_permissions = + new PermissionSet(APIPermissionSet(), + ManifestPermissionSet(), + new_explicit_hosts, + new_scriptable_hosts); + + // Update permissions for the session. This adds |new_permissions| to active + // permissions and granted permissions. + // TODO(devlin): Make sure that the permission is removed from + // withheld_permissions if appropriate. + PermissionsUpdater(web_contents()->GetBrowserContext()) + .AddPermissions(extension, new_permissions.get()); + + // Allow current tab to run injection. + OnClicked(extension); +} + +bool ActiveScriptController::HasActiveScriptAction(const Extension* extension) { + return enabled_ && active_script_actions_.count(extension->id()) > 0; +} + ExtensionAction* ActiveScriptController::GetActionForExtension( const Extension* extension) { if (!enabled_ || pending_requests_.count(extension->id()) == 0) diff --git a/chrome/browser/extensions/active_script_controller.h b/chrome/browser/extensions/active_script_controller.h index d55ec4a..6e4a9ed 100644 --- a/chrome/browser/extensions/active_script_controller.h +++ b/chrome/browser/extensions/active_script_controller.h @@ -54,6 +54,13 @@ class ActiveScriptController : public LocationBarController::ActionProvider, // Notifies the ActiveScriptController of detected ad injection. void OnAdInjectionDetected(const std::set<std::string>& ad_injectors); + // Adds the visible origin to |extension|'s active permissions, granting + // |extension| permission to always run script injections on the origin. + void AlwaysRunOnVisibleOrigin(const Extension* extension); + + // Returns true if there is an active script injection action for |extension|. + bool HasActiveScriptAction(const Extension* extension); + // LocationBarControllerProvider implementation. virtual ExtensionAction* GetActionForExtension( const Extension* extension) OVERRIDE; diff --git a/chrome/browser/extensions/active_script_controller_unittest.cc b/chrome/browser/extensions/active_script_controller_unittest.cc index 01fe26b..f40286b 100644 --- a/chrome/browser/extensions/active_script_controller_unittest.cc +++ b/chrome/browser/extensions/active_script_controller_unittest.cc @@ -45,6 +45,9 @@ class ActiveScriptControllerUnitTest : public ChromeRenderViewHostTestHarness { // Creates an extension with all hosts permission and adds it to the registry. const Extension* AddExtension(); + // Reloads |extension_| by removing it from the registry and recreating it. + const Extension* ReloadExtension(); + // Returns true if the |extension| requires user consent before injecting // a script. bool RequiresUserConsent(const Extension* extension) const; @@ -78,6 +81,8 @@ class ActiveScriptControllerUnitTest : public ChromeRenderViewHostTestHarness { // The map of observed executions, keyed by extension id. std::map<std::string, int> extension_executions_; + + scoped_refptr<const Extension> extension_; }; ActiveScriptControllerUnitTest::ActiveScriptControllerUnitTest() @@ -91,23 +96,27 @@ ActiveScriptControllerUnitTest::~ActiveScriptControllerUnitTest() { const Extension* ActiveScriptControllerUnitTest::AddExtension() { const std::string kId = id_util::GenerateId("all_hosts_extension"); - scoped_refptr<const Extension> extension = - ExtensionBuilder() - .SetManifest( - DictionaryBuilder() - .Set("name", "all_hosts_extension") - .Set("description", "an extension") - .Set("manifest_version", 2) - .Set("version", "1.0.0") - .Set("permissions", - ListBuilder().Append(kAllHostsPermission))) - .SetLocation(Manifest::INTERNAL) - .SetID(kId) - .Build(); - - ExtensionRegistry::Get(profile())->AddEnabled(extension); - PermissionsUpdater(profile()).InitializePermissions(extension); - return extension; + extension_ = ExtensionBuilder() + .SetManifest( + DictionaryBuilder() + .Set("name", "all_hosts_extension") + .Set("description", "an extension") + .Set("manifest_version", 2) + .Set("version", "1.0.0") + .Set("permissions", + ListBuilder().Append(kAllHostsPermission))) + .SetLocation(Manifest::INTERNAL) + .SetID(kId) + .Build(); + + ExtensionRegistry::Get(profile())->AddEnabled(extension_); + PermissionsUpdater(profile()).InitializePermissions(extension_); + return extension_; +} + +const Extension* ActiveScriptControllerUnitTest::ReloadExtension() { + ExtensionRegistry::Get(profile())->RemoveEnabled(extension_->id()); + return AddExtension(); } bool ActiveScriptControllerUnitTest::RequiresUserConsent( @@ -322,4 +331,61 @@ TEST_F(ActiveScriptControllerUnitTest, ActiveScriptsCanHaveAllUrlsPref) { EXPECT_TRUE(RequiresUserConsent(extension)); } +TEST_F(ActiveScriptControllerUnitTest, TestAlwaysRun) { + const Extension* extension = AddExtension(); + ASSERT_TRUE(extension); + + NavigateAndCommit(GURL("https://www.google.com/?gws_rd=ssl")); + + // Ensure that there aren't any executions pending. + ASSERT_EQ(0u, GetExecutionCountForExtension(extension->id())); + ASSERT_FALSE(controller()->GetActionForExtension(extension)); + + // Since the extension requests all_hosts, we should require user consent. + EXPECT_TRUE(RequiresUserConsent(extension)); + + // Request an injection. There should be an action visible, but no executions. + RequestInjection(extension); + EXPECT_TRUE(controller()->GetActionForExtension(extension)); + EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id())); + + // Allow the extension to always run on this origin. + controller()->AlwaysRunOnVisibleOrigin(extension); + + // The extension should execute, and the action should go away. + EXPECT_EQ(1u, GetExecutionCountForExtension(extension->id())); + EXPECT_FALSE(controller()->GetActionForExtension(extension)); + + // Since we already executed on the given page, we shouldn't need permission + // for a second time. + EXPECT_FALSE(RequiresUserConsent(extension)); + + // Navigating to another site that hasn't been granted a persisted permission + // should necessitate user consent. + NavigateAndCommit(GURL("https://www.foo.com/bar")); + EXPECT_TRUE(RequiresUserConsent(extension)); + + // We shouldn't need user permission upon returning to the original origin. + NavigateAndCommit(GURL("https://www.google.com/foo/bar")); + EXPECT_FALSE(RequiresUserConsent(extension)); + + // Reloading the extension should not clear any granted host permissions. + extension = ReloadExtension(); + Reload(); + EXPECT_FALSE(RequiresUserConsent(extension)); + + // Different host... + NavigateAndCommit(GURL("https://www.foo.com/bar")); + EXPECT_TRUE(RequiresUserConsent(extension)); + // Different scheme... + NavigateAndCommit(GURL("http://www.google.com/foo/bar")); + EXPECT_TRUE(RequiresUserConsent(extension)); + // Different subdomain... + NavigateAndCommit(GURL("https://en.google.com/foo/bar")); + EXPECT_TRUE(RequiresUserConsent(extension)); + // Only the "always run" origin should be allowed to run without user consent. + NavigateAndCommit(GURL("https://www.google.com/foo/bar")); + EXPECT_FALSE(RequiresUserConsent(extension)); +} + } // namespace extensions diff --git a/chrome/browser/extensions/active_tab_permission_granter.cc b/chrome/browser/extensions/active_tab_permission_granter.cc index 608eaa1..2f80ad7 100644 --- a/chrome/browser/extensions/active_tab_permission_granter.cc +++ b/chrome/browser/extensions/active_tab_permission_granter.cc @@ -47,12 +47,8 @@ void ActiveTabPermissionGranter::GrantIfRequested(const Extension* extension) { // permission in the manifest. if (permissions_data->HasAPIPermission(APIPermission::kActiveTab) || permissions_data->HasWithheldImpliedAllHosts()) { - URLPattern pattern(UserScript::ValidUserScriptSchemes()); - // Pattern parsing could fail if this is an unsupported URL e.g. chrome://. - if (pattern.Parse(web_contents()->GetURL().spec()) == - URLPattern::PARSE_SUCCESS) { - new_hosts.AddPattern(pattern); - } + new_hosts.AddOrigin(UserScript::ValidUserScriptSchemes(), + web_contents()->GetVisibleURL().GetOrigin()); new_apis.insert(APIPermission::kTab); } diff --git a/chrome/browser/extensions/extension_context_menu_model.cc b/chrome/browser/extensions/extension_context_menu_model.cc index 2edc1ac..9c1e125 100644 --- a/chrome/browser/extensions/extension_context_menu_model.cc +++ b/chrome/browser/extensions/extension_context_menu_model.cc @@ -7,6 +7,7 @@ #include "base/prefs/pref_service.h" #include "base/strings/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" +#include "chrome/browser/extensions/active_script_controller.h" #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" #include "chrome/browser/extensions/context_menu_matcher.h" #include "chrome/browser/extensions/extension_action.h" @@ -120,8 +121,7 @@ bool ExtensionContextMenuModel::IsCommandIdEnabled(int command_id) const { // homepage, we just disable this menu item. return extensions::ManifestURL::GetHomepageURL(extension).is_valid(); } else if (command_id == INSPECT_POPUP) { - WebContents* web_contents = - browser_->tab_strip_model()->GetActiveWebContents(); + WebContents* web_contents = GetActiveWebContents(); if (!web_contents) return false; @@ -164,6 +164,14 @@ void ExtensionContextMenuModel::ExecuteCommand(int command_id, browser_->OpenURL(params); break; } + case ALWAYS_RUN: { + WebContents* web_contents = GetActiveWebContents(); + if (web_contents) { + extensions::ActiveScriptController::GetForWebContents(web_contents) + ->AlwaysRunOnVisibleOrigin(extension); + } + break; + } case CONFIGURE: DCHECK(!extensions::ManifestURL::GetOptionsPage(extension).is_empty()); extensions::ExtensionTabUtil::OpenOptionsPage(extension, browser_); @@ -237,6 +245,18 @@ void ExtensionContextMenuModel::InitMenu(const Extension* extension) { AddItem(NAME, base::UTF8ToUTF16(extension_name)); AppendExtensionItems(); AddSeparator(ui::NORMAL_SEPARATOR); + + // Add the "Always Allow" item for adding persisted permissions for script + // injections if there is an active action for this extension. Note that this + // will add it to *all* extension action context menus, not just the one + // attached to the script injection request icon, but that's okay. + WebContents* web_contents = GetActiveWebContents(); + if (web_contents && + extensions::ActiveScriptController::GetForWebContents(web_contents) + ->HasActiveScriptAction(extension)) { + AddItemWithStringId(ALWAYS_RUN, IDS_EXTENSIONS_ALWAYS_RUN); + } + AddItemWithStringId(CONFIGURE, IDS_EXTENSIONS_OPTIONS_MENU_ITEM); AddItem(UNINSTALL, l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL)); if (extension_action_manager->GetBrowserAction(*extension)) @@ -267,3 +287,7 @@ void ExtensionContextMenuModel::AppendExtensionItems() { &extension_items_count_, true); // is_action_menu } + +content::WebContents* ExtensionContextMenuModel::GetActiveWebContents() const { + return browser_->tab_strip_model()->GetActiveWebContents(); +} diff --git a/chrome/browser/extensions/extension_context_menu_model.h b/chrome/browser/extensions/extension_context_menu_model.h index 0ec50f7..50e9837 100644 --- a/chrome/browser/extensions/extension_context_menu_model.h +++ b/chrome/browser/extensions/extension_context_menu_model.h @@ -15,6 +15,10 @@ class Browser; class ExtensionAction; class Profile; +namespace content { +class WebContents; +} + namespace extensions { class Extension; class ContextMenuMatcher; @@ -34,7 +38,8 @@ class ExtensionContextMenuModel HIDE, UNINSTALL, MANAGE, - INSPECT_POPUP + INSPECT_POPUP, + ALWAYS_RUN }; // Type of action the extension icon represents. @@ -89,6 +94,9 @@ class ExtensionContextMenuModel // extension has been uninstalled and no longer exists. const extensions::Extension* GetExtension() const; + // Returns the active web contents. + content::WebContents* GetActiveWebContents() const; + // Appends the extension's context menu items. void AppendExtensionItems(); diff --git a/chrome/browser/extensions/permissions_updater.cc b/chrome/browser/extensions/permissions_updater.cc index 5f2f629..798717c 100644 --- a/chrome/browser/extensions/permissions_updater.cc +++ b/chrome/browser/extensions/permissions_updater.cc @@ -36,15 +36,35 @@ namespace permissions = api::permissions; namespace { +// Returns a set of single origin permissions from |permissions| that match +// |bounds|. This is necessary for two reasons: +// a) single origin active permissions can get filtered out in +// GetBoundedActivePermissions because they are not recognized as a subset +// of all-host permissions +// b) active permissions that do not match any manifest permissions can +// exist if a manifest permission is dropped +URLPatternSet FilterSingleOriginPermissions(const URLPatternSet& permissions, + const URLPatternSet& bounds) { + URLPatternSet single_origin_permissions; + for (URLPatternSet::const_iterator iter = permissions.begin(); + iter != permissions.end(); + ++iter) { + if (iter->MatchesSingleOrigin() && + bounds.MatchesURL(GURL(iter->GetAsString()))) { + single_origin_permissions.AddPattern(*iter); + } + } + return single_origin_permissions; +} + // Returns a PermissionSet that has the active permissions of the extension, // bounded to its current manifest. scoped_refptr<const PermissionSet> GetBoundedActivePermissions( - const Extension* extension, ExtensionPrefs* extension_prefs) { + const Extension* extension, + const scoped_refptr<const PermissionSet>& active_permissions) { // If the extension has used the optional permissions API, it will have a // custom set of active permissions defined in the extension prefs. Here, // we update the extension's active permissions based on the prefs. - scoped_refptr<const PermissionSet> active_permissions = - extension_prefs->GetActivePermissions(extension->id()); if (!active_permissions) return extension->permissions_data()->active_permissions(); @@ -144,9 +164,11 @@ void PermissionsUpdater::GrantActivePermissions(const Extension* extension) { } void PermissionsUpdater::InitializePermissions(const Extension* extension) { + scoped_refptr<const PermissionSet> active_permissions = + ExtensionPrefs::Get(browser_context_) + ->GetActivePermissions(extension->id()); scoped_refptr<const PermissionSet> bounded_active = - GetBoundedActivePermissions(extension, - ExtensionPrefs::Get(browser_context_)); + GetBoundedActivePermissions(extension, active_permissions); // We withhold permissions iff the switch to do so is enabled, the extension // shows up in chrome:extensions (so the user can grant withheld permissions), @@ -175,6 +197,20 @@ void PermissionsUpdater::InitializePermissions(const Extension* extension) { &granted_scriptable_hosts, &withheld_scriptable_hosts); + // After withholding permissions, add back any origins to the active set that + // may have been lost during the set operations that would have dropped them. + // For example, the union of <all_urls> and "example.com" is <all_urls>, so + // we may lose "example.com". However, "example.com" is important once + // <all_urls> is stripped during withholding. + if (active_permissions) { + granted_explicit_hosts.AddPatterns( + FilterSingleOriginPermissions(active_permissions->explicit_hosts(), + bounded_active->explicit_hosts())); + granted_scriptable_hosts.AddPatterns( + FilterSingleOriginPermissions(active_permissions->scriptable_hosts(), + bounded_active->scriptable_hosts())); + } + bounded_active = new PermissionSet(bounded_active->apis(), bounded_active->manifest_permissions(), granted_explicit_hosts, diff --git a/extensions/common/url_pattern.cc b/extensions/common/url_pattern.cc index 735e71e..71b522e 100644 --- a/extensions/common/url_pattern.cc +++ b/extensions/common/url_pattern.cc @@ -466,6 +466,12 @@ bool URLPattern::ImpliesAllHosts() const { return registry_length > 0; } +bool URLPattern::MatchesSingleOrigin() const { + // Strictly speaking, the port is part of the origin, but in URLPattern it + // defaults to *. It's not very interesting anyway, so leave it out. + return !ImpliesAllHosts() && scheme_ != "*" && !match_subdomains_; +} + bool URLPattern::MatchesPath(const std::string& test) const { // Make the behaviour of OverlapsWith consistent with MatchesURL, which is // need to match hosted apps on e.g. 'google.com' also run on 'google.com/'. diff --git a/extensions/common/url_pattern.h b/extensions/common/url_pattern.h index 5a0e8c6..c58c3ef 100644 --- a/extensions/common/url_pattern.h +++ b/extensions/common/url_pattern.h @@ -162,6 +162,10 @@ class URLPattern { // cached. bool ImpliesAllHosts() const; + // Returns true if the pattern only matches a single origin. The pattern may + // include a path. + bool MatchesSingleOrigin() const; + // Sets the port. Returns false if the port is invalid. bool SetPort(const std::string& port); const std::string& port() const { return port_; } diff --git a/extensions/common/url_pattern_set.cc b/extensions/common/url_pattern_set.cc index ee5ea93..bc1d0d5 100644 --- a/extensions/common/url_pattern_set.cc +++ b/extensions/common/url_pattern_set.cc @@ -142,6 +142,18 @@ void URLPatternSet::ClearPatterns() { patterns_.clear(); } +bool URLPatternSet::AddOrigin(int valid_schemes, const GURL& origin) { + DCHECK_EQ(origin.GetOrigin(), origin); + URLPattern origin_pattern(valid_schemes); + // Origin adding could fail if |origin| does not match |valid_schemes|. + if (origin_pattern.Parse(origin.GetOrigin().spec()) != + URLPattern::PARSE_SUCCESS) { + return false; + } + origin_pattern.SetPath("/*"); + return AddPattern(origin_pattern); +} + bool URLPatternSet::Contains(const URLPatternSet& other) const { for (URLPatternSet::const_iterator it = other.begin(); it != other.end(); ++it) { diff --git a/extensions/common/url_pattern_set.h b/extensions/common/url_pattern_set.h index c17f613..30db558 100644 --- a/extensions/common/url_pattern_set.h +++ b/extensions/common/url_pattern_set.h @@ -69,6 +69,9 @@ class URLPatternSet { void ClearPatterns(); + // Adds a pattern based on |origin| to the set. + bool AddOrigin(int valid_schemes, const GURL& origin); + // Returns true if every URL that matches |set| is matched by this. In other // words, if every pattern in |set| is encompassed by a pattern in this. bool Contains(const URLPatternSet& set) const; diff --git a/extensions/common/url_pattern_set_unittest.cc b/extensions/common/url_pattern_set_unittest.cc index 1ad223e..ce2c94e 100644 --- a/extensions/common/url_pattern_set_unittest.cc +++ b/extensions/common/url_pattern_set_unittest.cc @@ -421,4 +421,22 @@ TEST(URLPatternSetTest, NwayUnion) { } } +TEST(URLPatternSetTest, AddOrigin) { + URLPatternSet set; + EXPECT_TRUE(set.AddOrigin( + URLPattern::SCHEME_ALL, GURL("https://www.google.com/"))); + EXPECT_TRUE(set.MatchesURL(GURL("https://www.google.com/foo/bar"))); + EXPECT_FALSE(set.MatchesURL(GURL("http://www.google.com/foo/bar"))); + EXPECT_FALSE(set.MatchesURL(GURL("https://en.google.com/foo/bar"))); + set.ClearPatterns(); + + EXPECT_TRUE(set.AddOrigin( + URLPattern::SCHEME_ALL, GURL("https://google.com/"))); + EXPECT_FALSE(set.MatchesURL(GURL("https://www.google.com/foo/bar"))); + EXPECT_TRUE(set.MatchesURL(GURL("https://google.com/foo/bar"))); + + EXPECT_FALSE(set.AddOrigin( + URLPattern::SCHEME_HTTP, GURL("https://google.com/"))); +} + } // namespace extensions diff --git a/extensions/common/url_pattern_unittest.cc b/extensions/common/url_pattern_unittest.cc index 9618aeb..d4398a7 100644 --- a/extensions/common/url_pattern_unittest.cc +++ b/extensions/common/url_pattern_unittest.cc @@ -810,4 +810,35 @@ TEST(ExtensionURLPatternTest, Subset) { EXPECT_TRUE(StrictlyContains(pattern12, pattern13)); } +TEST(ExtensionURLPatternTest, MatchesSingleOrigin) { + EXPECT_FALSE( + URLPattern(URLPattern::SCHEME_ALL, "http://*/").MatchesSingleOrigin()); + EXPECT_FALSE(URLPattern(URLPattern::SCHEME_ALL, "https://*.google.com/*") + .MatchesSingleOrigin()); + EXPECT_TRUE(URLPattern(URLPattern::SCHEME_ALL, "http://google.com/") + .MatchesSingleOrigin()); + EXPECT_TRUE(URLPattern(URLPattern::SCHEME_ALL, "http://google.com/*") + .MatchesSingleOrigin()); + EXPECT_TRUE(URLPattern(URLPattern::SCHEME_ALL, "http://www.google.com/") + .MatchesSingleOrigin()); + EXPECT_FALSE(URLPattern(URLPattern::SCHEME_ALL, "*://www.google.com/") + .MatchesSingleOrigin()); + EXPECT_FALSE(URLPattern(URLPattern::SCHEME_ALL, "http://*.com/") + .MatchesSingleOrigin()); + EXPECT_FALSE(URLPattern(URLPattern::SCHEME_ALL, "http://*.google.com/foo/bar") + .MatchesSingleOrigin()); + EXPECT_TRUE( + URLPattern(URLPattern::SCHEME_ALL, "http://www.google.com/foo/bar") + .MatchesSingleOrigin()); + EXPECT_FALSE(URLPattern(URLPattern::SCHEME_HTTPS, "*://*.google.com/foo/bar") + .MatchesSingleOrigin()); + EXPECT_TRUE(URLPattern(URLPattern::SCHEME_HTTPS, "https://www.google.com/") + .MatchesSingleOrigin()); + EXPECT_FALSE(URLPattern(URLPattern::SCHEME_HTTP, + "http://*.google.com/foo/bar").MatchesSingleOrigin()); + EXPECT_TRUE( + URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/foo/bar") + .MatchesSingleOrigin()); +} + } // namespace |