diff options
author | bauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-30 08:47:58 +0000 |
---|---|---|
committer | bauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-30 08:47:58 +0000 |
commit | 188827c86eca6fa38e6cef5ac9852a26826a658a (patch) | |
tree | 68d51db12b35ee9fb4653edd45594dcc28ae19b2 | |
parent | adf46b69ad590589a13477f2b8ddce9d071e92a9 (diff) | |
download | chromium_src-188827c86eca6fa38e6cef5ac9852a26826a658a.zip chromium_src-188827c86eca6fa38e6cef5ac9852a26826a658a.tar.gz chromium_src-188827c86eca6fa38e6cef5ac9852a26826a658a.tar.bz2 |
Use extension match pattern syntax in content settings extension API.
This requires adding a port to a URLPattern, but that shouldn't change existing behavior, as we already have a lenient parsing mode there.
BUG=71067
Review URL: http://codereview.chromium.org/7229012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@91099 0039d316-1c4b-4281-b951-d872f2087c98
23 files changed, 483 insertions, 307 deletions
diff --git a/chrome/browser/extensions/extension_content_settings_api.cc b/chrome/browser/extensions/extension_content_settings_api.cc index eaed7c0..58f8343 100644 --- a/chrome/browser/extensions/extension_content_settings_api.cc +++ b/chrome/browser/extensions/extension_content_settings_api.cc @@ -169,29 +169,27 @@ bool SetContentSettingFunction::RunImpl() { DictionaryValue* details = NULL; EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details)); - DictionaryValue* top_level_pattern_dict = NULL; - EXTENSION_FUNCTION_VALIDATE( - details->GetDictionary(keys::kTopLevelPatternKey, - &top_level_pattern_dict)); std::string top_level_pattern_str; + std::string top_level_error; EXTENSION_FUNCTION_VALIDATE( - top_level_pattern_dict->GetString(keys::kPatternKey, - &top_level_pattern_str)); + details->GetString(keys::kTopLevelPatternKey, &top_level_pattern_str)); ContentSettingsPattern top_level_pattern = - ContentSettingsPattern::FromString(top_level_pattern_str); - EXTENSION_FUNCTION_VALIDATE(top_level_pattern.IsValid()); + helpers::ParseExtensionPattern(top_level_pattern_str, &top_level_error); + if (!top_level_pattern.IsValid()) { + error_ = top_level_error; + return false; + } - DictionaryValue* embedded_pattern_dict = NULL; - EXTENSION_FUNCTION_VALIDATE( - details->GetDictionary(keys::kEmbeddedPatternKey, - &embedded_pattern_dict)); std::string embedded_pattern_str; + std::string embedded_error; EXTENSION_FUNCTION_VALIDATE( - embedded_pattern_dict->GetString(keys::kPatternKey, - &embedded_pattern_str)); + details->GetString(keys::kEmbeddedPatternKey, &embedded_pattern_str)); ContentSettingsPattern embedded_pattern = - ContentSettingsPattern::FromString(embedded_pattern_str); - EXTENSION_FUNCTION_VALIDATE(embedded_pattern.IsValid()); + helpers::ParseExtensionPattern(embedded_pattern_str, &embedded_error); + if (!embedded_pattern.IsValid()) { + error_ = embedded_error; + return false; + } std::string resource_identifier; if (details->HasKey(keys::kResourceIdentifierKey)) { diff --git a/chrome/browser/extensions/extension_content_settings_helpers.cc b/chrome/browser/extensions/extension_content_settings_helpers.cc index c250e7b1..bb24955 100644 --- a/chrome/browser/extensions/extension_content_settings_helpers.cc +++ b/chrome/browser/extensions/extension_content_settings_helpers.cc @@ -6,9 +6,17 @@ #include "base/basictypes.h" #include "base/logging.h" +#include "base/scoped_ptr.h" +#include "chrome/common/extensions/url_pattern.h" +#include "content/common/url_constants.h" namespace { +const char kNoPathWildcardsError[] = + "Path wildcards in file URL patterns are not allowed."; +const char kNoPathsError[] = "Specific paths are not allowed."; +const char kInvalidPatternError[] = "The pattern \"*\" is invalid."; + const char* const kContentSettingsTypeNames[] = { "cookies", "images", @@ -33,10 +41,77 @@ COMPILE_ASSERT(arraysize(kContentSettingNames) <= CONTENT_SETTING_NUM_SETTINGS, content_setting_names_size_invalid); +// TODO(bauerb): Move this someplace where it can be reused. +std::string GetDefaultPort(const std::string& scheme) { + if (scheme == chrome::kHttpScheme) + return "80"; + if (scheme == chrome::kHttpsScheme) + return "443"; + NOTREACHED(); + return ""; +} + } // namespace namespace extension_content_settings_helpers { +ContentSettingsPattern ParseExtensionPattern(const std::string& pattern_str, + std::string* error) { + URLPattern url_pattern(URLPattern::SCHEME_HTTP | + URLPattern::SCHEME_HTTPS | + URLPattern::SCHEME_FILE); + URLPattern::ParseResult result = + url_pattern.Parse(pattern_str, URLPattern::USE_PORTS); + if (result != URLPattern::PARSE_SUCCESS) { + *error = URLPattern::GetParseResultString(result); + return ContentSettingsPattern(); + } else { + scoped_ptr<ContentSettingsPattern::BuilderInterface> builder( + ContentSettingsPattern::CreateBuilder(false)); + builder->WithHost(url_pattern.host()); + if (url_pattern.match_subdomains()) + builder->WithDomainWildcard(); + + std::string scheme = url_pattern.scheme(); + if (scheme == "*") + builder->WithSchemeWildcard(); + else + builder->WithScheme(scheme); + + std::string port = url_pattern.port(); + if (port.empty() && scheme != "file") { + if (scheme == "*") + port = "*"; + else + port = GetDefaultPort(scheme); + } + if (port == "*") + builder->WithPortWildcard(); + else + builder->WithPort(port); + + std::string path = url_pattern.path(); + if (scheme == "file") { + // For file URLs we allow only exact path matches. + if (path.find_first_of("*?") != std::string::npos) { + *error = kNoPathWildcardsError; + return ContentSettingsPattern(); + } else { + builder->WithPath(path); + } + } else if (path != "/*") { + // For other URLs we allow only paths which match everything. + *error = kNoPathsError; + return ContentSettingsPattern(); + } + + ContentSettingsPattern pattern = builder->Build(); + if (!pattern.IsValid()) + *error = kInvalidPatternError; + return pattern; + } +} + ContentSettingsType StringToContentSettingsType( const std::string& content_type) { for (size_t type = 0; type < arraysize(kContentSettingsTypeNames); ++type) { diff --git a/chrome/browser/extensions/extension_content_settings_helpers.h b/chrome/browser/extensions/extension_content_settings_helpers.h index c7c6f25..b3e4ce7 100644 --- a/chrome/browser/extensions/extension_content_settings_helpers.h +++ b/chrome/browser/extensions/extension_content_settings_helpers.h @@ -8,10 +8,19 @@ #include <string> +#include "chrome/browser/content_settings/content_settings_pattern.h" #include "chrome/common/content_settings.h" namespace extension_content_settings_helpers { +// Parses an extension match pattern and returns a corresponding +// content settings pattern object. +// If |pattern_str| is invalid or can't be converted to a content settings +// pattern, |error| is set to the parsing error and an invalid pattern +// is returned. +ContentSettingsPattern ParseExtensionPattern(const std::string& pattern_str, + std::string* error); + // Converts a content settings type string to the corresponding // ContentSettingsType. Returns CONTENT_SETTINGS_TYPE_DEFAULT if the string // didn't specify a valid content settings type. diff --git a/chrome/browser/extensions/extension_content_settings_unittest.cc b/chrome/browser/extensions/extension_content_settings_unittest.cc new file mode 100644 index 0000000..500afc2 --- /dev/null +++ b/chrome/browser/extensions/extension_content_settings_unittest.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2011 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 "testing/gtest/include/gtest/gtest.h" + +#include "chrome/browser/extensions/extension_content_settings_helpers.h" + +namespace helpers = extension_content_settings_helpers; + +TEST(ExtensionContentSettingsHelpersTest, ParseExtensionPattern) { + const struct { + const char* extension_pattern; + const char* content_settings_pattern; + } kTestPatterns[] = { + { "<all_urls>", "*" }, + { "*://*.google.com/*", "[*.]google.com" }, + { "http://www.example.com/*", "http://www.example.com" }, + { "*://www.example.com/*", "www.example.com" }, + { "http://www.example.com:8080/*", "http://www.example.com:8080" }, + { "https://*/*", "https://*" }, + { "file:///foo/bar/baz", "file:///foo/bar/baz" }, + }; + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestPatterns); ++i) { + std::string error; + std::string pattern_str = helpers::ParseExtensionPattern( + kTestPatterns[i].extension_pattern, &error).ToString(); + EXPECT_EQ(kTestPatterns[i].content_settings_pattern, pattern_str) + << "Unexpected error parsing " << kTestPatterns[i].extension_pattern + << ": " << error; + } + + const struct { + const char* extension_pattern; + const char* expected_error; + } kInvalidTestPatterns[] = { + { "http://www.example.com/path", "Specific paths are not allowed." }, + { "file:///foo/bar/*", + "Path wildcards in file URL patterns are not allowed." }, + }; + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kInvalidTestPatterns); ++i) { + std::string error; + ContentSettingsPattern pattern = helpers::ParseExtensionPattern( + kInvalidTestPatterns[i].extension_pattern, &error); + EXPECT_FALSE(pattern.IsValid()); + EXPECT_EQ(kInvalidTestPatterns[i].expected_error, error) + << "Unexpected error parsing " + << kInvalidTestPatterns[i].extension_pattern; + } + +} diff --git a/chrome/browser/extensions/extension_context_menu_api.cc b/chrome/browser/extensions/extension_context_menu_api.cc index 50d08b7..d5f1e01 100644 --- a/chrome/browser/extensions/extension_context_menu_api.cc +++ b/chrome/browser/extensions/extension_context_menu_api.cc @@ -143,7 +143,7 @@ bool ExtensionContextMenuFunction::ParseURLPatterns( // TODO(skerner): Consider enabling strict pattern parsing // if this extension's location indicates that it is under development. if (URLPattern::PARSE_SUCCESS != pattern.Parse(tmp, - URLPattern::PARSE_LENIENT)) { + URLPattern::IGNORE_PORTS)) { error_ = ExtensionErrorUtils::FormatErrorMessage(kInvalidURLPatternError, tmp); return false; diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc index d7b63dc..600dea7 100644 --- a/chrome/browser/extensions/extension_prefs.cc +++ b/chrome/browser/extensions/extension_prefs.cc @@ -451,7 +451,7 @@ bool ExtensionPrefs::ReadExtensionPrefURLPatternSet( if (!value->GetString(i, &item)) return false; URLPattern pattern(valid_schemes); - if (pattern.Parse(item, URLPattern::PARSE_LENIENT) != + if (pattern.Parse(item, URLPattern::IGNORE_PORTS) != URLPattern::PARSE_SUCCESS) { NOTREACHED(); return false; diff --git a/chrome/browser/extensions/extension_webrequest_api.cc b/chrome/browser/extensions/extension_webrequest_api.cc index ce46469..df3a9ee 100644 --- a/chrome/browser/extensions/extension_webrequest_api.cc +++ b/chrome/browser/extensions/extension_webrequest_api.cc @@ -238,7 +238,7 @@ bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue( std::string url; URLPattern pattern(URLPattern::SCHEME_ALL); if (!urls_value->GetString(i, &url) || - pattern.Parse(url, URLPattern::PARSE_STRICT) != + pattern.Parse(url, URLPattern::ERROR_ON_PORTS) != URLPattern::PARSE_SUCCESS) { *error = ExtensionErrorUtils::FormatErrorMessage( keys::kInvalidRequestFilterUrl, url); diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc index 60f8be0..3772ac6 100644 --- a/chrome/browser/extensions/user_script_master.cc +++ b/chrome/browser/extensions/user_script_master.cc @@ -107,7 +107,7 @@ bool UserScriptMaster::ScriptReloader::ParseMetadataHeader( } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) { URLPattern pattern(UserScript::kValidUserScriptSchemes); if (URLPattern::PARSE_SUCCESS != - pattern.Parse(value, URLPattern::PARSE_LENIENT)) + pattern.Parse(value, URLPattern::IGNORE_PORTS)) return false; script->add_url_pattern(pattern); } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) { diff --git a/chrome/browser/tab_contents/render_view_context_menu_unittest.cc b/chrome/browser/tab_contents/render_view_context_menu_unittest.cc index 02ffe30..5589354 100644 --- a/chrome/browser/tab_contents/render_view_context_menu_unittest.cc +++ b/chrome/browser/tab_contents/render_view_context_menu_unittest.cc @@ -73,7 +73,7 @@ static ContextMenuParams CreateParams(int contexts) { // Generates a URLPatternSet with a single pattern static URLPatternSet CreatePatternSet(const std::string& pattern) { URLPattern target(URLPattern::SCHEME_HTTP); - target.Parse(pattern, URLPattern::PARSE_LENIENT); + target.Parse(pattern, URLPattern::IGNORE_PORTS); URLPatternSet rv; rv.AddPattern(target); diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 79a1f18e..2a02515 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1385,6 +1385,7 @@ 'browser/extensions/extension_menu_manager_unittest.cc', 'browser/extensions/extension_omnibox_unittest.cc', 'browser/extensions/extension_content_settings_store_unittest.cc', + 'browser/extensions/extension_content_settings_unittest.cc', 'browser/extensions/extension_pref_value_map_unittest.cc', 'browser/extensions/extension_prefs_unittest.cc', 'browser/extensions/extension_process_manager_unittest.cc', diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json index 50b97f2..cc30bf6 100644 --- a/chrome/common/extensions/api/extension_api.json +++ b/chrome/common/extensions/api/extension_api.json @@ -5802,26 +5802,16 @@ "description": "Currently, no content types use resource identifiers." }, { - "id": "Pattern", - "type": "object", - "properties": { - "pattern": { - "type": "string", - "description": "The pattern string. The pattern should never be constructed directly, but should always be derived from an URL using the methods in the <var>contentSettings.patterns</var> module." - } - } - }, - { "id": "ContentSettingRule", "type": "object", "properties": { "topLevelPattern": { - "$ref": "Pattern", - "description": "The pattern for the top-level frame URL." + "type": "string", + "description": "The pattern for the top-level frame URL. For details on the format of a pattern, see <a href='match_patterns.html'>Match Patterns</a>." }, "embeddedPattern": { - "$ref": "Pattern", - "description": "The pattern for the frame or object URL." + "type": "string", + "description": "The pattern for the frame or object URL. For details on the format of a pattern, see <a href='match_patterns.html'>Match Patterns</a>." }, "resourceIdentifier": { "$ref": "ResourceIdentifier", @@ -5920,12 +5910,12 @@ "type": "object", "properties": { "topLevelPattern": { - "$ref": "Pattern", - "description": "The pattern for the top-level frame URL." + "type": "string", + "description": "The pattern for the top-level frame URL. For details on the format of a pattern, see <a href='match_patterns.html'>Match Patterns</a>." }, "embeddedPattern": { - "$ref": "Pattern", - "description": "The pattern for the frame or object URL." + "type": "string", + "description": "The pattern for the frame or object URL. For details on the format of a pattern, see <a href='match_patterns.html'>Match Patterns</a>." }, "resourceIdentifier": { "$ref": "ResourceIdentifier", diff --git a/chrome/common/extensions/docs/examples/api/contentSettings.zip b/chrome/common/extensions/docs/examples/api/contentSettings.zip Binary files differindex d10841d..38a2a2a 100644 --- a/chrome/common/extensions/docs/examples/api/contentSettings.zip +++ b/chrome/common/extensions/docs/examples/api/contentSettings.zip diff --git a/chrome/common/extensions/docs/examples/api/contentSettings/popup.html b/chrome/common/extensions/docs/examples/api/contentSettings/popup.html index eebb9c4..d83e1d1 100644 --- a/chrome/common/extensions/docs/examples/api/contentSettings/popup.html +++ b/chrome/common/extensions/docs/examples/api/contentSettings/popup.html @@ -2,16 +2,6 @@ <html> <head> <script> -var settings = { - "cookies": ["allow", "session_only", "block"], - "images": ["allow", "block"], - "javascript": ["allow", "block"], - "plugins": ["allow", "block"], - "popups": ["allow", "block"], - // "location": ["allow", "ask", "block"], - "notifications": ["allow", "ask", "block"], -}; - var incognito; var url; @@ -37,9 +27,7 @@ function init() { function settingChanged(element) { var type = element.id; var setting = element.value; - var pattern = { - 'pattern': url - }; + var pattern = /^file:/.test(url) ? url : url.replace(/\/[^\/]*?$/, '/*'); console.log(type+" setting for "+pattern+": "+setting); chrome.experimental.contentSettings[type].set({ 'topLevelPattern': pattern, @@ -73,7 +61,6 @@ function settingChanged(element) { <dt><label for="plugins">Plug-ins: </label></dt> <dd><select id="plugins" onchange="settingChanged(this);"> <option value="allow">Allow</option> - <option value="ask">Click-to-play</option> <option value="block">Block</option> </select></dd> <dt><label for="popups">Pop-ups: </label></dt> diff --git a/chrome/common/extensions/docs/experimental.contentSettings.html b/chrome/common/extensions/docs/experimental.contentSettings.html index ce83132..fcb153b 100644 --- a/chrome/common/extensions/docs/experimental.contentSettings.html +++ b/chrome/common/extensions/docs/experimental.contentSettings.html @@ -310,8 +310,6 @@ <li> <a href="#type-ResourceIdentifier">ResourceIdentifier</a> </li><li> - <a href="#type-Pattern">Pattern</a> - </li><li> <a href="#type-ContentSettingRule">ContentSettingRule</a> </li><li> <a href="#type-ContentSetting">ContentSetting</a> @@ -1411,8 +1409,8 @@ </div> </div><div class="apiItem"> - <a name="type-Pattern"></a> - <h4>Pattern</h4> + <a name="type-ContentSettingRule"></a> + <h4>ContentSettingRule</h4> <div> <dt> @@ -1463,7 +1461,7 @@ <div> <div> <dt> - <var>pattern</var> + <var>topLevelPattern</var> <em> <!-- TYPE --> @@ -1491,7 +1489,7 @@ <dd class="todo" style="display: none; "> Undocumented. </dd> - <dd>The pattern string. The pattern should never be constructed directly, but should always be derived from an URL using the methods in the <var>contentSettings.patterns</var> module.</dd> + <dd>The pattern for the top-level frame URL. For details on the format of a pattern, see <a href="match_patterns.html">Match Patterns</a>.</dd> <dd style="display: none; "> This parameter was added in version <b><span></span></b>. @@ -1528,34 +1526,10 @@ </dd> </div> - </div> - </dl> - </dd> - - <!-- OBJECT METHODS --> - <dd style="display: none; "> - <div></div> - </dd> - - <!-- OBJECT EVENT FIELDS --> - <dd style="display: none; "> - <div></div> - </dd> - - <!-- FUNCTION PARAMETERS --> - <dd style="display: none; "> - <div></div> - </dd> - - </div> - - </div><div class="apiItem"> - <a name="type-ContentSettingRule"></a> - <h4>ContentSettingRule</h4> - - <div> + </div><div> + <div> <dt> - <var style="display: none; ">paramName</var> + <var>embeddedPattern</var> <em> <!-- TYPE --> @@ -1571,7 +1545,7 @@ <span style="display: none; "> array of <span><span></span></span> </span> - <span>object</span> + <span>string</span> <span style="display: none; "></span> </span> </span> @@ -1580,125 +1554,10 @@ </em> </dt> - <dd class="todo"> - Undocumented. - </dd> - <dd style="display: none; "> - Description of this parameter from the json schema. - </dd> - <dd style="display: none; "> - This parameter was added in version - <b><span></span></b>. - You must omit this parameter in earlier versions, - and you may omit it in any version. If you require this - parameter, the manifest key - <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a> - can ensure that your extension won't be run in an earlier browser version. - </dd> - - <!-- OBJECT PROPERTIES --> - <dd> - <dl> - <div> - <div> - <dt> - <var>topLevelPattern</var> - <em> - - <!-- TYPE --> - <div style="display:inline"> - ( - <span class="optional" style="display: none; ">optional</span> - <span class="enum" style="display: none; ">enumerated</span> - <span id="typeTemplate"> - <span> - <a href="experimental.contentSettings.html#type-Pattern">Pattern</a> - </span> - <span style="display: none; "> - <span> - array of <span><span></span></span> - </span> - <span>paramType</span> - <span></span> - </span> - </span> - ) - </div> - - </em> - </dt> - <dd class="todo" style="display: none; "> - Undocumented. - </dd> - <dd>The pattern for the top-level frame URL.</dd> - <dd style="display: none; "> - This parameter was added in version - <b><span></span></b>. - You must omit this parameter in earlier versions, - and you may omit it in any version. If you require this - parameter, the manifest key - <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a> - can ensure that your extension won't be run in an earlier browser version. - </dd> - - <!-- OBJECT PROPERTIES --> - <dd style="display: none; "> - <dl> - <div> - <div> - </div> - </div> - </dl> - </dd> - - <!-- OBJECT METHODS --> - <dd style="display: none; "> - <div></div> - </dd> - - <!-- OBJECT EVENT FIELDS --> - <dd style="display: none; "> - <div></div> - </dd> - - <!-- FUNCTION PARAMETERS --> - <dd style="display: none; "> - <div></div> - </dd> - - </div> - </div><div> - <div> - <dt> - <var>embeddedPattern</var> - <em> - - <!-- TYPE --> - <div style="display:inline"> - ( - <span class="optional" style="display: none; ">optional</span> - <span class="enum" style="display: none; ">enumerated</span> - <span id="typeTemplate"> - <span> - <a href="experimental.contentSettings.html#type-Pattern">Pattern</a> - </span> - <span style="display: none; "> - <span> - array of <span><span></span></span> - </span> - <span>paramType</span> - <span></span> - </span> - </span> - ) - </div> - - </em> - </dt> <dd class="todo" style="display: none; "> Undocumented. </dd> - <dd>The pattern for the frame or object URL.</dd> + <dd>The pattern for the frame or object URL. For details on the format of a pattern, see <a href="match_patterns.html">Match Patterns</a>.</dd> <dd style="display: none; "> This parameter was added in version <b><span></span></b>. @@ -3111,15 +2970,15 @@ <span class="optional" style="display: none; ">optional</span> <span class="enum" style="display: none; ">enumerated</span> <span id="typeTemplate"> - <span> - <a href="experimental.contentSettings.html#type-Pattern">Pattern</a> - </span> <span style="display: none; "> - <span> + <a> Type</a> + </span> + <span> + <span style="display: none; "> array of <span><span></span></span> </span> - <span>paramType</span> - <span></span> + <span>string</span> + <span style="display: none; "></span> </span> </span> ) @@ -3130,7 +2989,7 @@ <dd class="todo" style="display: none; "> Undocumented. </dd> - <dd>The pattern for the top-level frame URL.</dd> + <dd>The pattern for the top-level frame URL. For details on the format of a pattern, see <a href="match_patterns.html">Match Patterns</a>.</dd> <dd style="display: none; "> This parameter was added in version <b><span></span></b>. @@ -3179,15 +3038,15 @@ <span class="optional" style="display: none; ">optional</span> <span class="enum" style="display: none; ">enumerated</span> <span id="typeTemplate"> - <span> - <a href="experimental.contentSettings.html#type-Pattern">Pattern</a> - </span> <span style="display: none; "> - <span> + <a> Type</a> + </span> + <span> + <span style="display: none; "> array of <span><span></span></span> </span> - <span>paramType</span> - <span></span> + <span>string</span> + <span style="display: none; "></span> </span> </span> ) @@ -3198,7 +3057,7 @@ <dd class="todo" style="display: none; "> Undocumented. </dd> - <dd>The pattern for the frame or object URL.</dd> + <dd>The pattern for the frame or object URL. For details on the format of a pattern, see <a href="match_patterns.html">Match Patterns</a>.</dd> <dd style="display: none; "> This parameter was added in version <b><span></span></b>. diff --git a/chrome/common/extensions/docs/samples.json b/chrome/common/extensions/docs/samples.json index ae080e0..3b6e746 100644 --- a/chrome/common/extensions/docs/samples.json +++ b/chrome/common/extensions/docs/samples.json @@ -563,7 +563,7 @@ "manifest.json", "popup.html" ], - "source_hash": "f53b10cf54302a91ee763af603d7c0a3ffe1461f", + "source_hash": "1bd5e6d89bc8090a55837c26d0ba3911fd63b362", "zip_path": "examples\/api\/contentSettings.zip" }, { diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc index e98c5f0..e813b99 100644 --- a/chrome/common/extensions/extension.cc +++ b/chrome/common/extensions/extension.cc @@ -374,8 +374,8 @@ bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script, UserScript* result) { // When strict error checks are enabled, make URL pattern parsing strict. URLPattern::ParseOption parse_strictness = - (flags & STRICT_ERROR_CHECKS ? URLPattern::PARSE_STRICT - : URLPattern::PARSE_LENIENT); + (flags & STRICT_ERROR_CHECKS ? URLPattern::ERROR_ON_PORTS + : URLPattern::IGNORE_PORTS); // run_at if (content_script->HasKey(keys::kRunAt)) { @@ -785,8 +785,8 @@ FileBrowserHandler* Extension::LoadFileBrowserHandler( return NULL; } URLPattern pattern(URLPattern::SCHEME_FILESYSTEM); - if (URLPattern::PARSE_SUCCESS != pattern.Parse(filter, - URLPattern::PARSE_STRICT)) { + if (pattern.Parse(filter, URLPattern::ERROR_ON_PORTS) != + URLPattern::PARSE_SUCCESS) { *error = ExtensionErrorUtils::FormatErrorMessage( errors::kInvalidURLPatternError, filter); return NULL; @@ -1035,7 +1035,7 @@ bool Extension::LoadLaunchURL(const DictionaryValue* manifest, launch_web_url_ = gallery_url.spec(); URLPattern pattern(kValidWebExtentSchemes); - pattern.Parse(gallery_url.spec(), URLPattern::PARSE_STRICT); + pattern.Parse(gallery_url.spec(), URLPattern::ERROR_ON_PORTS); pattern.SetPath(pattern.path() + '*'); extent_.AddPattern(pattern); } @@ -1323,8 +1323,8 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags, std::string* error) { // When strict error checks are enabled, make URL pattern parsing strict. URLPattern::ParseOption parse_strictness = - (flags & STRICT_ERROR_CHECKS ? URLPattern::PARSE_STRICT - : URLPattern::PARSE_LENIENT); + (flags & STRICT_ERROR_CHECKS ? URLPattern::ERROR_ON_PORTS + : URLPattern::IGNORE_PORTS); // Initialize permissions with an empty, default permission set. permission_set_.reset(new ExtensionPermissionSet()); diff --git a/chrome/common/extensions/extension_messages.cc b/chrome/common/extensions/extension_messages.cc index 9d0eb78..268d06f 100644 --- a/chrome/common/extensions/extension_messages.cc +++ b/chrome/common/extensions/extension_messages.cc @@ -100,7 +100,7 @@ bool ParamTraits<URLPattern>::Read(const Message* m, void** iter, return false; p->set_valid_schemes(valid_schemes); - return URLPattern::PARSE_SUCCESS == p->Parse(spec, URLPattern::PARSE_LENIENT); + return URLPattern::PARSE_SUCCESS == p->Parse(spec, URLPattern::IGNORE_PORTS); } void ParamTraits<URLPattern>::Log(const param_type& p, std::string* l) { diff --git a/chrome/common/extensions/url_pattern.cc b/chrome/common/extensions/url_pattern.cc index 6749ab8..af0fd0a 100644 --- a/chrome/common/extensions/url_pattern.cc +++ b/chrome/common/extensions/url_pattern.cc @@ -4,6 +4,7 @@ #include "chrome/common/extensions/url_pattern.h" +#include "base/string_number_conversions.h" #include "base/string_piece.h" #include "base/string_split.h" #include "base/string_util.h" @@ -48,6 +49,8 @@ const char* kParseErrorInvalidHostWildcard = "Invalid host wildcard."; const char* kParseErrorEmptyPath = "Empty path."; const char* kParseErrorHasColon = "Ports are not supported in URL patterns. ':' may not be used in a host."; +const char* kParseErrorInvalidPort = + "Invalid port."; // Message explaining each URLPattern::ParseResult. const char* kParseResultMessages[] = { @@ -58,7 +61,8 @@ const char* kParseResultMessages[] = { kParseErrorEmptyHost, kParseErrorInvalidHostWildcard, kParseErrorEmptyPath, - kParseErrorHasColon + kParseErrorHasColon, + kParseErrorInvalidPort, }; COMPILE_ASSERT(URLPattern::NUM_PARSE_RESULTS == arraysize(kParseResultMessages), @@ -75,24 +79,45 @@ bool IsStandardScheme(const std::string& scheme) { url_parse::Component(0, static_cast<int>(scheme.length()))); } +bool IsValidPortForScheme(const std::string scheme, const std::string& port) { + if (port == "*") + return true; + + // Only accept non-wildcard ports if the scheme uses ports. + if (url_canon::DefaultPortForScheme(scheme.c_str(), scheme.length()) == + url_parse::PORT_UNSPECIFIED) { + return false; + } + + int parsed_port = url_parse::PORT_UNSPECIFIED; + if (!base::StringToInt(port, &parsed_port)) + return false; + return (parsed_port >= 0) && (parsed_port < 65536); +} + } // namespace URLPattern::URLPattern() : valid_schemes_(SCHEME_NONE), match_all_urls_(false), - match_subdomains_(false) {} + match_subdomains_(false), + port_("*") {} URLPattern::URLPattern(int valid_schemes) - : valid_schemes_(valid_schemes), match_all_urls_(false), - match_subdomains_(false) {} + : valid_schemes_(valid_schemes), + match_all_urls_(false), + match_subdomains_(false), + port_("*") {} URLPattern::URLPattern(int valid_schemes, const std::string& pattern) - : valid_schemes_(valid_schemes), match_all_urls_(false), - match_subdomains_(false) { + : valid_schemes_(valid_schemes), + match_all_urls_(false), + match_subdomains_(false), + port_("*") { // Strict error checking is used, because this constructor is only // appropriate when we know |pattern| is valid. - if (PARSE_SUCCESS != Parse(pattern, PARSE_STRICT)) + if (PARSE_SUCCESS != Parse(pattern, ERROR_ON_PORTS)) NOTREACHED() << "URLPattern is invalid: " << pattern; } @@ -101,9 +126,6 @@ URLPattern::~URLPattern() { URLPattern::ParseResult URLPattern::Parse(const std::string& pattern, ParseOption strictness) { - CHECK(strictness == PARSE_LENIENT || - strictness == PARSE_STRICT); - // Special case pattern to match every valid URL. if (pattern == kAllUrlsPattern) { match_all_urls_ = true; @@ -180,19 +202,34 @@ URLPattern::ParseResult URLPattern::Parse(const std::string& pattern, } host_ = JoinString(host_components, '.'); - // No other '*' can occur in the host, though. This isn't necessary, but is - // done as a convenience to developers who might otherwise be confused and - // think '*' works as a glob in the host. - if (host_.find('*') != std::string::npos) - return PARSE_ERROR_INVALID_HOST_WILDCARD; - path_start_pos = host_end_pos; } SetPath(pattern.substr(path_start_pos)); - if (strictness == PARSE_STRICT && host_.find(':') != std::string::npos) - return PARSE_ERROR_HAS_COLON; + size_t port_pos = host_.find(':'); + if (port_pos != std::string::npos) { + switch (strictness) { + case USE_PORTS: { + if (!SetPort(host_.substr(port_pos + 1))) + return PARSE_ERROR_INVALID_PORT; + host_ = host_.substr(0, port_pos); + break; + } + case ERROR_ON_PORTS: { + return PARSE_ERROR_HAS_COLON; + } + case IGNORE_PORTS: { + // Do nothing, i.e. leave the colon in the host. + } + } + } + + // No other '*' can occur in the host, though. This isn't necessary, but is + // done as a convenience to developers who might otherwise be confused and + // think '*' works as a glob in the host. + if (host_.find('*') != std::string::npos) + return PARSE_ERROR_INVALID_HOST_WILDCARD; return PARSE_SUCCESS; } @@ -226,6 +263,14 @@ void URLPattern::SetPath(const std::string& path) { ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?"); } +bool URLPattern::SetPort(const std::string& port) { + if (IsValidPortForScheme(scheme_, port)) { + port_ = port; + return true; + } + return false; +} + bool URLPattern::MatchesURL(const GURL &test) const { if (!MatchesScheme(test.scheme())) return false; @@ -240,6 +285,9 @@ bool URLPattern::MatchesURL(const GURL &test) const { if (!MatchesPath(test.PathForRequest())) return false; + if (!MatchesPort(test.EffectiveIntPort())) + return false; + return true; } @@ -296,6 +344,13 @@ bool URLPattern::MatchesPath(const std::string& test) const { return true; } +bool URLPattern::MatchesPort(int port) const { + if (port == url_parse::PORT_INVALID) + return false; + + return port_ == "*" || port_ == base::IntToString(port); +} + std::string URLPattern::GetAsString() const { if (match_all_urls_) return kAllUrlsPattern; @@ -314,6 +369,11 @@ std::string URLPattern::GetAsString() const { if (!host_.empty()) spec += host_; + + if (port_ != "*") { + spec += ":"; + spec += port_; + } } if (!path_.empty()) @@ -331,6 +391,9 @@ bool URLPattern::OverlapsWith(const URLPattern& other) const { if (!MatchesHost(other.host()) && !other.MatchesHost(host_)) return false; + if (port_ != "*" && other.port() != "*" && port_ != other.port()) + return false; + // We currently only use OverlapsWith() for the patterns inside // URLPatternSet. In those cases, we know that the path will have only a // single wildcard at the end. This makes figuring out overlap much easier. It diff --git a/chrome/common/extensions/url_pattern.h b/chrome/common/extensions/url_pattern.h index 264da1f..113d266 100644 --- a/chrome/common/extensions/url_pattern.h +++ b/chrome/common/extensions/url_pattern.h @@ -14,12 +14,19 @@ class GURL; // A pattern that can be used to match URLs. A URLPattern is a very restricted // subset of URL syntax: // -// <url-pattern> := <scheme>://<host><path> | '<all_urls>' +// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>' // <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome' // <host> := '*' | '*.' <anychar except '/' and '*'>+ +// <port> := [':' ('*' | <port number between 0 and 65535>)] // <path> := '/' <any chars> // // * Host is not used when the scheme is 'file'. +// * The port is only used if the pattern is parsed with the USE_PORTS option. +// If the patterns is parsed with the ERROR_ON_PORTS option, the port is not +// allowed, and the resulting pattern matches any port. If it is parsed with +// the IGNORE_PORTS option, the port (including colon) is kept as part of the +// host to maintain backwards compatibility with previous versions, which +// makes the pattern effectively never match any URL. // * The path can have embedded '*' characters which act as glob wildcards. // * '<all_urls>' is a special pattern that matches any URL that contains a // valid scheme (as specified by valid_schemes_). @@ -94,8 +101,9 @@ class URLPattern { // Options for URLPattern::Parse(). enum ParseOption { - PARSE_LENIENT, - PARSE_STRICT + ERROR_ON_PORTS, + IGNORE_PORTS, + USE_PORTS, }; // Error codes returned from Parse(). @@ -107,7 +115,8 @@ class URLPattern { PARSE_ERROR_EMPTY_HOST, PARSE_ERROR_INVALID_HOST_WILDCARD, PARSE_ERROR_EMPTY_PATH, - PARSE_ERROR_HAS_COLON, // Only checked when strict checks are enabled. + PARSE_ERROR_HAS_COLON, // Only checked when parsing with ERROR_ON_PORTS. + PARSE_ERROR_INVALID_PORT, // Only checked when parsing with USE_PORTS. NUM_PARSE_RESULTS }; @@ -194,6 +203,13 @@ class URLPattern { // Returns true if |test| matches our path. bool MatchesPath(const std::string& test) const; + // Returns true if |port| matches our port. + bool MatchesPort(int port) const; + + // Sets the port. Returns false if the port is invalid. + bool SetPort(const std::string& port); + const std::string& port() const { return port_; } + // Returns a string representing this instance. std::string GetAsString() const; @@ -260,6 +276,10 @@ class URLPattern { // component of the pattern's host was "*". bool match_subdomains_; + // The port. URL patterns only support specific ports if they are parsed with + // the |USE_PORTS| option. + std::string port_; + // The path to match. This is everything after the host of the URL, or // everything after the scheme in the case of file:// URLs. std::string path_; diff --git a/chrome/common/extensions/url_pattern_unittest.cc b/chrome/common/extensions/url_pattern_unittest.cc index cda9550..0903395 100644 --- a/chrome/common/extensions/url_pattern_unittest.cc +++ b/chrome/common/extensions/url_pattern_unittest.cc @@ -38,44 +38,96 @@ TEST(ExtensionURLPatternTest, ParseInvalid) { URLPattern pattern(URLPattern::SCHEME_ALL); EXPECT_EQ(kInvalidPatterns[i].expected_result, pattern.Parse(kInvalidPatterns[i].pattern, - URLPattern::PARSE_LENIENT)) + URLPattern::IGNORE_PORTS)) << kInvalidPatterns[i].pattern; } }; -TEST(ExtensionURLPatternTest, Colons) { +TEST(ExtensionURLPatternTest, Ports) { const struct { const char* pattern; - URLPattern::ParseResult expected_result; + URLPattern::ParseResult expected_result_error_on_ports; + URLPattern::ParseResult expected_result_ignore_ports; + URLPattern::ParseResult expected_result_use_ports; + const char* expected_host_ignoring_ports; + const char* expected_host_using_ports; + const char* expected_port; } kTestPatterns[] = { - { "http://foo:1234/", URLPattern::PARSE_ERROR_HAS_COLON }, - { "http://foo:1234/bar", URLPattern::PARSE_ERROR_HAS_COLON }, - { "http://*.foo:1234/", URLPattern::PARSE_ERROR_HAS_COLON }, - { "http://*.foo:1234/bar", URLPattern::PARSE_ERROR_HAS_COLON }, - { "http://:1234/", URLPattern::PARSE_ERROR_HAS_COLON }, - { "http://foo:/", URLPattern::PARSE_ERROR_HAS_COLON }, - { "http://*.foo:/", URLPattern::PARSE_ERROR_HAS_COLON }, - { "http://foo:com/", URLPattern::PARSE_ERROR_HAS_COLON }, + { "http://foo:1234/", URLPattern::PARSE_ERROR_HAS_COLON, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, + "foo:1234", "foo", "1234" }, + { "http://foo:1234/bar", URLPattern::PARSE_ERROR_HAS_COLON, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, + "foo:1234", "foo", "1234" }, + { "http://*.foo:1234/", URLPattern::PARSE_ERROR_HAS_COLON, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, + "*.foo:1234", "*.foo", "1234" }, + { "http://*.foo:1234/bar", URLPattern::PARSE_ERROR_HAS_COLON, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, + "*.foo:1234", "*.foo", "1234" }, + { "http://:1234/", URLPattern::PARSE_ERROR_HAS_COLON, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, + ":1234", "", "1234" }, + { "http://foo:/", URLPattern::PARSE_ERROR_HAS_COLON, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_ERROR_INVALID_PORT, + "foo:", "foo", "*" }, + { "http://foo:*/", URLPattern::PARSE_ERROR_HAS_COLON, + URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD, URLPattern::PARSE_SUCCESS, + "foo:*", "foo", "*" }, + { "http://*.foo:/", URLPattern::PARSE_ERROR_HAS_COLON, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_ERROR_INVALID_PORT, + "*.foo:", "*.foo", "*" }, + { "http://foo:com/", URLPattern::PARSE_ERROR_HAS_COLON, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_ERROR_INVALID_PORT, + "foo:com", "", "*" }, + { "http://foo:123456/", URLPattern::PARSE_ERROR_HAS_COLON, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_ERROR_INVALID_PORT, + "foo:123456", "", "*" }, + { "file://foo:1234/bar", URLPattern::PARSE_SUCCESS, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, + "", "", "*" }, + { "chrome://foo:1234/bar", URLPattern::PARSE_ERROR_HAS_COLON, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_ERROR_INVALID_PORT, + "foo:1234", "", "*" }, // Port-like strings in the path should not trigger a warning. - { "http://*/:1234", URLPattern::PARSE_SUCCESS }, - { "http://*.foo/bar:1234", URLPattern::PARSE_SUCCESS }, - { "http://foo/bar:1234/path", URLPattern::PARSE_SUCCESS }, + { "http://*/:1234", URLPattern::PARSE_SUCCESS, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, + "*", "*", "*" }, + { "http://*.foo/bar:1234", URLPattern::PARSE_SUCCESS, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, + "*.foo", "*.foo", "*" }, + { "http://foo/bar:1234/path", URLPattern::PARSE_SUCCESS, + URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, + "foo", "foo", "*" }, }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestPatterns); ++i) { - URLPattern pattern(URLPattern::SCHEME_ALL); - - // Without |strict_error_checks|, expect success. - EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse(kTestPatterns[i].pattern, - URLPattern::PARSE_LENIENT)) - << "Got unexpected error for URL pattern: " + URLPattern use_ports_pattern(URLPattern::SCHEME_ALL); + // Check results with |USE_PORTS|. + EXPECT_EQ(kTestPatterns[i].expected_result_use_ports, + use_ports_pattern.Parse(kTestPatterns[i].pattern, + URLPattern::USE_PORTS)) + << "Got unexpected result for URL pattern: " << kTestPatterns[i].pattern; - - EXPECT_EQ(kTestPatterns[i].expected_result, - pattern.Parse(kTestPatterns[i].pattern, - URLPattern::PARSE_STRICT)) + EXPECT_EQ(kTestPatterns[i].expected_port, use_ports_pattern.port()) + << "Got unexpected port for URL pattern: " << kTestPatterns[i].pattern; + + URLPattern ignore_ports_pattern(URLPattern::SCHEME_ALL); + // Check results with |IGNORE_PORTS|. + EXPECT_EQ(kTestPatterns[i].expected_result_ignore_ports, + ignore_ports_pattern.Parse(kTestPatterns[i].pattern, + URLPattern::IGNORE_PORTS)) + << "Got unexpected result for URL pattern: " + << kTestPatterns[i].pattern; + EXPECT_EQ("*", ignore_ports_pattern.port()) + << "Got unexpected port for URL pattern: " << kTestPatterns[i].pattern; + + URLPattern error_on_ports_pattern(URLPattern::SCHEME_ALL); + // Check results with |ERROR_ON_PORTS|. + EXPECT_EQ(kTestPatterns[i].expected_result_error_on_ports, + error_on_ports_pattern.Parse(kTestPatterns[i].pattern, + URLPattern::ERROR_ON_PORTS)) << "Got unexpected result for URL pattern: " << kTestPatterns[i].pattern; } @@ -85,7 +137,7 @@ TEST(ExtensionURLPatternTest, Colons) { TEST(ExtensionURLPatternTest, Match1) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("http://*/*", URLPattern::PARSE_STRICT)); + pattern.Parse("http://*/*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("http", pattern.scheme()); EXPECT_EQ("", pattern.host()); EXPECT_TRUE(pattern.match_subdomains()); @@ -102,7 +154,7 @@ TEST(ExtensionURLPatternTest, Match1) { TEST(ExtensionURLPatternTest, Match2) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("https://*/foo*", URLPattern::PARSE_STRICT)); + pattern.Parse("https://*/foo*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("https", pattern.scheme()); EXPECT_EQ("", pattern.host()); EXPECT_TRUE(pattern.match_subdomains()); @@ -119,7 +171,7 @@ TEST(URLPatternTest, Match3) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*.google.com/foo*bar", - URLPattern::PARSE_STRICT)); + URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("http", pattern.scheme()); EXPECT_EQ("google.com", pattern.host()); EXPECT_TRUE(pattern.match_subdomains()); @@ -136,7 +188,7 @@ TEST(URLPatternTest, Match3) { TEST(ExtensionURLPatternTest, Match5) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("file:///foo?bar\\*baz", URLPattern::PARSE_STRICT)); + pattern.Parse("file:///foo?bar\\*baz", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("file", pattern.scheme()); EXPECT_EQ("", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); @@ -150,7 +202,7 @@ TEST(ExtensionURLPatternTest, Match5) { TEST(ExtensionURLPatternTest, Match6) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("http://127.0.0.1/*", URLPattern::PARSE_STRICT)); + pattern.Parse("http://127.0.0.1/*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("http", pattern.scheme()); EXPECT_EQ("127.0.0.1", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); @@ -164,7 +216,7 @@ TEST(ExtensionURLPatternTest, Match7) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*.0.0.1/*", - URLPattern::PARSE_STRICT)); // allowed, but useless + URLPattern::ERROR_ON_PORTS)); // allowed, but useless EXPECT_EQ("http", pattern.scheme()); EXPECT_EQ("0.0.1", pattern.host()); EXPECT_TRUE(pattern.match_subdomains()); @@ -181,7 +233,7 @@ TEST(ExtensionURLPatternTest, Match8) { // http://*.\xe1\x80\xbf/a\xc2\x81\xe1* EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*.xn--gkd/a%C2%81%E1*", - URLPattern::PARSE_STRICT)); + URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("http", pattern.scheme()); EXPECT_EQ("xn--gkd", pattern.host()); EXPECT_TRUE(pattern.match_subdomains()); @@ -197,7 +249,7 @@ TEST(ExtensionURLPatternTest, Match8) { TEST(ExtensionURLPatternTest, Match9) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("chrome://favicon/*", URLPattern::PARSE_STRICT)); + pattern.Parse("chrome://favicon/*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("chrome", pattern.scheme()); EXPECT_EQ("favicon", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); @@ -212,7 +264,7 @@ TEST(ExtensionURLPatternTest, Match9) { TEST(ExtensionURLPatternTest, Match10) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("*://*/*", URLPattern::PARSE_STRICT)); + pattern.Parse("*://*/*", URLPattern::ERROR_ON_PORTS)); EXPECT_TRUE(pattern.MatchesScheme("http")); EXPECT_TRUE(pattern.MatchesScheme("https")); EXPECT_FALSE(pattern.MatchesScheme("chrome")); @@ -231,7 +283,7 @@ TEST(ExtensionURLPatternTest, Match10) { TEST(ExtensionURLPatternTest, Match11) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("<all_urls>", URLPattern::PARSE_STRICT)); + pattern.Parse("<all_urls>", URLPattern::ERROR_ON_PORTS)); EXPECT_TRUE(pattern.MatchesScheme("chrome")); EXPECT_TRUE(pattern.MatchesScheme("http")); EXPECT_TRUE(pattern.MatchesScheme("https")); @@ -249,7 +301,7 @@ TEST(ExtensionURLPatternTest, Match11) { TEST(ExtensionURLPatternTest, Match12) { URLPattern pattern(URLPattern::SCHEME_ALL); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("<all_urls>", URLPattern::PARSE_STRICT)); + pattern.Parse("<all_urls>", URLPattern::ERROR_ON_PORTS)); EXPECT_TRUE(pattern.MatchesScheme("chrome")); EXPECT_TRUE(pattern.MatchesScheme("http")); EXPECT_TRUE(pattern.MatchesScheme("https")); @@ -290,7 +342,7 @@ TEST(ExtensionURLPatternTest, Match13) { URLPattern pattern(URLPattern::SCHEME_ALL); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse(kMatch13UrlPatternTestCases[i].pattern, - URLPattern::PARSE_STRICT)) + URLPattern::ERROR_ON_PORTS)) << " while parsing " << kMatch13UrlPatternTestCases[i].pattern; EXPECT_TRUE(pattern.MatchesURL( GURL(kMatch13UrlPatternTestCases[i].matches))) @@ -300,7 +352,7 @@ TEST(ExtensionURLPatternTest, Match13) { // Negative test. URLPattern pattern(URLPattern::SCHEME_ALL); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("data:*", URLPattern::PARSE_STRICT)); + pattern.Parse("data:*", URLPattern::ERROR_ON_PORTS)); EXPECT_FALSE(pattern.MatchesURL(GURL("about:blank"))); }; @@ -308,7 +360,7 @@ TEST(ExtensionURLPatternTest, Match13) { TEST(ExtensionURLPatternTest, Match14) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("file:///foo*", URLPattern::PARSE_STRICT)); + pattern.Parse("file:///foo*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("file", pattern.scheme()); EXPECT_EQ("", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); @@ -325,7 +377,7 @@ TEST(ExtensionURLPatternTest, Match14) { TEST(ExtensionURLPatternTest, Match15) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("file://foo*", URLPattern::PARSE_STRICT)); + pattern.Parse("file://foo*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("file", pattern.scheme()); EXPECT_EQ("", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); @@ -342,7 +394,7 @@ TEST(ExtensionURLPatternTest, Match15) { TEST(ExtensionURLPatternTest, Match16) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("file://localhost/foo*", URLPattern::PARSE_STRICT)); + pattern.Parse("file://localhost/foo*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("file", pattern.scheme()); // Since hostname is ignored for file://. EXPECT_EQ("", pattern.host()); @@ -356,6 +408,40 @@ TEST(ExtensionURLPatternTest, Match16) { EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo"))); } +// Specific port +TEST(ExtensionURLPatternTest, Match17) { + URLPattern pattern(kAllSchemes); + EXPECT_EQ(URLPattern::PARSE_SUCCESS, + pattern.Parse("http://www.example.com:80/foo", + URLPattern::USE_PORTS)); + EXPECT_EQ("http", pattern.scheme()); + EXPECT_EQ("www.example.com", pattern.host()); + EXPECT_FALSE(pattern.match_subdomains()); + EXPECT_FALSE(pattern.match_all_urls()); + EXPECT_EQ("/foo", pattern.path()); + EXPECT_EQ("80", pattern.port()); + EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com:80/foo"))); + EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com/foo"))); + EXPECT_FALSE(pattern.MatchesURL(GURL("http://www.example.com:8080/foo"))); +} + +// Explicit port wildcard +TEST(ExtensionURLPatternTest, Match18) { + URLPattern pattern(kAllSchemes); + EXPECT_EQ(URLPattern::PARSE_SUCCESS, + pattern.Parse("http://www.example.com:*/foo", + URLPattern::USE_PORTS)); + EXPECT_EQ("http", pattern.scheme()); + EXPECT_EQ("www.example.com", pattern.host()); + EXPECT_FALSE(pattern.match_subdomains()); + EXPECT_FALSE(pattern.match_all_urls()); + EXPECT_EQ("/foo", pattern.path()); + EXPECT_EQ("*", pattern.port()); + EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com:80/foo"))); + EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com/foo"))); + EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com:8080/foo"))); +} + static const struct GetAsStringPatterns { const char* pattern; } kGetAsStringTestCases[] = { @@ -371,16 +457,26 @@ static const struct GetAsStringPatterns { { "data:monkey" }, { "javascript:*" }, { "javascript:atemyhomework" }, + { "http://www.example.com:8080/foo" }, }; TEST(ExtensionURLPatternTest, GetAsString) { for (size_t i = 0; i < arraysize(kGetAsStringTestCases); ++i) { - URLPattern pattern(URLPattern::SCHEME_ALL); + URLPattern pattern1(URLPattern::SCHEME_ALL); EXPECT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse(kGetAsStringTestCases[i].pattern, - URLPattern::PARSE_STRICT)); - EXPECT_STREQ(kGetAsStringTestCases[i].pattern, - pattern.GetAsString().c_str()); + pattern1.Parse(kGetAsStringTestCases[i].pattern, + URLPattern::USE_PORTS)) + << "Error parsing " << kGetAsStringTestCases[i].pattern; + EXPECT_EQ(kGetAsStringTestCases[i].pattern, + pattern1.GetAsString()); + URLPattern pattern2(URLPattern::SCHEME_ALL); + + EXPECT_EQ(URLPattern::PARSE_SUCCESS, + pattern2.Parse(kGetAsStringTestCases[i].pattern, + URLPattern::IGNORE_PORTS)) + << "Error parsing " << kGetAsStringTestCases[i].pattern; + EXPECT_EQ(kGetAsStringTestCases[i].pattern, + pattern2.GetAsString()); } } @@ -467,3 +563,20 @@ TEST(ExtensionURLPatternTest, ConvertToExplicitSchemes) { EXPECT_EQ("http://google.com/monkey", monkey[0].GetAsString()); } + +TEST(ExtensionURLPatternTest, IgnorePorts) { + std::string pattern_str = "http://www.example.com:8080/foo"; + GURL url("http://www.example.com:1234/foo"); + + URLPattern pattern1(kAllSchemes); + URLPattern pattern2(kAllSchemes); + EXPECT_EQ(URLPattern::PARSE_SUCCESS, + pattern1.Parse(pattern_str, URLPattern::IGNORE_PORTS)); + EXPECT_EQ(URLPattern::PARSE_SUCCESS, + pattern2.Parse(pattern_str, URLPattern::USE_PORTS)); + + EXPECT_EQ(pattern_str, pattern1.GetAsString()); + EXPECT_EQ(pattern_str, pattern2.GetAsString()); + EXPECT_FALSE(pattern1.MatchesURL(url)); + EXPECT_FALSE(pattern2.MatchesURL(url)); +} diff --git a/chrome/common/extensions/user_script.cc b/chrome/common/extensions/user_script.cc index 91fbb85..17aadbc 100644 --- a/chrome/common/extensions/user_script.cc +++ b/chrome/common/extensions/user_script.cc @@ -193,7 +193,7 @@ void UserScript::Unpickle(const ::Pickle& pickle, void** iter) { if (!had_file_scheme) pattern.set_valid_schemes(valid_schemes | URLPattern::SCHEME_FILE); CHECK(URLPattern::PARSE_SUCCESS == - pattern.Parse(pattern_str, URLPattern::PARSE_LENIENT)); + pattern.Parse(pattern_str, URLPattern::IGNORE_PORTS)); if (!had_file_scheme) pattern.set_valid_schemes(valid_schemes); diff --git a/chrome/common/extensions/user_script_unittest.cc b/chrome/common/extensions/user_script_unittest.cc index 47cec8f..c04e54d 100644 --- a/chrome/common/extensions/user_script_unittest.cc +++ b/chrome/common/extensions/user_script_unittest.cc @@ -73,7 +73,7 @@ TEST(ExtensionUserScriptTest, Glob_StringAnywhere) { TEST(ExtensionUserScriptTest, UrlPattern) { URLPattern pattern(kAllSchemes); ASSERT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("http://*/foo*", URLPattern::PARSE_STRICT)); + pattern.Parse("http://*/foo*", URLPattern::ERROR_ON_PORTS)); UserScript script; script.add_url_pattern(pattern); @@ -88,12 +88,12 @@ TEST(ExtensionUserScriptTest, ExcludeUrlPattern) { URLPattern pattern(kAllSchemes); ASSERT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("http://*.nytimes.com/*", URLPattern::PARSE_STRICT)); + pattern.Parse("http://*.nytimes.com/*", URLPattern::ERROR_ON_PORTS)); script.add_url_pattern(pattern); URLPattern exclude(kAllSchemes); ASSERT_EQ(URLPattern::PARSE_SUCCESS, - exclude.Parse("*://*/*business*", URLPattern::PARSE_STRICT)); + exclude.Parse("*://*/*business*", URLPattern::ERROR_ON_PORTS)); script.add_exclude_url_pattern(exclude); EXPECT_TRUE(script.MatchesURL(GURL("http://www.nytimes.com/health"))); @@ -106,7 +106,7 @@ TEST(ExtensionUserScriptTest, UrlPatternAndIncludeGlobs) { URLPattern pattern(kAllSchemes); ASSERT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("http://*.nytimes.com/*", URLPattern::PARSE_STRICT)); + pattern.Parse("http://*.nytimes.com/*", URLPattern::ERROR_ON_PORTS)); script.add_url_pattern(pattern); script.add_glob("*nytimes.com/???s/*"); @@ -121,7 +121,7 @@ TEST(ExtensionUserScriptTest, UrlPatternAndExcludeGlobs) { URLPattern pattern(kAllSchemes); ASSERT_EQ(URLPattern::PARSE_SUCCESS, - pattern.Parse("http://*.nytimes.com/*", URLPattern::PARSE_STRICT)); + pattern.Parse("http://*.nytimes.com/*", URLPattern::ERROR_ON_PORTS)); script.add_url_pattern(pattern); script.add_exclude_glob("*science*"); @@ -138,7 +138,7 @@ TEST(ExtensionUserScriptTest, UrlPatternGlobInteraction) { URLPattern pattern(kAllSchemes); ASSERT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://www.google.com/*", - URLPattern::PARSE_STRICT)); + URLPattern::ERROR_ON_PORTS)); script.add_url_pattern(pattern); script.add_glob("*bar*"); @@ -167,9 +167,9 @@ TEST(ExtensionUserScriptTest, Pickle) { URLPattern pattern1(kAllSchemes); URLPattern pattern2(kAllSchemes); ASSERT_EQ(URLPattern::PARSE_SUCCESS, - pattern1.Parse("http://*/foo*", URLPattern::PARSE_STRICT)); + pattern1.Parse("http://*/foo*", URLPattern::ERROR_ON_PORTS)); ASSERT_EQ(URLPattern::PARSE_SUCCESS, - pattern2.Parse("http://bar/baz*", URLPattern::PARSE_STRICT)); + pattern2.Parse("http://bar/baz*", URLPattern::ERROR_ON_PORTS)); UserScript script1; script1.js_scripts().push_back(UserScript::File( diff --git a/chrome/test/data/extensions/api_test/content_settings/standard/test.html b/chrome/test/data/extensions/api_test/content_settings/standard/test.html index 3a4149e..99f47df 100644 --- a/chrome/test/data/extensions/api_test/content_settings/standard/test.html +++ b/chrome/test/data/extensions/api_test/content_settings/standard/test.html @@ -65,8 +65,8 @@ chrome.test.runTests([ function setDefaultContentSettings() { default_content_settings.forEach(function(type, setting) { cs[type].set({ - 'topLevelPattern': {'pattern': '*'}, - 'embeddedPattern': {'pattern': '*'}, + 'topLevelPattern': '<all_urls>', + 'embeddedPattern': '<all_urls>', 'setting': setting }, chrome.test.callbackPass()); }); @@ -74,8 +74,8 @@ chrome.test.runTests([ function setContentSettings() { settings.forEach(function(type, setting) { cs[type].set({ - 'topLevelPattern': {'pattern': '[*.]google.com'}, - 'embeddedPattern': {'pattern': '[*.]google.com'}, + 'topLevelPattern': 'http://*.google.com/*', + 'embeddedPattern': 'http://*.google.com/*', 'setting': setting }, chrome.test.callbackPass()); }); @@ -94,6 +94,16 @@ chrome.test.runTests([ 'topLevelUrl': '', 'embeddedUrl': 'moo' }, chrome.test.callbackFail("The URL \"moo\" is invalid.")); + cs.plugins.set({ + 'topLevelPattern': 'http://example.com/*', + 'embeddedPattern': 'http://example.com/path', + 'setting': 'block' + }, chrome.test.callbackFail("Specific paths are not allowed.")); + cs.javascript.set({ + 'topLevelPattern': 'http://example.com/*', + 'embeddedPattern': 'file:///home/hansmoleman/*', + 'setting': 'allow' + }, chrome.test.callbackFail("Path wildcards in file URL patterns are not allowed.")); } ]); </script> |