Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

avoid duplication of source strings #2243

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 2 additions & 17 deletions modules/ipcscript.js
@@ -1,6 +1,5 @@
var EXPORTED_SYMBOLS = ['IPCScript'];

Components.utils.import("chrome://greasemonkey-modules/content/extractMeta.js");
Components.utils.import("chrome://greasemonkey-modules/content/util.js");

function IPCScript(aScript, addonVersion) {
Expand All @@ -17,37 +16,25 @@ function IPCScript(aScript, addonVersion) {
this.namespace = aScript.namespace;
this.noframes = aScript.noframes;
this.runAt = aScript.runAt;
this.textContent = aScript.textContent;
this.uuid = aScript.uuid;
this.version = aScript.version;
this.willUpdate = aScript.isRemoteUpdateAllowed();

this.requires = aScript.requires.map(function(req) {
return {
'fileURL': req.fileURL,
'textContent': req.textContent
'fileURL': req.fileURL
};
});

this.resources = aScript.resources.map(function(res) {
return {
'name': res.name,
'mimetype': res.mimetype,
'textContent': res.textContent,
'url': GM_util.getUriFromFile(res.file).spec
};
});
};

IPCScript.prototype.__defineGetter__('metaStr',
function IPCScript_getMetaStr() {
if (!this._metaStr) {
this._metaStr = extractMeta(this.textContent);
}

return this._metaStr;
});

IPCScript.prototype.info = function() {
var resources = {};
for (var i = 0, r = null; r = this.resources[i]; i++) {
Expand All @@ -60,8 +47,6 @@ IPCScript.prototype.info = function() {
return {
'uuid': this.uuid,
'version': this.addonVersion,
'scriptMetaStr': this.metaStr,
'scriptSource': this.textContent,
'scriptWillUpdate': this.willUpdate,
'script': {
'description': this.description,
Expand All @@ -80,4 +65,4 @@ IPCScript.prototype.info = function() {
'version': this.version
}
};
};
};
7 changes: 6 additions & 1 deletion modules/miscapis.js
Expand Up @@ -24,8 +24,13 @@ GM_Resources.prototype.getResourceURL = function(aScript, name) {
return ['greasemonkey-script:', aScript.uuid, '/', name].join('');
};


GM_Resources.prototype.getResourceText = function(name) {
return this._getDep(name).textContent;
var dep = this._getDep(name)
if(dep.textContent !== undefined)
return dep.textContent;
// lazy resources in IPC scripts
return GM_util.fileXHR(dep.url, "text/plain");
};

GM_Resources.prototype._getDep = function(name) {
Expand Down
83 changes: 69 additions & 14 deletions modules/sandbox.js
Expand Up @@ -11,12 +11,15 @@ Cu.import("chrome://greasemonkey-modules/content/miscapis.js");
Cu.import("chrome://greasemonkey-modules/content/storageFront.js");
Cu.import("chrome://greasemonkey-modules/content/util.js");
Cu.import("chrome://greasemonkey-modules/content/xmlhttprequester.js");
Cu.import("chrome://greasemonkey-modules/content/extractMeta.js");

var gStringBundle = Cc["@mozilla.org/intl/stringbundle;1"]
.getService(Ci.nsIStringBundleService)
.createBundle("chrome://greasemonkey/locale/greasemonkey.properties");
var gInvalidAccesskeyErrorStr = gStringBundle
.GetStringFromName('error.menu-invalid-accesskey');
var subLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);

// Only a particular set of strings are allowed. See: http://goo.gl/ex2LJ
var gMaxJSVersion = "ECMAv5";
Expand All @@ -35,9 +38,8 @@ function createSandbox(aScript, aContentWin, aUrl, aFrameScope) {
'wantXrays': false,
});
// GM_info is always provided.
// TODO: lazy getter? XPCOMUtils.defineLazyGetter
Components.utils.evalInSandbox(
'const GM_info = ' + uneval(aScript.info()), contentSandbox);
injectGMInfo(aScript, contentSandbox);

// Alias unsafeWindow for compatibility.
Components.utils.evalInSandbox(
'const unsafeWindow = window;', contentSandbox);
Expand Down Expand Up @@ -124,19 +126,69 @@ function createSandbox(aScript, aContentWin, aUrl, aFrameScope) {
'contentStartRequest');
}

// TODO: lazy getter?
Components.utils.evalInSandbox(
'const GM_info = ' + uneval(aScript.info()), sandbox);
injectGMInfo(aScript, sandbox);

return sandbox;
}



