[DNR] Add isRegexSupported API call
Add the isRegexSupported extension function which provides extension developers with a way to check that a given regular expression can be used as a regexFilter rule condition. Skipping presubmit since this seems to be hitting crbug.com/956368. R=karandeepb@chromium.org, kelvinjiang@chromium.org Bug: 1088457 No-Presubmit: True Change-Id: Ic51df5dd096806472f25e4053a020c0a08368179 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2372465 Commit-Queue: Karan Bhatia <karandeepb@chromium.org> Reviewed-by: Karan Bhatia <karandeepb@chromium.org> Cr-Commit-Position: refs/heads/master@{#808574}
This commit is contained in:
AUTHORS
chrome
browser
extensions
api
declarative_net_request
test
data
extensions
api_test
declarative_net_request
is_regex_supported
extensions
tools/metrics/histograms
2
AUTHORS
2
AUTHORS
@@ -232,7 +232,7 @@ Daniel Waxweiler <daniel.waxweiler@gmail.com>
|
|||||||
Dániel Bátyai <dbatyai@inf.u-szeged.hu>
|
Dániel Bátyai <dbatyai@inf.u-szeged.hu>
|
||||||
Dániel Vince <vinced@inf.u-szeged.hu>
|
Dániel Vince <vinced@inf.u-szeged.hu>
|
||||||
Darshini KN <kn.darshini@samsung.com>
|
Darshini KN <kn.darshini@samsung.com>
|
||||||
Dave Barker <kzar@kzar.co.uk>
|
Dave Vandyke <kzar@kzar.co.uk>
|
||||||
David Benjamin <davidben@mit.edu>
|
David Benjamin <davidben@mit.edu>
|
||||||
David Davidovic <david@davidovic.io>
|
David Davidovic <david@davidovic.io>
|
||||||
David Erceg <erceg.david@gmail.com>
|
David Erceg <erceg.david@gmail.com>
|
||||||
|
@@ -98,4 +98,8 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestLazyAPItest, GetMatchedRules) {
|
|||||||
ASSERT_TRUE(RunTest("get_matched_rules")) << message_;
|
ASSERT_TRUE(RunTest("get_matched_rules")) << message_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestLazyAPItest, IsRegexSupported) {
|
||||||
|
ASSERT_TRUE(RunTest("is_regex_supported")) << message_;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
54
chrome/test/data/extensions/api_test/declarative_net_request/is_regex_supported/background.js
Normal file
54
chrome/test/data/extensions/api_test/declarative_net_request/is_regex_supported/background.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2020 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.
|
||||||
|
|
||||||
|
function isRegexSupported(regexOptions) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
chrome.declarativeNetRequest.isRegexSupported(regexOptions, resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.test.runTests([
|
||||||
|
async function testSupportedRegex() {
|
||||||
|
let result = await isRegexSupported({regex: '[0-9]+'});
|
||||||
|
chrome.test.assertEq(result, {isSupported: true});
|
||||||
|
chrome.test.succeed();
|
||||||
|
},
|
||||||
|
|
||||||
|
async function testSupportedRegexWithOptions() {
|
||||||
|
let result = await isRegexSupported(
|
||||||
|
{regex: '[0-9]+', isCaseSensitive: false, requireCapturing: true});
|
||||||
|
chrome.test.assertEq(result, {isSupported: true});
|
||||||
|
chrome.test.succeed();
|
||||||
|
},
|
||||||
|
|
||||||
|
async function testInvalidRegex() {
|
||||||
|
let result = await isRegexSupported({regex: '[a-9]+'});
|
||||||
|
chrome.test.assertEq(result, {isSupported: false, reason: 'syntaxError'});
|
||||||
|
chrome.test.succeed();
|
||||||
|
},
|
||||||
|
|
||||||
|
async function testInvalidRegexWithOptions() {
|
||||||
|
let result = await isRegexSupported(
|
||||||
|
{regex: '[a-9]+', isCaseSensitive: false, requireCapturing: true});
|
||||||
|
chrome.test.assertEq(result, {isSupported: false, reason: 'syntaxError'});
|
||||||
|
chrome.test.succeed();
|
||||||
|
},
|
||||||
|
|
||||||
|
async function testMemoryError() {
|
||||||
|
let result = await isRegexSupported({regex: '[0-9]+'.repeat(1000)});
|
||||||
|
chrome.test.assertEq(
|
||||||
|
result, {isSupported: false, reason: 'memoryLimitExceeded'});
|
||||||
|
chrome.test.succeed();
|
||||||
|
},
|
||||||
|
|
||||||
|
async function testMemoryErrorWithOptions() {
|
||||||
|
let regex = '(a)'.repeat(50);
|
||||||
|
let result = await isRegexSupported({regex});
|
||||||
|
chrome.test.assertEq(result, {isSupported: true});
|
||||||
|
result = await isRegexSupported({regex, requireCapturing: true});
|
||||||
|
chrome.test.assertEq(
|
||||||
|
result, {isSupported: false, reason: 'memoryLimitExceeded'});
|
||||||
|
chrome.test.succeed();
|
||||||
|
}
|
||||||
|
]);
|
14
chrome/test/data/extensions/api_test/declarative_net_request/is_regex_supported/manifest.json
Normal file
14
chrome/test/data/extensions/api_test/declarative_net_request/is_regex_supported/manifest.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "Test extension",
|
||||||
|
"manifest_version": 2,
|
||||||
|
"permissions": [
|
||||||
|
"declarativeNetRequest"
|
||||||
|
],
|
||||||
|
"version": "1.0",
|
||||||
|
"background": {
|
||||||
|
"scripts": [
|
||||||
|
"background.js"
|
||||||
|
],
|
||||||
|
"persistent": false
|
||||||
|
}
|
||||||
|
}
|
@@ -354,4 +354,42 @@ DeclarativeNetRequestSetActionCountAsBadgeTextFunction::Run() {
|
|||||||
return RespondNow(NoArguments());
|
return RespondNow(NoArguments());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeclarativeNetRequestIsRegexSupportedFunction::
|
||||||
|
DeclarativeNetRequestIsRegexSupportedFunction() = default;
|
||||||
|
DeclarativeNetRequestIsRegexSupportedFunction::
|
||||||
|
~DeclarativeNetRequestIsRegexSupportedFunction() = default;
|
||||||
|
|
||||||
|
ExtensionFunction::ResponseAction
|
||||||
|
DeclarativeNetRequestIsRegexSupportedFunction::Run() {
|
||||||
|
using Params = dnr_api::IsRegexSupported::Params;
|
||||||
|
|
||||||
|
base::string16 error;
|
||||||
|
std::unique_ptr<Params> params(Params::Create(*args_, &error));
|
||||||
|
EXTENSION_FUNCTION_VALIDATE(params);
|
||||||
|
EXTENSION_FUNCTION_VALIDATE(error.empty());
|
||||||
|
|
||||||
|
bool is_case_sensitive = params->regex_options.is_case_sensitive
|
||||||
|
? *params->regex_options.is_case_sensitive
|
||||||
|
: true;
|
||||||
|
bool require_capturing = params->regex_options.require_capturing
|
||||||
|
? *params->regex_options.require_capturing
|
||||||
|
: false;
|
||||||
|
re2::RE2 regex(params->regex_options.regex,
|
||||||
|
declarative_net_request::CreateRE2Options(is_case_sensitive,
|
||||||
|
require_capturing));
|
||||||
|
|
||||||
|
dnr_api::IsRegexSupportedResult result;
|
||||||
|
if (regex.ok()) {
|
||||||
|
result.is_supported = true;
|
||||||
|
} else {
|
||||||
|
result.is_supported = false;
|
||||||
|
result.reason = regex.error_code() == re2::RE2::ErrorPatternTooLarge
|
||||||
|
? dnr_api::UNSUPPORTED_REGEX_REASON_MEMORYLIMITEXCEEDED
|
||||||
|
: dnr_api::UNSUPPORTED_REGEX_REASON_SYNTAXERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RespondNow(
|
||||||
|
ArgumentList(dnr_api::IsRegexSupported::Results::Create(result)));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace extensions
|
} // namespace extensions
|
||||||
|
@@ -118,6 +118,19 @@ class DeclarativeNetRequestSetActionCountAsBadgeTextFunction
|
|||||||
ExtensionFunction::ResponseAction Run() override;
|
ExtensionFunction::ResponseAction Run() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DeclarativeNetRequestIsRegexSupportedFunction : public ExtensionFunction {
|
||||||
|
public:
|
||||||
|
DeclarativeNetRequestIsRegexSupportedFunction();
|
||||||
|
DECLARE_EXTENSION_FUNCTION("declarativeNetRequest.isRegexSupported",
|
||||||
|
DECLARATIVENETREQUEST_ISREGEXSUPPORTED)
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~DeclarativeNetRequestIsRegexSupportedFunction() override;
|
||||||
|
|
||||||
|
// ExtensionFunction override:
|
||||||
|
ExtensionFunction::ResponseAction Run() override;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace extensions
|
} // namespace extensions
|
||||||
|
|
||||||
#endif // EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_DECLARATIVE_NET_REQUEST_API_H_
|
#endif // EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_DECLARATIVE_NET_REQUEST_API_H_
|
||||||
|
@@ -1568,6 +1568,7 @@ enum HistogramValue {
|
|||||||
INPUTMETHODPRIVATE_SETCOMPOSINGRANGE = 1505,
|
INPUTMETHODPRIVATE_SETCOMPOSINGRANGE = 1505,
|
||||||
AUTOTESTPRIVATE_LAUNCHSYSTEMWEBAPP = 1506,
|
AUTOTESTPRIVATE_LAUNCHSYSTEMWEBAPP = 1506,
|
||||||
ACCESSIBILITY_PRIVATE_PERFORMACCELERATORACTION = 1507,
|
ACCESSIBILITY_PRIVATE_PERFORMACCELERATORACTION = 1507,
|
||||||
|
DECLARATIVENETREQUEST_ISREGEXSUPPORTED = 1508,
|
||||||
// Last entry: Add new entries above, then run:
|
// Last entry: Add new entries above, then run:
|
||||||
// python tools/metrics/histograms/update_extension_histograms.py
|
// python tools/metrics/histograms/update_extension_histograms.py
|
||||||
ENUM_BOUNDARY
|
ENUM_BOUNDARY
|
||||||
|
@@ -66,6 +66,16 @@ namespace declarativeNetRequest {
|
|||||||
allowAllRequests
|
allowAllRequests
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Describes the reason why a given regular expression isn't supported.
|
||||||
|
enum UnsupportedRegexReason {
|
||||||
|
// The regular expression is syntactically incorrect, or uses features
|
||||||
|
// not available in the
|
||||||
|
// <a href = "https://github.com/google/re2/wiki/Syntax">RE2 syntax</a>.
|
||||||
|
syntaxError,
|
||||||
|
// The regular expression exceeds the memory limit.
|
||||||
|
memoryLimitExceeded
|
||||||
|
};
|
||||||
|
|
||||||
// Describes a single static ruleset.
|
// Describes a single static ruleset.
|
||||||
dictionary Ruleset {
|
dictionary Ruleset {
|
||||||
// A non-empty string uniquely identifying the ruleset. IDs beginning with
|
// A non-empty string uniquely identifying the ruleset. IDs beginning with
|
||||||
@@ -379,11 +389,34 @@ namespace declarativeNetRequest {
|
|||||||
DNRInfo declarative_net_request;
|
DNRInfo declarative_net_request;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dictionary RegexOptions {
|
||||||
|
// The regular expresson to check.
|
||||||
|
DOMString regex;
|
||||||
|
|
||||||
|
// Whether the <code>regex</code> specified is case sensitive. Default is
|
||||||
|
// true.
|
||||||
|
boolean? isCaseSensitive;
|
||||||
|
|
||||||
|
// Whether the <code>regex</code> specified requires capturing. Capturing is
|
||||||
|
// only required for redirect rules which specify a
|
||||||
|
// <code>regexSubstition</code> action. The default is false.
|
||||||
|
boolean? requireCapturing;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary IsRegexSupportedResult {
|
||||||
|
boolean isSupported;
|
||||||
|
|
||||||
|
// Specifies the reason why the regular expression is not supported. Only
|
||||||
|
// provided if <code>isSupported</code> is false.
|
||||||
|
UnsupportedRegexReason? reason;
|
||||||
|
};
|
||||||
|
|
||||||
callback EmptyCallback = void();
|
callback EmptyCallback = void();
|
||||||
callback GetAllowedPagesCallback = void(DOMString[] result);
|
callback GetAllowedPagesCallback = void(DOMString[] result);
|
||||||
callback GetRulesCallback = void(Rule[] rules);
|
callback GetRulesCallback = void(Rule[] rules);
|
||||||
callback GetMatchedRulesCallback = void(RulesMatchedDetails details);
|
callback GetMatchedRulesCallback = void(RulesMatchedDetails details);
|
||||||
callback GetEnabledRulesetsCallback = void(DOMString[] rulesetIds);
|
callback GetEnabledRulesetsCallback = void(DOMString[] rulesetIds);
|
||||||
|
callback IsRegexSupportedCallback = void(IsRegexSupportedResult result);
|
||||||
|
|
||||||
interface Functions {
|
interface Functions {
|
||||||
|
|
||||||
@@ -460,6 +493,14 @@ namespace declarativeNetRequest {
|
|||||||
// action count for a tab. This preference is persisted across sessions and
|
// action count for a tab. This preference is persisted across sessions and
|
||||||
// is false by default.
|
// is false by default.
|
||||||
static void setActionCountAsBadgeText(boolean enable);
|
static void setActionCountAsBadgeText(boolean enable);
|
||||||
|
|
||||||
|
// Checks if the given regular expression will be supported as a
|
||||||
|
// <code>regexFilter</code> rule condition.
|
||||||
|
// |regexOptions|: The regular expression to check.
|
||||||
|
// |callback|: Called with details consisting of whether the regular
|
||||||
|
// expression is supported and the reason if not.
|
||||||
|
static void isRegexSupported(RegexOptions regexOptions,
|
||||||
|
IsRegexSupportedCallback callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Properties {
|
interface Properties {
|
||||||
|
@@ -24569,6 +24569,7 @@ Called by update_extension_histograms.py.-->
|
|||||||
<int value="1505" label="INPUTMETHODPRIVATE_SETCOMPOSINGRANGE"/>
|
<int value="1505" label="INPUTMETHODPRIVATE_SETCOMPOSINGRANGE"/>
|
||||||
<int value="1506" label="AUTOTESTPRIVATE_LAUNCHSYSTEMWEBAPP"/>
|
<int value="1506" label="AUTOTESTPRIVATE_LAUNCHSYSTEMWEBAPP"/>
|
||||||
<int value="1507" label="ACCESSIBILITY_PRIVATE_PERFORMACCELERATORACTION"/>
|
<int value="1507" label="ACCESSIBILITY_PRIVATE_PERFORMACCELERATORACTION"/>
|
||||||
|
<int value="1508" label="DECLARATIVENETREQUEST_ISREGEXSUPPORTED"/>
|
||||||
</enum>
|
</enum>
|
||||||
|
|
||||||
<enum name="ExtensionIconState">
|
<enum name="ExtensionIconState">
|
||||||
|
Reference in New Issue
Block a user