Back out c6cb52ebb2c8 (bug 789527) for xpcshell bustage

--HG--
extra : rebase_source : 461c95c93d64d14f2130296acde2c7030a3009e4
This commit is contained in:
Phil Ringnalda 2012-09-27 14:37:39 -07:00
Родитель 97748e5b04
Коммит ad9192f6c0
2 изменённых файлов: 83 добавлений и 261 удалений

Просмотреть файл

@ -188,10 +188,8 @@ WebappsRegistry.prototype = {
// mozIDOMApplicationRegistry2 implementation // mozIDOMApplicationRegistry2 implementation
installPackage: function(aURL, aParams) { installPackage: function(aPackageURL, aParams) {
let installURL = this._window.location.href; this._validateScheme(aPackageURL);
let installOrigin = this._getOrigin(installURL);
this._validateScheme(aURL);
let request = this.createRequest(); let request = this.createRequest();
let requestID = this.getRequestId(request); let requestID = this.getRequestId(request);
@ -200,54 +198,13 @@ WebappsRegistry.prototype = {
Array.isArray(aParams.receipts)) ? aParams.receipts : []; Array.isArray(aParams.receipts)) ? aParams.receipts : [];
let categories = (aParams && aParams.categories && let categories = (aParams && aParams.categories &&
Array.isArray(aParams.categories)) ? aParams.categories : []; Array.isArray(aParams.categories)) ? aParams.categories : [];
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); cpmm.sendAsyncMessage("Webapps:InstallPackage", { url: aPackageURL,
xhr.open("GET", aURL, true);
xhr.channel.loadFlags |= Ci.nsIRequest.VALIDATE_ALWAYS;
xhr.addEventListener("load", (function() {
if (xhr.status == 200) {
let manifest;
try {
manifest = JSON.parse(xhr.responseText, installOrigin);
} catch(e) {
Services.DOMRequest.fireError(request, "MANIFEST_PARSE_ERROR");
return;
}
if (!(AppsUtils.checkManifest(manifest, installOrigin) &&
manifest.package_path)) {
Services.DOMRequest.fireError(request, "INVALID_MANIFEST");
} else {
if (!this.checkAppStatus(manifest)) {
Services.DOMRequest.fireError(request, "INVALID_SECURITY_LEVEL");
} else {
let receipts = (aParams && aParams.receipts && Array.isArray(aParams.receipts)) ? aParams.receipts : [];
let categories = (aParams && aParams.categories && Array.isArray(aParams.categories)) ? aParams.categories : [];
let etag = xhr.getResponseHeader("Etag");
cpmm.sendAsyncMessage("Webapps:InstallPackage", { app: {
installOrigin: installOrigin,
origin: this._getOrigin(aURL),
manifestURL: aURL,
updateManifest: manifest,
etag: etag,
receipts: receipts, receipts: receipts,
categories: categories }, categories: categories,
from: installURL,
oid: this._id,
requestID: requestID, requestID: requestID,
isPackage: true }); oid: this._id,
} from: this._window.location.href,
} installOrigin: this._getOrigin(this._window.location.href) });
}
else {
Services.DOMRequest.fireError(request, "MANIFEST_URL_ERROR");
}
}).bind(this), false);
xhr.addEventListener("error", (function() {
Services.DOMRequest.fireError(request, "NETWORK_ERROR");
}).bind(this), false);
xhr.send(null);
return request; return request;
}, },
@ -381,11 +338,9 @@ WebappsApplication.prototype = {
"Webapps:Uninstall:Return:KO", "Webapps:Uninstall:Return:KO",
"Webapps:OfflineCache", "Webapps:OfflineCache",
"Webapps:CheckForUpdate:Return:OK", "Webapps:CheckForUpdate:Return:OK",
"Webapps:CheckForUpdate:Return:KO", "Webapps:CheckForUpdate:Return:KO"]);
"Webapps:PackageEvent"]);
cpmm.sendAsyncMessage("Webapps:RegisterForMessages", cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
["Webapps:Uninstall:Return:OK", "Webapps:OfflineCache", ["Webapps:Uninstall:Return:OK", "Webapps:OfflineCache"]);
"Webapps:PackageEvent"]);
}, },
set onprogress(aCallback) { set onprogress(aCallback) {
@ -479,8 +434,7 @@ WebappsApplication.prototype = {
uninit: function() { uninit: function() {
this._onprogress = null; this._onprogress = null;
cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
["Webapps:Uninstall:Return:OK", "Webapps:OfflineCache", ["Webapps:Uninstall:Return:OK", "Webapps:OfflineCache"]);
"Webapps:PackageEvent"]);
}, },
_fireEvent: function(aName, aHandler) { _fireEvent: function(aName, aHandler) {
@ -491,11 +445,9 @@ WebappsApplication.prototype = {
}, },
receiveMessage: function(aMessage) { receiveMessage: function(aMessage) {
let msg = aMessage.json; var msg = aMessage.json;
let req = this.takeRequest(msg.requestID); let req = this.takeRequest(msg.requestID);
if ((msg.oid != this._id || !req) && if ((msg.oid != this._id || !req) && aMessage.name !== "Webapps:OfflineCache")
aMessage.name !== "Webapps:OfflineCache" &&
aMessage.name !== "Webapps:PackageEvent")
return; return;
switch (aMessage.name) { switch (aMessage.name) {
case "Webapps:Uninstall:Return:OK": case "Webapps:Uninstall:Return:OK":
@ -539,43 +491,6 @@ WebappsApplication.prototype = {
case "Webapps:CheckForUpdate:Return:KO": case "Webapps:CheckForUpdate:Return:KO":
Services.DOMRequest.fireError(req, msg.error); Services.DOMRequest.fireError(req, msg.error);
break; break;
case "Webapps:PackageEvent":
if (msg.manifestURL != this.manifestURL)
return;
switch(msg.type) {
case "error":
this._downloadError = msg.error;
this._fireEvent("downloaderror", this._ondownloaderror);
break;
case "progress":
this.progress = msg.progress;
this._fireEvent("downloadprogress", this._onprogress);
break;
case "installed":
let app = msg.app;
this.progress = app.progress || 0;
this.downloadAvailable = app.downloadAvailable;
this.downloading = app.downloading;
this.readyToApplyDownload = app.readyToApplyDownload;
this.downloadSize = app.downloadSize || 0;
this.installState = app.installState;
this.manifest = app.manifest;
this._fireEvent("downloaded", this._ondownloaded);
this._fireEvent("downloadapplied", this._ondownloadapplied);
break;
case "canceled":
app = msg.app;
this.progress = app.progress || 0;
this.downloadAvailable = app.downloadAvailable;
this.downloading = app.downloading;
this.readyToApplyDownload = app.readyToApplyDownload;
this.downloadSize = app.downloadSize || 0;
this.installState = app.installState;
this._downloadError = msg.error;
this._fireEvent("downloaderror", this._ondownloaderror);
break;
}
break;
} }
}, },

Просмотреть файл

@ -57,7 +57,6 @@ let DOMApplicationRegistry = {
webapps: { }, webapps: { },
children: [ ], children: [ ],
allAppsLaunchable: false, allAppsLaunchable: false,
downloads: { },
init: function() { init: function() {
this.messages = ["Webapps:Install", "Webapps:Uninstall", this.messages = ["Webapps:Install", "Webapps:Uninstall",
@ -471,8 +470,7 @@ let DOMApplicationRegistry = {
mm.sendAsyncMessage("Webapps:GetAll:Return:KO", msg); mm.sendAsyncMessage("Webapps:GetAll:Return:KO", msg);
break; break;
case "Webapps:InstallPackage": case "Webapps:InstallPackage":
// always ask for UI to install this.installPackage(msg, mm);
Services.obs.notifyObservers(mm, "webapps-ask-install", JSON.stringify(msg));
break; break;
case "Webapps:GetBasePath": case "Webapps:GetBasePath":
return this.webapps[msg.id].basePath; return this.webapps[msg.id].basePath;
@ -568,26 +566,6 @@ let DOMApplicationRegistry = {
cancelDownload: function cancelDowload(aManifestURL) { cancelDownload: function cancelDowload(aManifestURL) {
// We can't cancel appcache dowloads for now. // We can't cancel appcache dowloads for now.
if (!this.downloads[aManifestURL]) {
return;
}
// This is a HTTP channel.
let download = this.downloads[aManifestURL]
download.channel.cancel(Cr.NS_BINDING_ABORTED);
let app = this.webapps[dowload.appId];
app.progress = 0;
app.installState = app.previousState;
app.dowloading = false;
app.dowloadavailable = false;
app.downloadSize = 0;
this._saveApps((function() {
this.broadcastMessage("Webapps:PackageEvent",
{ type: "canceled",
manifestURL: aApp.manifestURL,
app: app,
error: "DOWNLOAD_CANCELED" });
}).bind(this));
}, },
startOfflineCacheDownload: function startOfflineCacheDownload(aManifest, aApp, aProfileDir) { startOfflineCacheDownload: function startOfflineCacheDownload(aManifest, aApp, aProfileDir) {
@ -736,8 +714,7 @@ let DOMApplicationRegistry = {
confirmInstall: function(aData, aFromSync, aProfileDir, aOfflineCacheObserver) { confirmInstall: function(aData, aFromSync, aProfileDir, aOfflineCacheObserver) {
let app = aData.app; let app = aData.app;
app.removable = true; app.removable = true;
let id = app.syncId || this._appId(app.origin);
let id = app.syncId || this._appIdForManifestURL(app.manifestURL);
let localId = this.getAppLocalIdByManifestURL(app.manifestURL); let localId = this.getAppLocalIdByManifestURL(app.manifestURL);
// Installing an application again is considered as an update. // Installing an application again is considered as an update.
@ -752,14 +729,9 @@ let DOMApplicationRegistry = {
localId = this._nextLocalId(); localId = this._nextLocalId();
} }
let manifestName = "manifest.webapp"; if (app.packageId) {
if (aData.isPackage) {
// Override the origin with the correct id. // Override the origin with the correct id.
app.origin = "app://" + id; app.origin = "app://" + id;
// For packaged apps, keep the update manifest distinct from the app
// manifest.
manifestName = "update.webapp";
} }
let appObject = AppsUtils.cloneAppObject(app); let appObject = AppsUtils.cloneAppObject(app);
@ -774,23 +746,30 @@ let DOMApplicationRegistry = {
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true); let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
let manFile = dir.clone(); let manFile = dir.clone();
manFile.append(manifestName); manFile.append("manifest.webapp");
let jsonManifest = aData.isPackage ? app.updateManifest : app.manifest; this._writeFile(manFile, JSON.stringify(app.manifest), function() {
this._writeFile(manFile, JSON.stringify(jsonManifest), function() { }); // If this a packaged app, move the zip file from the temp directory,
// and delete the temp directory.
if (app.packageId) {
let appFile = FileUtils.getFile("TmpD", ["webapps", app.packageId, "application.zip"],
true, true);
appFile.moveTo(dir, "application.zip");
let tmpDir = FileUtils.getDir("TmpD", ["webapps", app.packageId],
true, true);
try {
tmpDir.remove(true);
} catch(e) {
}
}
});
let manifest = new DOMApplicationManifest(jsonManifest, app.manifestURL); let manifest = new DOMApplicationManifest(app.manifest, app.origin);
if (manifest.appcache_path) { if (manifest.appcache_path) {
appObject.installState = "pending"; appObject.installState = "pending";
appObject.downloadAvailable = true; appObject.downloadAvailable = true;
appObject.downloading = true; appObject.downloading = true;
appObject.downloadSize = 0; appObject.downloadsize = 0;
appObject.readyToApplyDownload = false;
} else if (manifest.package_path) {
appObject.installState = "pending";
appObject.downloadAvailable = true;
appObject.downloading = true;
appObject.downloadSize = manifest.size;
appObject.readyToApplyDownload = false; appObject.readyToApplyDownload = false;
} else { } else {
appObject.installState = "installed"; appObject.installState = "installed";
@ -799,13 +778,9 @@ let DOMApplicationRegistry = {
appObject.readyToApplyDownload = false; appObject.readyToApplyDownload = false;
} }
appObject.name = manifest.name; appObject.name = app.manifest.name;
this.webapps[id] = appObject; this.webapps[id] = appObject;
["installState", "downloadAvailable",
"downloading", "downloadSize", "readyToApplyDownload"].forEach(function(aProp) {
aData.app[aProp] = appObject[aProp];
});
if (!aFromSync) if (!aFromSync)
this._saveApps((function() { this._saveApps((function() {
@ -815,16 +790,11 @@ let DOMApplicationRegistry = {
}).bind(this)); }).bind(this));
#ifdef MOZ_SYS_MSG #ifdef MOZ_SYS_MSG
if (!aData.isPackage) {
this._registerSystemMessages(app.manifest, app); this._registerSystemMessages(app.manifest, app);
this._registerActivities(app.manifest, app); this._registerActivities(app.manifest, app);
}
#endif #endif
this.startOfflineCacheDownload(manifest, appObject, aProfileDir); this.startOfflineCacheDownload(manifest, appObject, aProfileDir);
if (manifest.package_path) {
this.downloadPackage(manifest, appObject);
}
}, },
_nextLocalId: function() { _nextLocalId: function() {
@ -841,14 +811,6 @@ let DOMApplicationRegistry = {
return null; return null;
}, },
_appIdForManifestURL: function(aURI) {
for (let id in this.webapps) {
if (this.webapps[id].manifestURL == aURI)
return id;
}
return null;
},
makeAppId: function() { makeAppId: function() {
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
return uuidGenerator.generateUUID().toString(); return uuidGenerator.generateUUID().toString();
@ -876,9 +838,6 @@ let DOMApplicationRegistry = {
// the manifest file used to be named manifest.json, so fallback on this. // the manifest file used to be named manifest.json, so fallback on this.
let baseDir = (this.webapps[id].removable ? DIRECTORY_NAME : "coreAppsDir"); let baseDir = (this.webapps[id].removable ? DIRECTORY_NAME : "coreAppsDir");
let file = FileUtils.getFile(baseDir, ["webapps", id, "manifest.webapp"], true); let file = FileUtils.getFile(baseDir, ["webapps", id, "manifest.webapp"], true);
if (!file.exists()) {
file = FileUtils.getFile(baseDir, ["webapps", id, "update.webapp"], true);
}
if (!file.exists()) { if (!file.exists()) {
file = FileUtils.getFile(baseDir, ["webapps", id, "manifest.json"], true); file = FileUtils.getFile(baseDir, ["webapps", id, "manifest.json"], true);
} }
@ -892,7 +851,7 @@ let DOMApplicationRegistry = {
}).bind(this)); }).bind(this));
}, },
downloadPackage: function(aManifest, aApp) { installPackage: function(aData, aMm) {
// 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.
@ -901,21 +860,30 @@ let DOMApplicationRegistry = {
// - add the new app to the registry. // - add the new app to the registry.
// If we fail at any step, we backout the previous ones and return an error. // If we fail at any step, we backout the previous ones and return an error.
debug(JSON.stringify(aApp)); let id;
let manifestURL = "jar:" + aData.url + "!manifest.webapp";
// Check if we reinstall a known application.
for (let appId in this.webapps) {
if (this.webapps[appId].manifestURL == manifestURL) {
id = appId;
}
}
let id = this._appIdForManifestURL(aApp.manifestURL); // New application.
let app = this.webapps[id]; if (!id) {
id = this.makeAppId();
}
let dir = FileUtils.getDir("TmpD", ["webapps", id], true, true);
// 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.
function cleanup(aError) { function cleanup(aError) {
debug("Cleanup: " + aError);
let dir = FileUtils.getDir("TmpD", ["webapps", id], true, true);
try { try {
dir.remove(true); dir.remove(true);
} catch (e) { } } catch (e) { }
this.broadcastMessage("Webapps:PackageEvent", aMm.sendAsyncMessage("Webapps:Install:Return:KO",
{ type: "error", { oid: aData.oid,
manifestURL: aApp.manifestURL, requestID: aData.requestID,
error: aError }); error: aError });
} }
@ -960,40 +928,7 @@ let DOMApplicationRegistry = {
return (getAppManifestStatus(aManifest) <= getInferedStatus()); return (getAppManifestStatus(aManifest) <= getInferedStatus());
} }
debug("About to download " + aManifest.fullPackagePath()); NetUtil.asyncFetch(aData.url, function(aInput, aResult, aRequest) {
let requestChannel = NetUtil.newChannel(aManifest.fullPackagePath())
.QueryInterface(Ci.nsIHttpChannel);
this.downloads[aApp.manifestURL] =
{ channel:requestChannel,
appId: id,
previousState: "pending"
};
requestChannel.notificationCallbacks = {
QueryInterface: function notifQI(aIID) {
if (aIID.equals(Ci.nsISupports) ||
aIID.equals(Ci.nsIProgressEventSink))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
getInterface: function notifGI(aIID) {
return this.QueryInterface(aIID);
},
onProgress: function notifProgress(aRequest, aContext,
aProgress, aProgressMax) {
debug("onProgress: " + aProgress + "/" + aProgressMax);
app.progress = aProgress;
DOMApplicationRegistry.broadcastMessage("Webapps:PackageEvent",
{ type: "progress",
manifestURL: aApp.manifestURL,
progress: aProgress });
},
onStatus: function notifStatus(aRequest, aContext, aStatus, aStatusArg) { }
}
NetUtil.asyncFetch(requestChannel,
function(aInput, aResult, aRequest) {
if (!Components.isSuccessCode(aResult)) { if (!Components.isSuccessCode(aResult)) {
// We failed to fetch the zip. // We failed to fetch the zip.
cleanup("NETWORK_ERROR"); cleanup("NETWORK_ERROR");
@ -1009,7 +944,23 @@ let DOMApplicationRegistry = {
cleanup("DOWNLOAD_ERROR"); cleanup("DOWNLOAD_ERROR");
return; return;
} }
// Build a data structure to call the webapps confirmation dialog :
// - load the manifest from the zip
// - set data.app.(origin, install_origin, manifestURL, manifest, receipts, categories)
// - call notifyObservers(this, "webapps-ask-install", JSON.stringify(msg));
let msg = {
from: aData.from,
oid: aData.oid,
requestID: aData.requestID,
app: {
packageId: id,
installOrigin: aData.installOrigin,
origin: "app://" + id,
manifestURL: manifestURL,
receipts: aData.receipts,
categories: aData.categories
}
}
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"] let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
.createInstance(Ci.nsIZipReader); .createInstance(Ci.nsIZipReader);
try { try {
@ -1019,50 +970,19 @@ let DOMApplicationRegistry = {
} }
let istream = zipReader.getInputStream("manifest.webapp"); let istream = zipReader.getInputStream("manifest.webapp");
msg.app.manifest = JSON.parse(NetUtil.readInputStreamToString(istream,
// Obtain a converter to read from a UTF-8 encoded input stream. istream.available()) || "");
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] if (!AppsUtils.checkManifest(msg.app.manifest, aData.installOrigin)) {
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let manifest = JSON.parse(converter.ConvertToUnicode(NetUtil.readInputStreamToString(istream,
istream.available()) || ""));
if (!AppsUtils.checkManifest(manifest, aApp.installOrigin)) {
throw "INVALID_MANIFEST"; throw "INVALID_MANIFEST";
} }
if (!checkAppStatus(manifest)) { if (!checkAppStatus(msg.app.manifest)) {
throw "INVALID_SECURITY_LEVEL"; throw "INVALID_SECURITY_LEVEL";
} }
// Success! Move the zip out of TmpD. msg.app.appStatus = getAppStatus(msg.app.manifest);
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true); Services.obs.notifyObservers(this, "webapps-ask-install",
zipFile.moveTo(dir, "application.zip"); JSON.stringify(msg));
let tmpDir = FileUtils.getDir("TmpD", ["webapps", id], true, true);
try {
tmpDir.remove(true);
} catch(e) { }
// Save the manifest
let manFile = dir.clone();
manFile.append("manifest.webapp");
DOMApplicationRegistry._writeFile(manFile,
JSON.stringify(manifest),
function() { });
// Set state and fire events.
app.installState = "installed";
app.dowloading = false;
app.dowloadavailable = false;
DOMApplicationRegistry._saveApps(function() {
debug("About to fire Webapps:PackageEvent");
DOMApplicationRegistry.broadcastMessage("Webapps:PackageEvent",
{ type: "installed",
manifestURL: aApp.manifestURL,
app: app,
manifest: manifest });
delete DOMApplicationRegistry.downloads[aApp.manifestURL]
});
} catch (e) { } catch (e) {
// XXX we may need new error messages. // XXX we may need new error messages.
cleanup(e); cleanup(e);
@ -1222,7 +1142,7 @@ let DOMApplicationRegistry = {
return; return;
let id = this._appId(aOrigin); let id = this._appId(aOrigin);
if (!id || this.webapps[id].installState == "pending") { if (!id) {
aCallback(null); aCallback(null);
return; return;
} }
@ -1575,14 +1495,6 @@ DOMApplicationManifest.prototype = {
return this._localeProp("orientation"); return this._localeProp("orientation");
}, },
get package_path() {
return this._localeProp("package_path");
},
get size() {
return this._manifest["size"] || 0;
},
iconURLForSize: function(aSize) { iconURLForSize: function(aSize) {
let icons = this._localeProp("icons"); let icons = this._localeProp("icons");
if (!icons) if (!icons)
@ -1626,11 +1538,6 @@ DOMApplicationManifest.prototype = {
fullAppcachePath: function() { fullAppcachePath: function() {
let appcachePath = this._localeProp("appcache_path"); let appcachePath = this._localeProp("appcache_path");
return this._origin.resolve(appcachePath ? appcachePath : ""); return this._origin.resolve(appcachePath ? appcachePath : "");
},
fullPackagePath: function() {
let packagePath = this._localeProp("package_path");
return this._origin.resolve(packagePath ? packagePath : "");
} }
}; };