diff --git a/toolkit/mozapps/extensions/XPIProvider.jsm b/toolkit/mozapps/extensions/XPIProvider.jsm index 0011ec85ce73..94a3a9334f3f 100644 --- a/toolkit/mozapps/extensions/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/XPIProvider.jsm @@ -3218,7 +3218,7 @@ AddonInstall.prototype = { cancel: function AI_cancel() { switch (this.state) { case AddonManager.STATE_DOWNLOADING: - break; + this.channel.cancel(Cr.NS_BINDING_ABORTED); case AddonManager.STATE_AVAILABLE: case AddonManager.STATE_DOWNLOADED: LOG("Cancelling download of " + this.sourceURL.spec); @@ -3327,6 +3327,11 @@ AddonInstall.prototype = { } }, + observe: function AI_observe(subject, topic, data) { + // Network is going offline + this.cancel(); + }, + /** * Starts downloading the add-on's XPI file. */ @@ -3378,15 +3383,17 @@ AddonInstall.prototype = { let listener = Cc["@mozilla.org/network/stream-listener-tee;1"]. createInstance(Ci.nsIStreamListenerTee); listener.init(this, this.stream); - let channel = NetUtil.newChannel(this.sourceURL); + this.channel = NetUtil.newChannel(this.sourceURL); if (this.loadGroup) - channel.loadGroup = this.loadGroup; + this.channel.loadGroup = this.loadGroup; + + Services.obs.addObserver(this, "network:offline-about-to-go-offline", false); // Verify that we don't end up on an insecure channel if we haven't got a // hash to verify with (see bug 537761 for discussion) if (!this.hash) - channel.notificationCallbacks = new BadCertHandler(); - channel.asyncOpen(listener, null); + this.channel.notificationCallbacks = new BadCertHandler(); + this.channel.asyncOpen(listener, null); } catch (e) { WARN("Failed to start download: " + e); @@ -3442,6 +3449,13 @@ AddonInstall.prototype = { */ onStopRequest: function AI_onStopRequest(request, context, status) { this.stream.close(); + this.channel = null; + Services.obs.removeObserver(this, "network:offline-about-to-go-offline"); + + // If the download was cancelled then all events will have already been sent + if (status == Cr.NS_BINDING_ABORTED) + return; + LOG("Download of " + this.sourceURL.spec + " completed."); if (Components.isSuccessCode(status)) { diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_offline.js b/toolkit/mozapps/extensions/test/xpinstall/browser_offline.js index f742825bdbf8..ffd1ab13c768 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_offline.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_offline.js @@ -2,7 +2,6 @@ // Tests that going offline cancels an in progress download. function test() { Harness.downloadProgressCallback = download_progress; - Harness.downloadFailedCallback = download_failed; Harness.installsCompletedCallback = finish_test; Harness.setup(); @@ -25,10 +24,6 @@ function download_progress(addon, value, maxValue) { } } -function download_failed(install, status) { - is(status, -210, "Install should be cancelled"); -} - function finish_test(count) { is(count, 0, "No add-ons should have been installed"); try { diff --git a/toolkit/mozapps/extensions/test/xpinstall/head.js b/toolkit/mozapps/extensions/test/xpinstall/head.js index 67df687a3b9c..ffdf050f4c8d 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/head.js +++ b/toolkit/mozapps/extensions/test/xpinstall/head.js @@ -32,6 +32,8 @@ var Harness = { downloadProgressCallback: null, // If set will be called when an xpi fails to download. downloadFailedCallback: null, + // If set will be called when an xpi download is cancelled. + downloadCancelledCallback: null, // If set will be called when downloading of an item has ended. downloadEndedCallback: null, // If set will be called when installation by the extension manager of an xpi @@ -96,8 +98,11 @@ var Harness = { this.installConfirmCallback = null; this.downloadStartedCallback = null; this.downloadProgressCallback = null; + this.downloadCancelledCallback = null; + this.downloadFailedCallback = null; this.downloadEndedCallback = null; this.installStartedCallback = null; + this.installFailedCallback = null; this.installEndedCallback = null; this.installsCompletedCallback = null; }, @@ -203,6 +208,12 @@ var Harness = { this.downloadEndedCallback(install); }, + onDownloadCancelled: function(install) { + if (this.downloadCancelledCallback) + this.downloadCancelledCallback(install); + this.checkTestEnded(); + }, + onDownloadFailed: function(install, status) { if (this.downloadFailedCallback) this.downloadFailedCallback(install, status);