зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1368102: Part 4 - Use WebExtensionContentScript to match content scripts. r=mixedpuppy,zombie
MozReview-Commit-ID: 1Ga0259WjC --HG-- extra : rebase_source : 2768c37e1ed594d293d892c0fb8f9b346508a41d
This commit is contained in:
Родитель
cc9c553d7c
Коммит
884bb014cb
|
@ -196,27 +196,27 @@ defineLazyGetter(BrowserExtensionContent.prototype, "authorCSS", () => {
|
|||
|
||||
// Represents a content script.
|
||||
class Script {
|
||||
constructor(extension, options) {
|
||||
constructor(extension, matcher) {
|
||||
this.extension = extension;
|
||||
this.options = options;
|
||||
this.matcher = matcher;
|
||||
|
||||
this.runAt = this.options.run_at;
|
||||
this.js = this.options.js || [];
|
||||
this.css = this.options.css || [];
|
||||
this.remove_css = this.options.remove_css;
|
||||
this.css_origin = this.options.css_origin;
|
||||
this.runAt = this.matcher.runAt;
|
||||
this.js = this.matcher.jsPaths;
|
||||
this.css = this.matcher.cssPaths;
|
||||
this.removeCSS = this.matcher.removeCSS;
|
||||
this.cssOrigin = this.matcher.cssOrigin;
|
||||
|
||||
this.cssCache = extension[this.css_origin === "user" ? "userCSS"
|
||||
: "authorCSS"];
|
||||
this.scriptCache = extension[options.wantReturnValue ? "dynamicScripts"
|
||||
this.cssCache = extension[this.cssOrigin === "user" ? "userCSS"
|
||||
: "authorCSS"];
|
||||
this.scriptCache = extension[matcher.wantReturnValue ? "dynamicScripts"
|
||||
: "staticScripts"];
|
||||
|
||||
if (options.wantReturnValue) {
|
||||
if (matcher.wantReturnValue) {
|
||||
this.compileScripts();
|
||||
this.loadCSS();
|
||||
}
|
||||
|
||||
this.requiresCleanup = !this.remove_css && (this.css.length > 0 || options.cssCode);
|
||||
this.requiresCleanup = !this.removeCss && (this.css.length > 0 || matcher.cssCode);
|
||||
}
|
||||
|
||||
compileScripts() {
|
||||
|
@ -228,10 +228,10 @@ class Script {
|
|||
}
|
||||
|
||||
cleanup(window) {
|
||||
if (!this.remove_css && this.cssURLs.length) {
|
||||
if (!this.removeCss && this.cssURLs.length) {
|
||||
let winUtils = getWinUtils(window);
|
||||
|
||||
let type = this.css_origin === "user" ? winUtils.USER_SHEET : winUtils.AUTHOR_SHEET;
|
||||
let type = this.cssOrigin === "user" ? winUtils.USER_SHEET : winUtils.AUTHOR_SHEET;
|
||||
for (let url of this.cssURLs) {
|
||||
this.cssCache.deleteDocument(url, window.document);
|
||||
runSafeSyncWithoutClone(winUtils.removeSheetUsingURIString, url, type);
|
||||
|
@ -276,9 +276,9 @@ class Script {
|
|||
let window = context.contentWindow;
|
||||
let winUtils = getWinUtils(window);
|
||||
|
||||
let type = this.css_origin === "user" ? winUtils.USER_SHEET : winUtils.AUTHOR_SHEET;
|
||||
let type = this.cssOrigin === "user" ? winUtils.USER_SHEET : winUtils.AUTHOR_SHEET;
|
||||
|
||||
if (this.remove_css) {
|
||||
if (this.removeCSS) {
|
||||
for (let url of this.cssURLs) {
|
||||
this.cssCache.deleteDocument(url, window.document);
|
||||
|
||||
|
@ -325,8 +325,8 @@ class Script {
|
|||
result = script.executeInGlobal(context.cloneScope);
|
||||
}
|
||||
|
||||
if (this.options.jsCode) {
|
||||
result = Cu.evalInSandbox(this.options.jsCode, context.cloneScope, "latest");
|
||||
if (this.matcher.jsCode) {
|
||||
result = Cu.evalInSandbox(this.matcher.jsCode, context.cloneScope, "latest");
|
||||
}
|
||||
|
||||
await cssPromise;
|
||||
|
@ -338,8 +338,8 @@ defineLazyGetter(Script.prototype, "cssURLs", function() {
|
|||
// We can handle CSS urls (css) and CSS code (cssCode).
|
||||
let urls = this.css.slice();
|
||||
|
||||
if (this.options.cssCode) {
|
||||
urls.push("data:text/css;charset=utf-8," + encodeURIComponent(this.options.cssCode));
|
||||
if (this.matcher.cssCode) {
|
||||
urls.push("data:text/css;charset=utf-8," + encodeURIComponent(this.matcher.cssCode));
|
||||
}
|
||||
|
||||
return urls;
|
||||
|
|
|
@ -30,6 +30,23 @@ const isParentProcess = appinfo.processType === appinfo.PROCESS_TYPE_DEFAULT;
|
|||
* when no extensions are running.
|
||||
*/
|
||||
|
||||
function parseScriptOptions(options) {
|
||||
return {
|
||||
allFrames: options.all_frames,
|
||||
matchAboutBlank: options.match_about_blank,
|
||||
frameID: options.frame_id,
|
||||
runAt: options.run_at,
|
||||
|
||||
matches: new MatchPatternSet(options.matches),
|
||||
excludeMatches: new MatchPatternSet(options.exclude_matches || []),
|
||||
includeGlobs: options.include_globs && options.include_globs.map(glob => new MatchGlob(glob)),
|
||||
excludeGlobs: options.include_globs && options.exclude_globs.map(glob => new MatchGlob(glob)),
|
||||
|
||||
jsPaths: options.js || [],
|
||||
cssPaths: options.css || [],
|
||||
};
|
||||
}
|
||||
|
||||
var APIs = {
|
||||
apis: new Map(),
|
||||
|
||||
|
@ -94,6 +111,8 @@ var ExtensionManagement = {
|
|||
|
||||
backgroundScripts: (extension.manifest.background &&
|
||||
extension.manifest.background.scripts),
|
||||
|
||||
contentScripts: (extension.manifest.content_scripts || []).map(parseScriptOptions),
|
||||
});
|
||||
|
||||
extension.policy = policy;
|
||||
|
|
|
@ -353,11 +353,16 @@ WebExtensionContentScript::Matches(const DocInfo& aDoc) const
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!MatchesURI(aDoc.PrincipalURL())) {
|
||||
return false;
|
||||
// Top-level about:blank is a special case. We treat it as a match if
|
||||
// matchAboutBlank is true and it has the null principal. In all other
|
||||
// cases, we test the URL of the principal that it inherits.
|
||||
if (mMatchAboutBlank && aDoc.IsTopLevel() &&
|
||||
aDoc.URL().Spec().EqualsLiteral("about:blank") &&
|
||||
aDoc.Principal()->GetIsNullPrincipal()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return MatchesURI(aDoc.PrincipalURL());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -445,8 +450,8 @@ DocInfo::FrameID() const
|
|||
} else {
|
||||
struct Matcher
|
||||
{
|
||||
uint64_t match(Window aWin) { return aWin->GetCurrentInnerWindow()->WindowID(); }
|
||||
uint64_t match(LoadInfo aLoadInfo) { return aLoadInfo->GetInnerWindowID(); }
|
||||
uint64_t match(Window aWin) { return aWin->WindowID(); }
|
||||
uint64_t match(LoadInfo aLoadInfo) { return aLoadInfo->GetOuterWindowID(); }
|
||||
};
|
||||
mFrameID.emplace(mObj.match(Matcher()));
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
|
|||
"resource://gre/modules/ExtensionManagement.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
|
||||
"resource://gre/modules/MessageChannel.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WebNavigationFrames",
|
||||
"resource://gre/modules/WebNavigationFrames.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionChild",
|
||||
"resource://gre/modules/ExtensionChild.jsm");
|
||||
|
@ -39,33 +37,39 @@ XPCOMUtils.defineLazyGetter(this, "getInnerWindowID", () => ExtensionUtils.getIn
|
|||
const appinfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
|
||||
const isContentProcess = appinfo.processType == appinfo.PROCESS_TYPE_CONTENT;
|
||||
|
||||
function parseScriptOptions(options) {
|
||||
return {
|
||||
allFrames: options.all_frames,
|
||||
matchAboutBlank: options.match_about_blank,
|
||||
frameID: options.frame_id,
|
||||
runAt: options.run_at,
|
||||
|
||||
matches: new MatchPatternSet(options.matches),
|
||||
excludeMatches: new MatchPatternSet(options.exclude_matches || []),
|
||||
includeGlobs: options.include_globs && options.include_globs.map(glob => new MatchGlob(glob)),
|
||||
excludeGlobs: options.exclude_globs && options.exclude_globs.map(glob => new MatchGlob(glob)),
|
||||
|
||||
jsPaths: options.js || [],
|
||||
cssPaths: options.css || [],
|
||||
};
|
||||
}
|
||||
|
||||
class ScriptMatcher {
|
||||
constructor(extension, options) {
|
||||
constructor(extension, matcher) {
|
||||
this.extension = extension;
|
||||
this.options = options;
|
||||
this.matcher = matcher;
|
||||
|
||||
this._script = null;
|
||||
|
||||
this.allFrames = options.all_frames;
|
||||
this.matchAboutBlank = options.match_about_blank;
|
||||
this.frameId = options.frame_id;
|
||||
this.runAt = options.run_at;
|
||||
|
||||
this.matches = new MatchPatternSet(options.matches);
|
||||
this.excludeMatches = new MatchPatternSet(options.exclude_matches || []);
|
||||
this.includeGlobs = options.include_globs && options.include_globs.map(glob => new MatchGlob(glob));
|
||||
this.excludeGlobs = options.include_globs && options.exclude_globs.map(glob => new MatchGlob(glob));
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `[Script {js: [${this.options.js}], matchAboutBlank: ${this.matchAboutBlank}, runAt: ${this.runAt}, matches: ${this.options.matches}}]`;
|
||||
get matchAboutBlank() {
|
||||
return this.matcher.matchAboutBlank;
|
||||
}
|
||||
|
||||
get script() {
|
||||
if (!this._script) {
|
||||
this._script = new ExtensionContent.Script(this.extension.realExtension,
|
||||
this.options);
|
||||
this.matcher);
|
||||
}
|
||||
return this._script;
|
||||
}
|
||||
|
@ -78,82 +82,11 @@ class ScriptMatcher {
|
|||
}
|
||||
|
||||
matchesLoadInfo(uri, loadInfo) {
|
||||
if (!this.matchesURI(uri)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.allFrames && !loadInfo.isTopLevelLoad) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
matchesURI(uri) {
|
||||
if (!(this.matches.matches(uri))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.excludeMatches.matches(uri)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.includeGlobs && !this.includeGlobs.some(glob => glob.matches(uri.spec))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.excludeGlobs && this.excludeGlobs.some(glob => glob.matches(uri.spec))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return this.matcher.matchesLoadInfo(uri, loadInfo);
|
||||
}
|
||||
|
||||
matchesWindow(window) {
|
||||
if (!this.allFrames && this.frameId == null && window.parent !== window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let uri = window.document.documentURIObject;
|
||||
let principal = window.document.nodePrincipal;
|
||||
|
||||
if (this.matchAboutBlank) {
|
||||
// When matching top-level about:blank documents,
|
||||
// allow loading into any with a NullPrincipal.
|
||||
if (uri.spec === "about:blank" && window === window.parent && principal.isNullPrincipal) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// When matching about:blank/srcdoc iframes, the checks below
|
||||
// need to be performed against the "owner" document's URI.
|
||||
if (["about:blank", "about:srcdoc"].includes(uri.spec)) {
|
||||
uri = principal.URI;
|
||||
}
|
||||
}
|
||||
|
||||
// Documents from data: URIs also inherit the principal.
|
||||
if (Services.netUtils.URIChainHasFlags(uri, Ci.nsIProtocolHandler.URI_INHERITS_SECURITY_CONTEXT)) {
|
||||
if (!this.matchAboutBlank) {
|
||||
return false;
|
||||
}
|
||||
uri = principal.URI;
|
||||
}
|
||||
|
||||
if (!this.matchesURI(uri)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.frameId != null && WebNavigationFrames.getFrameId(window) !== this.frameId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If mozAddonManager is present on this page, don't allow
|
||||
// content scripts.
|
||||
if (window.navigator.mozAddonManager !== undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return this.matcher.matchesWindow(window);
|
||||
}
|
||||
|
||||
injectInto(window) {
|
||||
|
@ -202,7 +135,18 @@ class ExtensionGlobal {
|
|||
return ExtensionContent.handleDetectLanguage(this.global, target);
|
||||
case "Extension:Execute":
|
||||
let extension = ExtensionManager.get(recipient.extensionId);
|
||||
let script = new ScriptMatcher(extension, data.options);
|
||||
|
||||
let matcher = new WebExtensionContentScript(extension.policy, parseScriptOptions(data.options));
|
||||
|
||||
let options = Object.assign(matcher, {
|
||||
wantReturnValue: data.options.wantReturnValue,
|
||||
removeCSS: data.options.remove_css,
|
||||
cssOrigin: data.options.css_origin,
|
||||
cssCode: data.options.cssCode,
|
||||
jsCode: data.options.jsCode,
|
||||
});
|
||||
|
||||
let script = new ScriptMatcher(extension, options);
|
||||
|
||||
return ExtensionContent.handleExtensionExecute(this.global, target, data.options, script);
|
||||
case "WebNavigation:GetFrame":
|
||||
|
@ -536,11 +480,11 @@ class StubExtension {
|
|||
this.whiteListedHosts = new MatchPatternSet(data.whiteListedHosts);
|
||||
this.webAccessibleResources = data.webAccessibleResources.map(path => new MatchGlob(path));
|
||||
|
||||
this.scripts = data.content_scripts.map(scriptData => new ScriptMatcher(this, scriptData));
|
||||
|
||||
this._realExtension = null;
|
||||
|
||||
this.startup();
|
||||
|
||||
this.scripts = this.policy.contentScripts.map(matcher => new ScriptMatcher(this, matcher));
|
||||
}
|
||||
|
||||
startup() {
|
||||
|
@ -548,6 +492,8 @@ class StubExtension {
|
|||
if (isContentProcess) {
|
||||
let uri = Services.io.newURI(this.data.resourceURL);
|
||||
ExtensionManagement.startupExtension(this.uuid, uri, this);
|
||||
} else {
|
||||
this.policy = WebExtensionPolicy.getByID(this.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче