mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 593535: Allow restarting extension downloads after failures. r=robstrong, a=blocks-betaN
This commit is contained in:
parent
d1c59140ef
commit
be8fb0186c
@ -4670,6 +4670,16 @@ var XPIDatabase = {
|
||||
}
|
||||
};
|
||||
|
||||
function getHashStringForCrypto(aCrypto) {
|
||||
// return the two-digit hexadecimal code for a byte
|
||||
function toHexString(charCode)
|
||||
("0" + charCode.toString(16)).slice(-2);
|
||||
|
||||
// convert the binary hash data to a hex string.
|
||||
let binary = aCrypto.finish(false);
|
||||
return [toHexString(binary.charCodeAt(i)) for (i in binary)].join("").toLowerCase()
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates an AddonInstall and passes the new object to a callback when
|
||||
* it is complete.
|
||||
@ -4707,7 +4717,14 @@ function AddonInstall(aCallback, aInstallLocation, aUrl, aHash, aName, aType,
|
||||
this.installLocation = aInstallLocation;
|
||||
this.sourceURI = aUrl;
|
||||
this.releaseNotesURI = aReleaseNotesURI;
|
||||
this.hash = aHash;
|
||||
if (aHash) {
|
||||
let hashSplit = aHash.toLowerCase().split(":");
|
||||
this.originalHash = {
|
||||
algorithm: hashSplit[0],
|
||||
data: hashSplit[1]
|
||||
};
|
||||
}
|
||||
this.hash = this.originalHash;
|
||||
this.loadGroup = aLoadGroup;
|
||||
this.listeners = [];
|
||||
this.existingAddon = aExistingAddon;
|
||||
@ -4736,13 +4753,25 @@ function AddonInstall(aCallback, aInstallLocation, aUrl, aHash, aName, aType,
|
||||
if (this.hash) {
|
||||
let crypto = Cc["@mozilla.org/security/hash;1"].
|
||||
createInstance(Ci.nsICryptoHash);
|
||||
try {
|
||||
crypto.initWithString(this.hash.algorithm);
|
||||
}
|
||||
catch (e) {
|
||||
WARN("Unknown hash algorithm " + this.hash.algorithm);
|
||||
this.state = AddonManager.STATE_DOWNLOAD_FAILED;
|
||||
this.error = AddonManager.ERROR_INCORRECT_HASH;
|
||||
aCallback(this);
|
||||
return;
|
||||
}
|
||||
|
||||
let fis = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
fis.init(this.file, -1, -1, false);
|
||||
crypto.updateFromStream(fis, this.file.fileSize);
|
||||
let hash = crypto.finish(true);
|
||||
if (hash != this.hash) {
|
||||
WARN("Hash mismatch");
|
||||
let calculatedHash = getHashStringForCrypto(crypto);
|
||||
if (calculatedHash != this.hash.data) {
|
||||
WARN("File hash (" + calculatedHash + ") did not match provided hash (" +
|
||||
this.hash.data + ")");
|
||||
this.state = AddonManager.STATE_DOWNLOAD_FAILED;
|
||||
this.error = AddonManager.ERROR_INCORRECT_HASH;
|
||||
aCallback(this);
|
||||
@ -4816,6 +4845,7 @@ AddonInstall.prototype = {
|
||||
wrapper: null,
|
||||
stream: null,
|
||||
crypto: null,
|
||||
originalHash: null,
|
||||
hash: null,
|
||||
loadGroup: null,
|
||||
badCertHandler: null,
|
||||
@ -4855,6 +4885,18 @@ AddonInstall.prototype = {
|
||||
case AddonManager.STATE_DOWNLOADED:
|
||||
this.startInstall();
|
||||
break;
|
||||
case AddonManager.STATE_DOWNLOAD_FAILED:
|
||||
case AddonManager.STATE_INSTALL_FAILED:
|
||||
case AddonManager.STATE_CANCELLED:
|
||||
this.removeTemporaryFile();
|
||||
this.state = AddonManager.STATE_AVAILABLE;
|
||||
this.error = 0;
|
||||
this.progress = 0;
|
||||
this.maxProgress = -1;
|
||||
this.hash = this.originalHash;
|
||||
XPIProvider.installs.push(this);
|
||||
this.startDownload();
|
||||
break;
|
||||
case AddonManager.STATE_DOWNLOADING:
|
||||
case AddonManager.STATE_CHECKING:
|
||||
case AddonManager.STATE_INSTALLING:
|
||||
@ -5260,7 +5302,12 @@ AddonInstall.prototype = {
|
||||
if (!this.hash && aOldChannel.originalURI.schemeIs("https") &&
|
||||
aOldChannel instanceof Ci.nsIHttpChannel) {
|
||||
try {
|
||||
this.hash = aOldChannel.getResponseHeader("X-Target-Digest");
|
||||
let hashStr = aOldChannel.getResponseHeader("X-Target-Digest");
|
||||
let hashSplit = hashStr.toLowerCase().split(":");
|
||||
this.hash = {
|
||||
algorithm: hashSplit[0],
|
||||
data: hashSplit[1]
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
@ -5283,13 +5330,11 @@ AddonInstall.prototype = {
|
||||
this.crypto = Cc["@mozilla.org/security/hash;1"].
|
||||
createInstance(Ci.nsICryptoHash);
|
||||
if (this.hash) {
|
||||
[alg, this.hash] = this.hash.split(":", 2);
|
||||
|
||||
try {
|
||||
this.crypto.initWithString(alg);
|
||||
this.crypto.initWithString(this.hash.algorithm);
|
||||
}
|
||||
catch (e) {
|
||||
WARN("Unknown hash algorithm " + alg);
|
||||
WARN("Unknown hash algorithm " + this.hash.algorithm);
|
||||
this.state = AddonManager.STATE_DOWNLOAD_FAILED;
|
||||
this.error = AddonManager.ERROR_INCORRECT_HASH;
|
||||
XPIProvider.removeActiveInstall(this);
|
||||
@ -5347,18 +5392,13 @@ AddonInstall.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
// return the two-digit hexadecimal code for a byte
|
||||
function toHexString(charCode)
|
||||
("0" + charCode.toString(16)).slice(-2);
|
||||
|
||||
// convert the binary hash data to a hex string.
|
||||
let binary = this.crypto.finish(false);
|
||||
let hash = [toHexString(binary.charCodeAt(i)) for (i in binary)].join("")
|
||||
let calculatedHash = getHashStringForCrypto(this.crypto);
|
||||
this.crypto = null;
|
||||
if (this.hash && hash.toLowerCase() != this.hash.toLowerCase()) {
|
||||
if (this.hash && calculatedHash != this.hash.data) {
|
||||
this.downloadFailed(AddonManager.ERROR_INCORRECT_HASH,
|
||||
"Downloaded file hash (" + hash +
|
||||
") did not match provided hash (" + this.hash + ")");
|
||||
"Downloaded file hash (" + calculatedHash +
|
||||
") did not match provided hash (" + this.hash.data + ")");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@ -5411,7 +5451,11 @@ AddonInstall.prototype = {
|
||||
XPIProvider.removeActiveInstall(this);
|
||||
AddonManagerPrivate.callInstallListeners("onDownloadFailed", this.listeners,
|
||||
this.wrapper);
|
||||
this.removeTemporaryFile();
|
||||
|
||||
// If the listener hasn't restarted the download then remove any temporary
|
||||
// file
|
||||
if (this.state == AddonManager.STATE_DOWNLOAD_FAILED)
|
||||
this.removeTemporaryFile();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -52,6 +52,14 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Installation can begin from any of these states
|
||||
const READY_STATES = [
|
||||
AddonManager.STATE_AVAILABLE,
|
||||
AddonManager.STATE_DOWNLOAD_FAILED,
|
||||
AddonManager.STATE_INSTALL_FAILED,
|
||||
AddonManager.STATE_CANCELLED
|
||||
];
|
||||
|
||||
["LOG", "WARN", "ERROR"].forEach(function(aName) {
|
||||
this.__defineGetter__(aName, function() {
|
||||
Components.utils.import("resource://gre/modules/AddonLogging.jsm");
|
||||
@ -95,7 +103,7 @@ function Installer(aWindow, aUrl, aInstalls) {
|
||||
aInstall.addListener(this);
|
||||
|
||||
// Start downloading if it hasn't already begun
|
||||
if (aInstall.state == AddonManager.STATE_AVAILABLE)
|
||||
if (READY_STATES.indexOf(aInstall.state) != -1)
|
||||
aInstall.install();
|
||||
}, this);
|
||||
|
||||
|
@ -119,6 +119,28 @@ function do_get_addon(aName) {
|
||||
return do_get_file("addons/" + aName + ".xpi");
|
||||
}
|
||||
|
||||
function do_get_addon_hash(aName, aAlgorithm) {
|
||||
if (!aAlgorithm)
|
||||
aAlgorithm = "sha1";
|
||||
|
||||
let file = do_get_addon(aName);
|
||||
|
||||
let crypto = AM_Cc["@mozilla.org/security/hash;1"].
|
||||
createInstance(AM_Ci.nsICryptoHash);
|
||||
crypto.initWithString(aAlgorithm);
|
||||
let fis = AM_Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(AM_Ci.nsIFileInputStream);
|
||||
fis.init(file, -1, -1, false);
|
||||
crypto.updateFromStream(fis, file.fileSize);
|
||||
|
||||
// return the two-digit hexadecimal code for a byte
|
||||
function toHexString(charCode)
|
||||
("0" + charCode.toString(16)).slice(-2);
|
||||
|
||||
let binary = crypto.finish(false);
|
||||
return aAlgorithm + ":" + [toHexString(binary.charCodeAt(i)) for (i in binary)].join("")
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an extension uri spec
|
||||
*
|
||||
|
@ -1287,7 +1287,185 @@ function check_test_21(aInstall) {
|
||||
AddonManager.getAddonByID("addon2@tests.mozilla.org", function(a2) {
|
||||
do_check_eq(a2, null);
|
||||
|
||||
end_test();
|
||||
run_test_22();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Tests that an install can be restarted after being cancelled
|
||||
function run_test_22() {
|
||||
prepare_test({ }, [
|
||||
"onNewInstall"
|
||||
]);
|
||||
|
||||
let url = "http://localhost:4444/addons/test_install3.xpi";
|
||||
AddonManager.getInstallForURL(url, function(aInstall) {
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(aInstall, null);
|
||||
do_check_eq(aInstall.state, AddonManager.STATE_AVAILABLE);
|
||||
|
||||
prepare_test({}, [
|
||||
"onDownloadStarted",
|
||||
"onDownloadEnded",
|
||||
], check_test_22);
|
||||
aInstall.install();
|
||||
}, "application/x-xpinstall");
|
||||
}
|
||||
|
||||
function check_test_22(aInstall) {
|
||||
prepare_test({}, [
|
||||
"onDownloadCancelled"
|
||||
]);
|
||||
|
||||
aInstall.cancel();
|
||||
|
||||
ensure_test_completed();
|
||||
|
||||
prepare_test({
|
||||
"addon3@tests.mozilla.org": [
|
||||
"onInstalling"
|
||||
]
|
||||
}, [
|
||||
"onDownloadStarted",
|
||||
"onDownloadEnded",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded"
|
||||
], finish_test_22);
|
||||
|
||||
aInstall.install();
|
||||
}
|
||||
|
||||
function finish_test_22(aInstall) {
|
||||
prepare_test({
|
||||
"addon3@tests.mozilla.org": [
|
||||
"onOperationCancelled"
|
||||
]
|
||||
}, [
|
||||
"onInstallCancelled"
|
||||
]);
|
||||
|
||||
aInstall.cancel();
|
||||
|
||||
ensure_test_completed();
|
||||
|
||||
run_test_23();
|
||||
}
|
||||
|
||||
// Tests that an install can be restarted after being cancelled when a hash
|
||||
// was provided
|
||||
function run_test_23() {
|
||||
prepare_test({ }, [
|
||||
"onNewInstall"
|
||||
]);
|
||||
|
||||
let url = "http://localhost:4444/addons/test_install3.xpi";
|
||||
AddonManager.getInstallForURL(url, function(aInstall) {
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(aInstall, null);
|
||||
do_check_eq(aInstall.state, AddonManager.STATE_AVAILABLE);
|
||||
|
||||
prepare_test({}, [
|
||||
"onDownloadStarted",
|
||||
"onDownloadEnded",
|
||||
], check_test_23);
|
||||
aInstall.install();
|
||||
}, "application/x-xpinstall", do_get_addon_hash("test_install3"));
|
||||
}
|
||||
|
||||
function check_test_23(aInstall) {
|
||||
prepare_test({}, [
|
||||
"onDownloadCancelled"
|
||||
]);
|
||||
|
||||
aInstall.cancel();
|
||||
|
||||
ensure_test_completed();
|
||||
|
||||
prepare_test({
|
||||
"addon3@tests.mozilla.org": [
|
||||
"onInstalling"
|
||||
]
|
||||
}, [
|
||||
"onDownloadStarted",
|
||||
"onDownloadEnded",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded"
|
||||
], finish_test_23);
|
||||
|
||||
aInstall.install();
|
||||
}
|
||||
|
||||
function finish_test_23(aInstall) {
|
||||
prepare_test({
|
||||
"addon3@tests.mozilla.org": [
|
||||
"onOperationCancelled"
|
||||
]
|
||||
}, [
|
||||
"onInstallCancelled"
|
||||
]);
|
||||
|
||||
aInstall.cancel();
|
||||
|
||||
ensure_test_completed();
|
||||
|
||||
run_test_24();
|
||||
}
|
||||
|
||||
// Tests that an install with a bad hash can be restarted after it fails, though
|
||||
// it will only fail again
|
||||
function run_test_24() {
|
||||
prepare_test({ }, [
|
||||
"onNewInstall"
|
||||
]);
|
||||
|
||||
let url = "http://localhost:4444/addons/test_install3.xpi";
|
||||
AddonManager.getInstallForURL(url, function(aInstall) {
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(aInstall, null);
|
||||
do_check_eq(aInstall.state, AddonManager.STATE_AVAILABLE);
|
||||
|
||||
prepare_test({}, [
|
||||
"onDownloadStarted",
|
||||
"onDownloadFailed",
|
||||
], check_test_24);
|
||||
aInstall.install();
|
||||
}, "application/x-xpinstall", "sha1:foo");
|
||||
}
|
||||
|
||||
function check_test_24(aInstall) {
|
||||
prepare_test({ }, [
|
||||
"onDownloadStarted",
|
||||
"onDownloadFailed"
|
||||
], run_test_25);
|
||||
|
||||
aInstall.install();
|
||||
}
|
||||
|
||||
// Tests that installs with a hash for a local file work
|
||||
function run_test_25() {
|
||||
prepare_test({ }, [
|
||||
"onNewInstall"
|
||||
]);
|
||||
|
||||
let url = Services.io.newFileURI(do_get_addon("test_install3")).spec;
|
||||
AddonManager.getInstallForURL(url, function(aInstall) {
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(aInstall, null);
|
||||
do_check_eq(aInstall.state, AddonManager.STATE_DOWNLOADED);
|
||||
do_check_eq(aInstall.error, 0);
|
||||
|
||||
prepare_test({ }, [
|
||||
"onDownloadCancelled"
|
||||
]);
|
||||
|
||||
aInstall.cancel();
|
||||
|
||||
ensure_test_completed();
|
||||
|
||||
end_test();
|
||||
}, "application/x-xpinstall", do_get_addon_hash("test_install3"));
|
||||
}
|
||||
|
@ -92,6 +92,7 @@ _BROWSER_FILES = head.js \
|
||||
browser_httphash3.js \
|
||||
browser_httphash4.js \
|
||||
browser_httphash5.js \
|
||||
browser_httphash6.js \
|
||||
browser_badargs.js \
|
||||
unsigned.xpi \
|
||||
signed.xpi \
|
||||
@ -116,6 +117,7 @@ _BROWSER_FILES = head.js \
|
||||
cookieRedirect.sjs \
|
||||
hashRedirect.sjs \
|
||||
bug540558.html \
|
||||
redirect.sjs \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_FILES)
|
||||
|
@ -0,0 +1,83 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// Tests that a new hash is accepted when restarting a failed download
|
||||
// This verifies bug 593535
|
||||
function setup_redirect(aSettings) {
|
||||
var url = "https://example.com/browser/" + RELATIVE_DIR + "redirect.sjs?mode=setup";
|
||||
for (var name in aSettings) {
|
||||
url += "&" + name + "=" + aSettings[name];
|
||||
}
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", url, false);
|
||||
req.send(null);
|
||||
}
|
||||
|
||||
var gInstall = null;
|
||||
|
||||
function test() {
|
||||
Harness.downloadFailedCallback = download_failed;
|
||||
Harness.installsCompletedCallback = finish_failed_download;
|
||||
Harness.setup();
|
||||
|
||||
var pm = Services.perms;
|
||||
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||
Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
|
||||
|
||||
// Set up the redirect to give a bad hash
|
||||
setup_redirect({
|
||||
"X-Target-Digest": "sha1:foo",
|
||||
"Location": "http://example.com/browser/" + RELATIVE_DIR + "unsigned.xpi"
|
||||
});
|
||||
|
||||
var url = "https://example.com/browser/" + RELATIVE_DIR + "redirect.sjs?mode=redirect";
|
||||
|
||||
var triggers = encodeURIComponent(JSON.stringify({
|
||||
"Unsigned XPI": {
|
||||
URL: url,
|
||||
toString: function() { return this.URL; }
|
||||
}
|
||||
}));
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||
}
|
||||
|
||||
function download_failed(install) {
|
||||
is(install.error, AddonManager.ERROR_INCORRECT_HASH, "Should have seen a hash failure");
|
||||
// Stash the failed download while the harness cleans itself up
|
||||
gInstall = install;
|
||||
}
|
||||
|
||||
function finish_failed_download() {
|
||||
// Setup to track the successful re-download
|
||||
Harness.installEndedCallback = install_ended;
|
||||
Harness.installsCompletedCallback = finish_test;
|
||||
Harness.setup();
|
||||
|
||||
// Give it the right hash this time
|
||||
setup_redirect({
|
||||
"X-Target-Digest": "sha1:3d0dc22e1f394e159b08aaf5f0f97de4d5c65f4f",
|
||||
"Location": "http://example.com/browser/" + RELATIVE_DIR + "unsigned.xpi"
|
||||
});
|
||||
|
||||
// The harness expects onNewInstall events for all installs that are about to start
|
||||
Harness.onNewInstall(gInstall);
|
||||
|
||||
// Restart the install as a regular webpage install so the harness tracks it
|
||||
AddonManager.installAddonsFromWebpage("application/x-xpinstall",
|
||||
gBrowser.contentWindow,
|
||||
gBrowser.currentURI, [gInstall]);
|
||||
}
|
||||
|
||||
function install_ended(install, addon) {
|
||||
install.cancel();
|
||||
}
|
||||
|
||||
function finish_test(count) {
|
||||
is(count, 1, "1 Add-on should have been successfully installed");
|
||||
|
||||
Services.perms.remove("example.com", "install");
|
||||
Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
Harness.finish();
|
||||
}
|
@ -72,39 +72,53 @@ var Harness = {
|
||||
installCount: null,
|
||||
runningInstalls: null,
|
||||
|
||||
waitingForFinish: false,
|
||||
|
||||
// Setup and tear down functions
|
||||
setup: function() {
|
||||
waitForExplicitFinish();
|
||||
Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true);
|
||||
Services.obs.addObserver(this, "addon-install-started", false);
|
||||
Services.obs.addObserver(this, "addon-install-blocked", false);
|
||||
Services.obs.addObserver(this, "addon-install-failed", false);
|
||||
Services.obs.addObserver(this, "addon-install-complete", false);
|
||||
Services.wm.addListener(this);
|
||||
if (!this.waitingForFinish) {
|
||||
waitForExplicitFinish();
|
||||
this.waitingForFinish = true;
|
||||
|
||||
Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true);
|
||||
Services.obs.addObserver(this, "addon-install-started", false);
|
||||
Services.obs.addObserver(this, "addon-install-blocked", false);
|
||||
Services.obs.addObserver(this, "addon-install-failed", false);
|
||||
Services.obs.addObserver(this, "addon-install-complete", false);
|
||||
|
||||
AddonManager.addInstallListener(this);
|
||||
|
||||
Services.wm.addListener(this);
|
||||
|
||||
var self = this;
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref(PREF_LOGGING_ENABLED);
|
||||
Services.obs.removeObserver(self, "addon-install-started");
|
||||
Services.obs.removeObserver(self, "addon-install-blocked");
|
||||
Services.obs.removeObserver(self, "addon-install-failed");
|
||||
Services.obs.removeObserver(self, "addon-install-complete");
|
||||
|
||||
AddonManager.removeInstallListener(self);
|
||||
|
||||
Services.wm.removeListener(self);
|
||||
|
||||
AddonManager.getAllInstalls(function(aInstalls) {
|
||||
is(aInstalls.length, 0, "Should be no active installs at the end of the test");
|
||||
installs.forEach(function(aInstall) {
|
||||
info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state);
|
||||
aInstall.cancel();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
AddonManager.addInstallListener(this);
|
||||
this.installCount = 0;
|
||||
this.pendingCount = 0;
|
||||
this.runningInstalls = [];
|
||||
|
||||
var self = this;
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref(PREF_LOGGING_ENABLED);
|
||||
Services.obs.removeObserver(self, "addon-install-started");
|
||||
Services.obs.removeObserver(self, "addon-install-blocked");
|
||||
Services.obs.removeObserver(self, "addon-install-failed");
|
||||
Services.obs.removeObserver(self, "addon-install-complete");
|
||||
Services.wm.removeListener(self);
|
||||
|
||||
AddonManager.removeInstallListener(self);
|
||||
});
|
||||
},
|
||||
|
||||
finish: function() {
|
||||
AddonManager.getAllInstalls(function(installs) {
|
||||
is(installs.length, 0, "Should be no active installs at the end of the test");
|
||||
finish();
|
||||
});
|
||||
finish();
|
||||
},
|
||||
|
||||
endTest: function() {
|
||||
|
45
toolkit/mozapps/extensions/test/xpinstall/redirect.sjs
Normal file
45
toolkit/mozapps/extensions/test/xpinstall/redirect.sjs
Normal file
@ -0,0 +1,45 @@
|
||||
// Script has two modes based on the query string. If the mode is "setup" then
|
||||
// parameters from the query string configure the redirection. If the mode is
|
||||
// "redirect" then a redirect is returned
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
let parts = request.queryString.split("&");
|
||||
let settings = {};
|
||||
|
||||
parts.forEach(function(aString) {
|
||||
let [k, v] = aString.split("=");
|
||||
settings[k] = v;
|
||||
})
|
||||
|
||||
if (settings.mode == "setup") {
|
||||
delete settings.mode;
|
||||
|
||||
// Object states must be an nsISupports
|
||||
var state = {
|
||||
settings: settings,
|
||||
QueryInterface: function(aIid) {
|
||||
if (aIid.equals(Components.interfaces.nsISupports))
|
||||
return settings;
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
state.wrappedJSObject = state;
|
||||
|
||||
setObjectState("xpinstall-redirect-settings", state);
|
||||
response.setStatusLine(request.httpVersion, 200, "Ok");
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.write("Setup complete");
|
||||
}
|
||||
else if (settings.mode == "redirect") {
|
||||
getObjectState("xpinstall-redirect-settings", function(aObject) {
|
||||
settings = aObject.wrappedJSObject.settings;
|
||||
});
|
||||
|
||||
response.setStatusLine(request.httpVersion, 302, "Found");
|
||||
for (var name in settings) {
|
||||
response.setHeader(name, settings[name]);
|
||||
}
|
||||
response.write("Done");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user