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 [aId, aManifest] = yield this.downloadPackage(manifest, {
manifestURL: aManifestURL,
origin: app.origin,
installOrigin: app.installOrigin,
downloadSize: app.downloadSize
}, isUpdate);
let newApp = {
manifestURL: aManifestURL,
origin: app.origin,
installOrigin: app.installOrigin,
downloadSize: app.downloadSize
};
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
// applyDownload() will be called.
// 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");
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.
app.downloading = false;
app.downloadAvailable = false;
@ -2281,7 +2291,7 @@ this.DOMApplicationRegistry = {
queuedDownload: {},
queuedPackageDownload: {},
onInstallSuccessAck: function(aManifestURL, aDontNeedNetwork) {
onInstallSuccessAck: Task.async(function*(aManifestURL, aDontNeedNetwork) {
// If we are offline, register to run when we'll be online.
if ((Services.io.offline) && !aDontNeedNetwork) {
let onlineWrapper = {
@ -2314,11 +2324,18 @@ this.DOMApplicationRegistry = {
delete this.queuedPackageDownload[aManifestURL];
this.downloadPackage(manifest, newApp, false).then(
this._onDownloadPackage.bind(this, newApp, installSuccessCallback)
);
let id = this._appIdForManifestURL(newApp.manifestURL);
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) {
let app = aData.app;
@ -2603,7 +2620,7 @@ this.DOMApplicationRegistry = {
* @param aManifest {Object} The manifest of the application
*/
_onDownloadPackage: Task.async(function*(aNewApp, aInstallSuccessCallback,
[aId, aManifest]) {
aId, aManifest) {
debug("_onDownloadPackage");
// Success! Move the zip out of TmpD.
let app = this.webapps[aId];
@ -2737,7 +2754,7 @@ this.DOMApplicationRegistry = {
}.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:
// - create a temp directory where to store the app.
// - download the zip in this directory.
@ -2745,91 +2762,80 @@ this.DOMApplicationRegistry = {
// - extract the manifest from the zip and check it.
// - ask confirmation to the user.
// - 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 id = this._appIdForManifestURL(aNewApp.manifestURL);
let oldApp = this.webapps[id];
let fullPackagePath = aManifest.fullPackagePath();
// Check if it's a local file install (we've downloaded/sideloaded the
// 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*() {
yield this._ensureSufficientStorage(aNewApp);
debug("About to download " + fullPackagePath);
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
// 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';
AppDownloadManager.add(
aNewApp.manifestURL,
{
channel: requestChannel,
appId: aId,
previousState: aIsUpdate ? "installed" : "pending"
}
);
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,
isLocalFileInstall,
oldApp,
aNewApp);
// We determine the app's 'installState' according to its previous
// state. Cancelled download should remain as 'pending'. Successfully
// installed apps should morph to 'updating'.
aOldApp.installState = aIsUpdate ? "updating" : "pending";
AppDownloadManager.add(
aNewApp.manifestURL,
{
channel: requestChannel,
appId: id,
previousState: aIsUpdate ? "installed" : "pending"
}
);
// initialize the progress to 0 right now
aOldApp.progress = 0;
// We set the 'downloading' flag to true right before starting the fetch.
oldApp.downloading = true;
// Save the current state of the app to handle cases where we may be
// retrying a past download.
yield DOMApplicationRegistry._saveApps();
// We determine the app's 'installState' according to its previous
// 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", {
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
// Clear any previous download errors.
error: null,
app: oldApp,
app: aOldApp,
manifestURL: aNewApp.manifestURL
});
});
let zipFile = yield this._getPackage(requestChannel, id, oldApp, aNewApp);
let hash = yield this._computeFileHash(zipFile.path);
let zipFile = yield this._getPackage(requestChannel, aId, aOldApp, aNewApp);
let hash = yield this._computeFileHash(zipFile.path);
let responseStatus = requestChannel.responseStatus;
let oldPackage = (responseStatus == 304 || hash == oldApp.packageHash);
let responseStatus = requestChannel.responseStatus;
let oldPackage = (responseStatus == 304 || hash == aOldApp.packageHash);
if (oldPackage) {
debug("package's etag or hash unchanged; sending 'applied' event");
// The package's Etag or hash has not changed.
// 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
// the caller that the package wasn't downloaded.
this._sendAppliedEvent(aNewApp, oldApp, id);
throw new Error("PACKAGE_UNCHANGED");
}
if (oldPackage) {
debug("package's etag or hash unchanged; sending 'applied' event");
// The package's Etag or hash has not changed.
// 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
// the caller that the package wasn't downloaded.
this._sendAppliedEvent(aNewApp, aOldApp, aId);
throw new Error("PACKAGE_UNCHANGED");
}
let newManifest = yield this._openAndReadPackage(zipFile, oldApp, aNewApp,
isLocalFileInstall, aIsUpdate, aManifest, requestChannel, hash);
let newManifest = yield this._openAndReadPackage(zipFile, aOldApp, aNewApp,
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) {
let deferred = Promise.defer();
@ -3494,8 +3500,8 @@ this.DOMApplicationRegistry = {
},
// Removes the directory we created, and sends an error to the DOM side.
_revertDownloadPackage: function(aId, aOldApp, aNewApp, aIsUpdate, aError) {
debug("Cleanup: " + aError + "\n" + aError.stack);
revertDownloadPackage: function(aId, aOldApp, aNewApp, aIsUpdate, aError) {
debug("Error downloading package: " + aError);
let dir = FileUtils.getDir("TmpD", ["webapps", aId], true, true);
try {
dir.remove(true);
@ -3536,8 +3542,6 @@ this.DOMApplicationRegistry = {
});
});
AppDownloadManager.remove(aNewApp.manifestURL);
throw aError;
},
doUninstall: function(aData, aMm) {