summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorbauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-30 08:47:58 +0000
committerbauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-30 08:47:58 +0000
commit188827c86eca6fa38e6cef5ac9852a26826a658a (patch)
tree68d51db12b35ee9fb4653edd45594dcc28ae19b2 /chrome
parentadf46b69ad590589a13477f2b8ddce9d071e92a9 (diff)
downloadchromium_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
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/extension_content_settings_api.cc30
-rw-r--r--chrome/browser/extensions/extension_content_settings_helpers.cc75
-rw-r--r--chrome/browser/extensions/extension_content_settings_helpers.h9
-rw-r--r--chrome/browser/extensions/extension_content_settings_unittest.cc51
-rw-r--r--chrome/browser/extensions/extension_context_menu_api.cc2
-rw-r--r--chrome/browser/extensions/extension_prefs.cc2
-rw-r--r--chrome/browser/extensions/extension_webrequest_api.cc2
-rw-r--r--chrome/browser/extensions/user_script_master.cc2
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu_unittest.cc2
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/extensions/api/extension_api.json26
-rw-r--r--chrome/common/extensions/docs/examples/api/contentSettings.zipbin12584 -> 12278 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/contentSettings/popup.html15
-rw-r--r--chrome/common/extensions/docs/experimental.contentSettings.html187
-rw-r--r--chrome/common/extensions/docs/samples.json2
-rw-r--r--chrome/common/extensions/extension.cc14
-rw-r--r--chrome/common/extensions/extension_messages.cc2
-rw-r--r--chrome/common/extensions/url_pattern.cc99
-rw-r--r--chrome/common/extensions/url_pattern.h28
-rw-r--r--chrome/common/extensions/url_pattern_unittest.cc205
-rw-r--r--chrome/common/extensions/user_script.cc2
-rw-r--r--chrome/common/extensions/user_script_unittest.cc16
-rw-r--r--chrome/test/data/extensions/api_test/content_settings/standard/test.html18
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
index d10841d..38a2a2a 100644
--- a/chrome/common/extensions/docs/examples/api/contentSettings.zip
+++ b/chrome/common/extensions/docs/examples/api/contentSettings.zip
Binary files differ
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>