Bug 997717 - Move rejection handler out of downloadPackage r=myk

This commit is contained in:
Martyn Haigh 2014-07-21 10:26:58 +01:00
parent b4cf06074c
commit 15143def1e

View File

@ -1428,21 +1428,31 @@ this.DOMApplicationRegistry = {
} }
let manifest = new ManifestHelper(json, app.manifestURL); let manifest = new ManifestHelper(json, app.manifestURL);
let [aId, aManifest] = yield this.downloadPackage(manifest, { let newApp = {
manifestURL: aManifestURL, manifestURL: aManifestURL,
origin: app.origin, origin: app.origin,
installOrigin: app.installOrigin, installOrigin: app.installOrigin,
downloadSize: app.downloadSize downloadSize: app.downloadSize
}, isUpdate); };
let newManifest, newId;
try {
[newId, newManifest] = yield this.downloadPackage(id, app, manifest, newApp, isUpdate);
} catch (ex) {
this.revertDownloadPackage(id, app, newApp, isUpdate, ex);
throw ex;
}
// Success! Keep the zip in of TmpD, we'll move it out when // Success! Keep the zip in of TmpD, we'll move it out when
// applyDownload() will be called. // applyDownload() will be called.
// Save the manifest in TmpD also // Save the manifest in TmpD also
let manFile = OS.Path.join(OS.Constants.Path.tmpDir, "webapps", aId, let manFile = OS.Path.join(OS.Constants.Path.tmpDir, "webapps", newId,
"manifest.webapp"); "manifest.webapp");
yield this._writeFile(manFile, JSON.stringify(aManifest)); yield this._writeFile(manFile, JSON.stringify(newManifest));
app = this.webapps[id];
app = this.webapps[aId];
// Set state and fire events. // Set state and fire events.
app.downloading = false; app.downloading = false;
app.downloadAvailable = false; app.downloadAvailable = false;
@ -2281,7 +2291,7 @@ this.DOMApplicationRegistry = {
queuedDownload: {}, queuedDownload: {},
queuedPackageDownload: {}, queuedPackageDownload: {},
onInstallSuccessAck: function(aManifestURL, aDontNeedNetwork) { onInstallSuccessAck: Task.async(function*(aManifestURL, aDontNeedNetwork) {
// If we are offline, register to run when we'll be online. // If we are offline, register to run when we'll be online.
if ((Services.io.offline) && !aDontNeedNetwork) { if ((Services.io.offline) && !aDontNeedNetwork) {
let onlineWrapper = { let onlineWrapper = {
@ -2314,11 +2324,18 @@ this.DOMApplicationRegistry = {
delete this.queuedPackageDownload[aManifestURL]; delete this.queuedPackageDownload[aManifestURL];
this.downloadPackage(manifest, newApp, false).then( let id = this._appIdForManifestURL(newApp.manifestURL);
this._onDownloadPackage.bind(this, newApp, installSuccessCallback) let oldApp = this.webapps[id];
); let newManifest, newId;
try {
[newId, newManifest] = yield this.downloadPackage(id, oldApp, manifest, newApp, false);
yield this._onDownloadPackage(newApp, installSuccessCallback, newId, newManifest);
} catch (ex) {
this.revertDownloadPackage(id, oldApp, newApp, false, ex);
}
} }
}, }),
_setupApp: function(aData, aId) { _setupApp: function(aData, aId) {
let app = aData.app; let app = aData.app;
@ -2603,7 +2620,7 @@ this.DOMApplicationRegistry = {
* @param aManifest {Object} The manifest of the application * @param aManifest {Object} The manifest of the application
*/ */
_onDownloadPackage: Task.async(function*(aNewApp, aInstallSuccessCallback, _onDownloadPackage: Task.async(function*(aNewApp, aInstallSuccessCallback,
[aId, aManifest]) { aId, aManifest) {
debug("_onDownloadPackage"); debug("_onDownloadPackage");
// Success! Move the zip out of TmpD. // Success! Move the zip out of TmpD.
let app = this.webapps[aId]; let app = this.webapps[aId];
@ -2737,7 +2754,7 @@ this.DOMApplicationRegistry = {
}.bind(this)).then(null, Cu.reportError); }.bind(this)).then(null, Cu.reportError);
}, },
downloadPackage: function(aManifest, aNewApp, aIsUpdate, aOnSuccess) { downloadPackage: Task.async(function*(aId, aOldApp, aManifest, aNewApp, aIsUpdate) {
// Here are the steps when installing a package: // Here are the steps when installing a package:
// - create a temp directory where to store the app. // - create a temp directory where to store the app.
// - download the zip in this directory. // - download the zip in this directory.
@ -2745,91 +2762,80 @@ this.DOMApplicationRegistry = {
// - extract the manifest from the zip and check it. // - extract the manifest from the zip and check it.
// - ask confirmation to the user. // - ask confirmation to the user.
// - add the new app to the registry. // - add the new app to the registry.
// If we fail at any step, we revert the previous ones and return an error. yield this._ensureSufficientStorage(aNewApp);
// We define these outside the task to use them in its reject handler. let fullPackagePath = aManifest.fullPackagePath();
let id = this._appIdForManifestURL(aNewApp.manifestURL); // Check if it's a local file install (we've downloaded/sideloaded the
let oldApp = this.webapps[id]; // package already, it existed on the build, or it came with an APK).
// Note that this variable also controls whether files signed with expired
// certificates are accepted or not. If isLocalFileInstall is true and the
// device date is earlier than the build generation date, then the signature
// will be accepted even if the certificate is expired.
let isLocalFileInstall =
Services.io.extractScheme(fullPackagePath) === 'file';
return Task.spawn((function*() { debug("About to download " + fullPackagePath);
yield this._ensureSufficientStorage(aNewApp);
let fullPackagePath = aManifest.fullPackagePath(); let requestChannel = this._getRequestChannel(fullPackagePath,
isLocalFileInstall,
aOldApp,
aNewApp);
// Check if it's a local file install (we've downloaded/sideloaded the AppDownloadManager.add(
// package already, it existed on the build, or it came with an APK). aNewApp.manifestURL,
// Note that this variable also controls whether files signed with expired {
// certificates are accepted or not. If isLocalFileInstall is true and the channel: requestChannel,
// device date is earlier than the build generation date, then the signature appId: aId,
// will be accepted even if the certificate is expired. previousState: aIsUpdate ? "installed" : "pending"
let isLocalFileInstall = }
Services.io.extractScheme(fullPackagePath) === 'file'; );
debug("About to download " + fullPackagePath); // We set the 'downloading' flag to true right before starting the fetch.
aOldApp.downloading = true;
let requestChannel = this._getRequestChannel(fullPackagePath, // We determine the app's 'installState' according to its previous
isLocalFileInstall, // state. Cancelled download should remain as 'pending'. Successfully
oldApp, // installed apps should morph to 'updating'.
aNewApp); aOldApp.installState = aIsUpdate ? "updating" : "pending";
AppDownloadManager.add( // initialize the progress to 0 right now
aNewApp.manifestURL, aOldApp.progress = 0;
{
channel: requestChannel,
appId: id,
previousState: aIsUpdate ? "installed" : "pending"
}
);
// We set the 'downloading' flag to true right before starting the fetch. // Save the current state of the app to handle cases where we may be
oldApp.downloading = true; // retrying a past download.
yield DOMApplicationRegistry._saveApps();
// We determine the app's 'installState' according to its previous DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
// state. Cancelled download should remain as 'pending'. Successfully
// installed apps should morph to 'updating'.
oldApp.installState = aIsUpdate ? "updating" : "pending";
// initialize the progress to 0 right now
oldApp.progress = 0;
// Save the current state of the app to handle cases where we may be
// retrying a past download.
yield DOMApplicationRegistry._saveApps();
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
// Clear any previous download errors. // Clear any previous download errors.
error: null, error: null,
app: oldApp, app: aOldApp,
manifestURL: aNewApp.manifestURL manifestURL: aNewApp.manifestURL
}); });
let zipFile = yield this._getPackage(requestChannel, id, oldApp, aNewApp); let zipFile = yield this._getPackage(requestChannel, aId, aOldApp, aNewApp);
let hash = yield this._computeFileHash(zipFile.path); let hash = yield this._computeFileHash(zipFile.path);
let responseStatus = requestChannel.responseStatus; let responseStatus = requestChannel.responseStatus;
let oldPackage = (responseStatus == 304 || hash == oldApp.packageHash); let oldPackage = (responseStatus == 304 || hash == aOldApp.packageHash);
if (oldPackage) { if (oldPackage) {
debug("package's etag or hash unchanged; sending 'applied' event"); debug("package's etag or hash unchanged; sending 'applied' event");
// The package's Etag or hash has not changed. // The package's Etag or hash has not changed.
// We send an "applied" event right away so code awaiting that event // We send an "applied" event right away so code awaiting that event
// can proceed to access the app. We also throw an error to alert // can proceed to access the app. We also throw an error to alert
// the caller that the package wasn't downloaded. // the caller that the package wasn't downloaded.
this._sendAppliedEvent(aNewApp, oldApp, id); this._sendAppliedEvent(aNewApp, aOldApp, aId);
throw new Error("PACKAGE_UNCHANGED"); throw new Error("PACKAGE_UNCHANGED");
} }
let newManifest = yield this._openAndReadPackage(zipFile, oldApp, aNewApp, let newManifest = yield this._openAndReadPackage(zipFile, aOldApp, aNewApp,
isLocalFileInstall, aIsUpdate, aManifest, requestChannel, hash); isLocalFileInstall, aIsUpdate, aManifest, requestChannel, hash);
AppDownloadManager.remove(aNewApp.manifestURL); AppDownloadManager.remove(aNewApp.manifestURL);
return [oldApp.id, newManifest]; return [aOldApp.id, newManifest];
}).bind(this)).then( }),
aOnSuccess,
this._revertDownloadPackage.bind(this, id, oldApp, aNewApp, aIsUpdate)
);
},
_ensureSufficientStorage: function(aNewApp) { _ensureSufficientStorage: function(aNewApp) {
let deferred = Promise.defer(); let deferred = Promise.defer();
@ -3494,8 +3500,8 @@ this.DOMApplicationRegistry = {
}, },
// Removes the directory we created, and sends an error to the DOM side. // Removes the directory we created, and sends an error to the DOM side.
_revertDownloadPackage: function(aId, aOldApp, aNewApp, aIsUpdate, aError) { revertDownloadPackage: function(aId, aOldApp, aNewApp, aIsUpdate, aError) {
debug("Cleanup: " + aError + "\n" + aError.stack); debug("Error downloading package: " + aError);
let dir = FileUtils.getDir("TmpD", ["webapps", aId], true, true); let dir = FileUtils.getDir("TmpD", ["webapps", aId], true, true);
try { try {
dir.remove(true); dir.remove(true);
@ -3536,8 +3542,6 @@ this.DOMApplicationRegistry = {
}); });
}); });
AppDownloadManager.remove(aNewApp.manifestURL); AppDownloadManager.remove(aNewApp.manifestURL);
throw aError;
}, },
doUninstall: function(aData, aMm) { doUninstall: function(aData, aMm) {