Bug 1312690: Speed up MatchPattern matching. r?aswan
MozReview-Commit-ID: 2QmKnG0aBQw
--- a/toolkit/modules/addons/MatchPattern.jsm
+++ b/toolkit/modules/addons/MatchPattern.jsm
@@ -36,70 +36,69 @@ function globToRegexp(pat, allowQuestion
return new RegExp("^" + pat + "$");
}
// These patterns follow the syntax in
// https://developer.chrome.com/extensions/match_patterns
function SingleMatchPattern(pat) {
if (pat == "<all_urls>") {
this.schemes = PERMITTED_SCHEMES;
- this.host = "*";
- this.path = new RegExp(".*");
+ this.hostMatch = () => true;
+ this.pathMatch = () => true;
} else if (!pat) {
this.schemes = [];
} else {
let re = new RegExp(`^(${PERMITTED_SCHEMES_REGEXP}|\\*)://(\\*|\\*\\.[^*/]+|[^*/]+|)(/.*)$`);
let match = re.exec(pat);
if (!match) {
Cu.reportError(`Invalid match pattern: '${pat}'`);
this.schemes = [];
return;
}
if (match[1] == "*") {
this.schemes = ["http", "https"];
} else {
this.schemes = [match[1]];
}
- this.host = match[2];
- this.path = globToRegexp(match[3], false);
// We allow the host to be empty for file URLs.
- if (this.host == "" && this.schemes[0] != "file") {
+ if (match[2] == "" && this.schemes[0] != "file") {
Cu.reportError(`Invalid match pattern: '${pat}'`);
this.schemes = [];
return;
}
+
+ this.host = match[2];
+ this.hostMatch = this.getHostMatcher(match[2]);
+
+ let pathMatch = globToRegexp(match[3], false);
+ this.pathMatch = pathMatch.test.bind(pathMatch);
}
}
SingleMatchPattern.prototype = {
- matches(uri, ignorePath = false) {
- if (!this.schemes.includes(uri.scheme)) {
- return false;
- }
-
+ getHostMatcher(host) {
// This code ignores the port, as Chrome does.
- if (this.host == "*") {
- // Don't check anything.
- } else if (this.host[0] == "*") {
- // It must be *.foo. We also need to allow foo by itself.
- let suffix = this.host.substr(2);
- if (uri.host != suffix && !uri.host.endsWith("." + suffix)) {
- return false;
- }
- } else if (this.host != uri.host) {
- return false;
+ if (host == "*") {
+ return () => true;
}
+ if (host.startsWith("*.")) {
+ let suffix = host.substr(2);
+ let dotSuffix = "." + suffix;
- if (!ignorePath && !this.path.test(uri.path)) {
- return false;
+ return ({host}) => host === suffix || host.endsWith(dotSuffix);
}
+ return uri => uri.host === host;
+ },
- return true;
+ matches(uri, ignorePath = false) {
+ return (this.schemes.includes(uri.scheme) &&
+ this.hostMatch(uri) &&
+ (ignorePath || this.pathMatch(uri.path)));
},
};
this.MatchPattern = function(pat) {
this.pat = pat;
if (!pat) {
this.matchers = [];
} else if (pat instanceof String || typeof(pat) == "string") {
@@ -107,31 +106,21 @@ this.MatchPattern = function(pat) {
} else {
this.matchers = pat.map(p => new SingleMatchPattern(p));
}
};
MatchPattern.prototype = {
// |uri| should be an nsIURI.
matches(uri) {
- for (let matcher of this.matchers) {
- if (matcher.matches(uri)) {
- return true;
- }
- }
- return false;
+ return this.matchers.some(matcher => matcher.matches(uri));
},
matchesIgnoringPath(uri) {
- for (let matcher of this.matchers) {
- if (matcher.matches(uri, true)) {
- return true;
- }
- }
- return false;
+ return this.matchers.some(matcher => matcher.matches(uri, true));
},
// Checks that this match pattern grants access to read the given
// cookie. |cookie| should be an |nsICookie2| instance.
matchesCookie(cookie) {
// First check for simple matches.
let secureURI = NetUtil.newURI(`https://${cookie.rawHost}/`);
if (this.matchesIgnoringPath(secureURI)) {