Bug 852848 - Add support for app-specific redirections r=bz,ferjm

This commit is contained in:
Fabrice Desré 2013-05-14 12:00:09 -07:00
parent c2e3ffc78d
commit 6a0039c103
5 changed files with 105 additions and 6 deletions

View File

@ -202,6 +202,8 @@
#include "nsIAppShellService.h"
#include "nsAppShellCID.h"
#include "nsIAppsService.h"
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
@ -6436,6 +6438,30 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
if (!oldURI || !newURI) {
return;
}
// Check if we have a redirect registered for this url.
uint32_t appId;
nsresult rv = GetAppId(&appId);
if (NS_FAILED(rv)) {
return;
}
if (appId != nsIScriptSecurityManager::NO_APP_ID &&
appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
nsCOMPtr<nsIAppsService> appsService =
do_GetService(APPS_SERVICE_CONTRACTID);
NS_ASSERTION(appsService, "No AppsService available");
nsCOMPtr<nsIURI> redirect;
rv = appsService->GetRedirect(appId, newURI, getter_AddRefs(redirect));
if (NS_SUCCEEDED(rv) && redirect) {
aNewChannel->Cancel(NS_BINDING_ABORTED);
rv = LoadURI(redirect, nullptr, 0, false);
if (NS_SUCCEEDED(rv)) {
return;
}
}
}
// On session restore we get a redirect from page to itself. Don't count it.
bool equals = false;
if (mTiming &&

View File

@ -13,6 +13,7 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const APPS_SERVICE_CID = Components.ID("{05072afa-92fe-45bf-ae22-39b69c117058}");
@ -78,6 +79,42 @@ AppsService.prototype = {
return DOMApplicationRegistry.getAppInfo(aAppId);
},
getRedirect: function getRedirect(aLocalId, aURI) {
debug("getRedirect for " + aLocalId + " " + aURI.spec);
if (aLocalId == Ci.nsIScriptSecurityManager.NO_APP_ID ||
aLocalId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) {
return null;
}
let app = DOMApplicationRegistry.getAppByLocalId(aLocalId);
if (app && app.redirects) {
let spec = aURI.spec;
for (let i = 0; i < app.redirects.length; i++) {
let redirect = app.redirects[i];
if (spec.startsWith(redirect.from)) {
// Prepend the app origin to the redirection. We need that since
// the origin of packaged apps is a uuid created at install time.
let to = app.origin + redirect.to;
// If we have a ? or a # in the current URL, add this part to the
// redirection.
let index = -1;
index = spec.indexOf('?');
if (index == -1) {
index = spec.indexOf('#');
}
if (index != -1) {
to += spec.substring(index);
}
debug('App specific redirection from ' + spec + ' to ' + to);
return Services.io.newURI(to, null, null);
}
}
} else {
return null;
}
},
classID : APPS_SERVICE_CID,
QueryInterface : XPCOMUtils.generateQI([Ci.nsIAppsService])
}

View File

@ -20,13 +20,13 @@ XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
// Shared code for AppsServiceChild.jsm, Webapps.jsm and Webapps.js
this.EXPORTED_SYMBOLS = ["AppsUtils", "ManifestHelper"];
this.EXPORTED_SYMBOLS = ["AppsUtils", "ManifestHelper", "isAbsoluteURI"];
function debug(s) {
//dump("-*- AppsUtils.jsm: " + s + "\n");
}
function isAbsoluteURI(aURI) {
this.isAbsoluteURI = function(aURI) {
let foo = Services.io.newURI("http://foo", null, null);
let bar = Services.io.newURI("http://bar", null, null);
return Services.io.newURI(aURI, null, foo).prePath != foo.prePath ||
@ -92,7 +92,8 @@ this.AppsUtils = {
installerAppId: aApp.installerAppId || Ci.nsIScriptSecurityManager.NO_APP_ID,
installerIsBrowser: !!aApp.installerIsBrowser,
storeId: aApp.storeId || "",
storeVersion: aApp.storeVersion || 0
storeVersion: aApp.storeVersion || 0,
redirects: aApp.redirects
};
},

View File

@ -196,6 +196,24 @@ this.DOMApplicationRegistry = {
this._saveApps();
},
// Ensure that the .to property in redirects is a relative URL.
sanitizeRedirects: function sanitizeRedirects(aSource) {
if (!aSource) {
return null;
}
let res = [];
for (let i = 0; i < aSource.length; i++) {
let redirect = aSource[i];
if (redirect.from && redirect.to &&
isAbsoluteURI(redirect.from) &&
!isAbsoluteURI(redirect.to)) {
res.push(redirect);
}
}
return res.length > 0 ? res : null;
},
// Registers all the activities and system messages.
registerAppsHandlers: function registerAppsHandlers(aRunUpdate) {
this.notifyAppsRegistryStart();
@ -211,7 +229,11 @@ this.DOMApplicationRegistry = {
// twice
this._readManifests(ids, (function readCSPs(aResults) {
aResults.forEach(function registerManifest(aResult) {
this.webapps[aResult.id].csp = aResult.manifest.csp || "";
let app = this.webapps[aResult.id];
app.csp = aResult.manifest.csp || "";
if (app.appStatus >= Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) {
app.redirects = this.sanitizeRedirects(aResult.redirects);
}
}, this);
}).bind(this));
@ -673,6 +695,9 @@ this.DOMApplicationRegistry = {
let manifest = aResult.manifest;
app.name = manifest.name;
app.csp = manifest.csp || "";
if (app.appStatus >= Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) {
app.redirects = this.sanitizeRedirects(manifest.redirects);
}
this._registerSystemMessages(manifest, app);
appsToRegister.push({ manifest: manifest, app: app });
}, this);
@ -1327,11 +1352,14 @@ this.DOMApplicationRegistry = {
return [toHexString(hash.charCodeAt(i)) for (i in hash)].join("");
},
// Updates the activities and system message handlers.
// Updates the redirect mapping, activities and system message handlers.
// aOldManifest can be null if we don't have any handler to unregister.
updateAppHandlers: function(aOldManifest, aNewManifest, aApp) {
debug("updateAppHandlers: old=" + aOldManifest + " new=" + aNewManifest);
this.notifyAppsRegistryStart();
if (aApp.appStatus >= Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) {
aApp.redirects = this.sanitizeRedirects(aNewManifest.redirects);
}
if (supportSystemMessages()) {
if (aOldManifest) {

View File

@ -6,6 +6,7 @@
interface mozIDOMApplication;
interface mozIApplication;
interface nsIURI;
%{C++
#define APPS_SERVICE_CID { 0x05072afa, 0x92fe, 0x45bf, { 0xae, 0x22, 0x39, 0xb6, 0x9c, 0x11, 0x70, 0x58 } }
@ -16,7 +17,7 @@ interface mozIApplication;
* This service allows accessing some DOMApplicationRegistry methods from
* non-javascript code.
*/
[scriptable, uuid(1113c6e3-28a2-4315-be10-8b3230eecc0f)]
[scriptable, uuid(27b995cf-bec8-47de-aa48-6117c950fce3)]
interface nsIAppsService : nsISupports
{
mozIDOMApplication getAppByManifestURL(in DOMString manifestURL);
@ -63,6 +64,12 @@ interface nsIAppsService : nsISupports
jsval getAppInfo(in DOMString appId);
/**
* Returns a URI to redirect to when we get a redirection to 'uri'.
* Returns null if no redirection is declared for this uri.
*/
nsIURI getRedirect(in unsigned long localId, in nsIURI uri);
/**
* Returns the localId if the app was installed from a store
*/