function injectGMInfo(aScript, sandbox) {
var rawInfo = aScript.info();
var scriptURL = aScript.fileURL;

// TODO: also delay top level clone via lazy getter? XPCOMUtils.defineLazyGetter
sandbox.GM_info = Cu.cloneInto(rawInfo, sandbox);

var waivedInfo = Components.utils.waiveXrays(sandbox.GM_info);

var fileCache = new Map();


function getScriptSource() {
var content = fileCache.get("scriptSource");
if (content === undefined) {
content = GM_util.fileXHR(scriptURL, "application/javascript");
fileCache.set("scriptSource", content);
}
return content;
}

function getMeta() {
var meta = fileCache.get("meta");
if (meta === undefined) {
meta = extractMeta(getScriptSource());
fileCache.set("meta", meta);
}
return meta;
}

// lazy getters for heavyweight strings that aren't sent down through IPC
Object.defineProperty(waivedInfo, "scriptSource", {
get: Cu.exportFunction(getScriptSource, sandbox)
});

// meta depends on content, so we need a lazy one here too
Object.defineProperty(waivedInfo, 'scriptMetaStr', {
get: Cu.exportFunction(getMeta, sandbox)
});

}

function uriToString(uri) {
var channel = NetUtil.newChannel({ uri: NetUtil.newURI(uri, "UTF-8"), loadUsingSystemPrincipal: true});
var stream = channel.open();

var count = stream.available();
var data = NetUtil.readInputStreamToString(stream, count, { charset : "utf-8" });
return data;
}

function runScriptInSandbox(script, sandbox) {
// Eval the code, with anonymous wrappers when/if appropriate.
function evalWithWrapper(code, fileName) {
function evalWithWrapper(uri) {
try {
Components.utils.evalInSandbox(code, sandbox, gMaxJSVersion, fileName, 1);
subLoader.loadSubScript(uri, sandbox, "UTF-8");
} catch (e) {
if ("return not in function" == e.message) {
// See #1592; we never anon wrap anymore, unless forced to by a return
Expand All @@ -147,8 +199,11 @@ function runScriptInSandbox(script, sandbox) {
fileName,
e.lineNumber
);

var code = GM_util.fileXHR(uri, "application/javascript");

Components.utils.evalInSandbox(
'(function(){ '+code+'\n})()', sandbox, gMaxJSVersion, fileName, 1);
'(function(){ '+code+'\n})()', sandbox, gMaxJSVersion, uri, 1);
} else {
// Otherwise raise.
throw e;
Expand All @@ -157,22 +212,22 @@ function runScriptInSandbox(script, sandbox) {
}

// Eval the code, with a try/catch to report errors cleanly.
function evalWithCatch(code, fileName) {
function evalWithCatch(uri) {
try {
evalWithWrapper(code, fileName);
evalWithWrapper(uri);
} catch (e) {
// Log it properly.
GM_util.logError(e, false, fileName, e.lineNumber);
GM_util.logError(e, false, e.fileName, e.lineNumber);
// Stop the script, in the case of requires, as if it was one big script.
return false;
}
return true;
}

for (var i = 0, require = null; require = script.requires[i]; i++) {
if (!evalWithCatch(require.textContent, require.fileURL)) {
if (!evalWithCatch(require.fileURL)) {
return;
}
}
evalWithCatch(script.textContent, script.fileURL);
evalWithCatch(script.fileURL);
}
1 change: 1 addition & 0 deletions modules/util.js
Expand Up @@ -27,6 +27,7 @@ XPCOMUtils.defineLazyModuleGetter(GM_util, 'alert', 'chrome://greasemonkey-modul
XPCOMUtils.defineLazyModuleGetter(GM_util, 'compareFirefoxVersion', 'chrome://greasemonkey-modules/content/util/compareFirefoxVersion.js');
XPCOMUtils.defineLazyModuleGetter(GM_util, 'emptyEl', 'chrome://greasemonkey-modules/content/util/emptyEl.js');
XPCOMUtils.defineLazyModuleGetter(GM_util, 'enqueueRemoveFile', 'chrome://greasemonkey-modules/content/util/enqueueRemoveFile.js');
XPCOMUtils.defineLazyModuleGetter(GM_util, 'fileXHR', 'chrome://greasemonkey-modules/content/util/fileXHR.js');
XPCOMUtils.defineLazyModuleGetter(GM_util, 'findMessageManager', 'chrome://greasemonkey-modules/content/util/findMessageManager.js');
XPCOMUtils.defineLazyModuleGetter(GM_util, 'getBestLocaleMatch', 'chrome://greasemonkey-modules/content/util/getBestLocaleMatch.js');
XPCOMUtils.defineLazyModuleGetter(GM_util, 'getBinaryContents', 'chrome://greasemonkey-modules/content/util/getBinaryContents.js');
Expand Down
15 changes: 15 additions & 0 deletions modules/util/fileXHR.js
@@ -0,0 +1,15 @@
'use strict';

var EXPORTED_SYMBOLS = ['fileXHR'];

Components.utils.importGlobalProperties(["XMLHttpRequest"]);

// sync XHR. it's just meant to fetch file:// uris that aren't otherwise accessible in content
// don't use it in the parent process or for web URLs
function fileXHR(uri, mimetype) {
var xhr = new XMLHttpRequest();
xhr.open("open", uri, false);
xhr.overrideMimeType(mimetype);
xhr.send(null);
return xhr.responseText;
}