Bug 1196021 - Pass requesting channel to PackagedAppService::GetResource r=ckerschb

This commit is contained in:
Valentin Gosu 2015-08-25 03:06:24 +02:00
Родитель ac53c9a29f
Коммит 7833654240
5 изменённых файлов: 121 добавлений и 73 удалений

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

@ -5,10 +5,8 @@
#include "nsISupports.idl"
interface nsIPrincipal;
interface nsILoadContextInfo;
interface nsIChannel;
interface nsICacheEntryOpenCallback;
interface nsILoadInfo;
%{C++
#define PACKAGED_APP_TOKEN "!//"
@ -17,16 +15,16 @@ interface nsILoadInfo;
/**
* nsIPackagedAppService
*/
[scriptable, builtinclass, uuid(b36efde7-6596-4082-a5fc-fc223148489f)]
[scriptable, builtinclass, uuid(9c96c638-e80c-4dce-abec-c96fdb7a25d8)]
interface nsIPackagedAppService : nsISupports
{
/**
* @param aPrincipal
* the principal associated to the URL of a packaged resource
* URL format: package_url + PACKAGED_APP_TOKEN + resource_path
* example: http://test.com/path/to/package!//resource.html
* @param aFlags
* the load flags used for downloading the package
* @param aChannel
* this param is passed to the packaged app service in order to provide
* info about the requesting channel, which wants to access the contents
* of a packaged app resource. Its URI has the following format:
* http://domain.com/path/to/package.pak!//path/to/subresource.html
*
* @param aCallback
* an object implementing nsICacheEntryOpenCallback
* this is the target of the async result of the operation
@ -35,18 +33,12 @@ interface nsIPackagedAppService : nsISupports
* the cached entry, if one exists, or an error code otherwise
* aCallback is kept alive using an nsCOMPtr until OnCacheEntryAvailable
* is called
* @param aInfo
* an object used to determine the cache jar this resource goes in.
* usually created by calling GetLoadContextInfo(requestingChannel)
*
* Calling this method will either download the package containing the given
* resource URI, store it in the cache and pass the cache entry to aCallback,
* or if that resource has already been downloaded it will be served from
* the cache.
*/
void getResource(in nsIPrincipal aPrincipal,
in nsILoadInfo aLoadInfo,
in uint32_t aFlags,
in nsILoadContextInfo aInfo,
void getResource(in nsIChannel aChannel,
in nsICacheEntryOpenCallback aCallback);
};

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

@ -690,29 +690,55 @@ PackagedAppService::GetPackageURI(nsIURI *aURI, nsIURI **aPackageURI)
}
NS_IMETHODIMP
PackagedAppService::GetResource(nsIPrincipal *aPrincipal,
nsILoadInfo *aLoadInfo,
uint32_t aLoadFlags,
nsILoadContextInfo *aInfo,
PackagedAppService::GetResource(nsIChannel *aChannel,
nsICacheEntryOpenCallback *aCallback)
{
// Check arguments are not null
if (!aPrincipal || !aLoadInfo || !aCallback || !aInfo) {
MOZ_RELEASE_ASSERT(NS_IsMainThread(), "mDownloadingPackages hashtable is not thread safe");
LOG(("[%p] PackagedAppService::GetResource(aChannel: %p, aCallback: %p)\n",
this, aChannel, aCallback));
if (!aChannel || !aCallback) {
return NS_ERROR_INVALID_ARG;
}
nsresult rv;
nsIScriptSecurityManager *securityManager =
nsContentUtils::GetSecurityManager();
if (!securityManager) {
LOG(("[%p] > No securityManager\n", this));
return NS_ERROR_UNEXPECTED;
}
nsCOMPtr<nsIPrincipal> principal;
rv = securityManager->GetChannelURIPrincipal(aChannel, getter_AddRefs(principal));
if (NS_FAILED(rv) || !principal) {
LOG(("[%p] > Error getting principal rv=%X principal=%p\n",
this, rv, principal.get()));
return NS_FAILED(rv) ? rv : NS_ERROR_NULL_POINTER;
}
nsCOMPtr<nsIURI> uri;
rv = aPrincipal->GetURI(getter_AddRefs(uri));
if (NS_WARN_IF(NS_FAILED(rv))) {
nsCOMPtr<nsILoadContextInfo> loadContextInfo = GetLoadContextInfo(aChannel);
if (!loadContextInfo) {
LOG(("[%p] > Channel has no loadContextInfo\n", this));
return NS_ERROR_NULL_POINTER;
}
nsLoadFlags loadFlags = 0;
rv = aChannel->GetLoadFlags(&loadFlags);
if (NS_FAILED(rv)) {
LOG(("[%p] > Error calling GetLoadFlags rv=%X\n", this, rv));
return rv;
}
LogURI("PackagedAppService::GetResource", this, uri, aInfo);
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
MOZ_RELEASE_ASSERT(NS_IsMainThread(), "mDownloadingPackages hashtable is not thread safe");
nsCOMPtr<nsIURI> uri;
rv = principal->GetURI(getter_AddRefs(uri));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("[%p] > Error calling GetURI rv=%X\n", this, rv));
return rv;
}
LogURI("PackagedAppService::GetResource", this, uri, loadContextInfo);
nsCOMPtr<nsIURI> packageURI;
rv = GetPackageURI(uri, getter_AddRefs(packageURI));
if (NS_FAILED(rv)) {
@ -720,7 +746,7 @@ PackagedAppService::GetResource(nsIPrincipal *aPrincipal,
}
nsAutoCString key;
CacheFileUtils::AppendKeyPrefix(aInfo, key);
CacheFileUtils::AppendKeyPrefix(loadContextInfo, key);
{
nsAutoCString spec;
@ -743,8 +769,8 @@ PackagedAppService::GetResource(nsIPrincipal *aPrincipal,
nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannelInternal(
getter_AddRefs(channel), packageURI,
aLoadInfo,
nullptr, nullptr, aLoadFlags);
loadInfo,
nullptr, nullptr, loadFlags);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -759,7 +785,7 @@ PackagedAppService::GetResource(nsIPrincipal *aPrincipal,
}
downloader = new PackagedAppDownloader();
rv = downloader->Init(aInfo, key);
rv = downloader->Init(loadContextInfo, key);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -785,7 +811,7 @@ PackagedAppService::GetResource(nsIPrincipal *aPrincipal,
nsRefPtr<PackagedAppChannelListener> listener =
new PackagedAppChannelListener(downloader, mimeConverter);
if (aLoadInfo->GetEnforceSecurity()) {
if (loadInfo && loadInfo->GetEnforceSecurity()) {
return channel->AsyncOpen2(listener);
}

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

@ -5206,12 +5206,6 @@ nsHttpChannel::BeginConnect()
// by the packaged app service into the cache, and the cache entry will
// be passed to OnCacheEntryAvailable.
// Pass the original load flags to the packaged app request.
uint32_t loadFlags = mLoadFlags;
mLoadFlags |= LOAD_ONLY_FROM_CACHE;
mLoadFlags |= LOAD_FROM_CACHE;
mLoadFlags &= ~VALIDATE_ALWAYS;
nsCOMPtr<nsIPackagedAppService> pas =
do_GetService("@mozilla.org/network/packaged-app-service;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -5219,12 +5213,18 @@ nsHttpChannel::BeginConnect()
return rv;
}
nsCOMPtr<nsIPrincipal> principal = GetURIPrincipal();
nsCOMPtr<nsILoadContextInfo> loadContextInfo = GetLoadContextInfo(this);
rv = pas->GetResource(principal, mLoadInfo, loadFlags, loadContextInfo, this);
rv = pas->GetResource(this, this);
if (NS_FAILED(rv)) {
AsyncAbort(rv);
}
// We need to alter the flags so the cache entry returned by the
// packaged app service is always accepted. Revalidation is handled
// by the service.
mLoadFlags |= LOAD_ONLY_FROM_CACHE;
mLoadFlags |= LOAD_FROM_CACHE;
mLoadFlags &= ~VALIDATE_ALWAYS;
return rv;
}

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

@ -60,16 +60,24 @@ function packagedAppContentHandler(metadata, response)
response.bodyOutputStream.write(body, body.length);
}
function getPrincipal(url) {
function getChannelForURL(url) {
let uri = createURI(url);
let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
let uri = createURI(url);
return ssm.createCodebasePrincipal(uri, {});
}
let principal = ssm.createCodebasePrincipal(uri, {});
let tmpChannel =
NetUtil.newChannel({
uri: url,
loadingPrincipal: principal,
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER
});
function getLoadInfo(url) {
let tmpChannel = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true});
return tmpChannel.loadInfo;
tmpChannel.notificationCallbacks =
new LoadContextCallback(principal.appId,
principal.isInBrowserElement,
false,
false);
return tmpChannel;
}
// The package content
@ -135,6 +143,15 @@ function run_test()
add_test(test_bad_package);
add_test(test_bad_package_404);
// Channels created by addons could have no load info.
// In debug mode this triggers an assertion, but we still want to test that
// it works in optimized mode. See bug 1196021 comment 17
if (Components.classes["@mozilla.org/xpcom/debug;1"]
.getService(Components.interfaces.nsIDebug2)
.isDebugBuild == false) {
add_test(test_channel_no_loadinfo);
}
// run tests
run_next_test();
}
@ -185,13 +202,10 @@ var cacheListener = new packagedResourceListener(testData.content[0].data);
// These calls should fail, since one of the arguments is invalid or null
function test_bad_args() {
let principal = getPrincipal("http://test.com/package!//test");
let loadInfo = getLoadInfo("http://test.com/package!//test");
Assert.throws(() => { paservice.getResource(getPrincipal("http://test.com"), loadInfo, 0, LoadContextInfo.default, cacheListener); }, "url's with no !// aren't allowed");
Assert.throws(() => { paservice.getResource(principal, loadInfo, 0, LoadContextInfo.default, null); }, "should have a callback");
Assert.throws(() => { paservice.getResource(null, loadInfo, 0, LoadContextInfo.default, cacheListener); }, "should have a principal");
Assert.throws(() => { paservice.getResource(principal, loadInfo, 0, null, cacheListener); }, "should have a LoadContextInfo");
Assert.throws(() => { paservice.getResource(principal, null, 0, LoadContextInfo.default, cacheListener); }, "should have a LoadInfo");
Assert.throws(() => { paservice.getResource(getChannelForURL("http://test.com"), cacheListener); }, "url's with no !// aren't allowed");
Assert.throws(() => { paservice.getResource(getChannelForURL("http://test.com/package!//test"), null); }, "should have a callback");
Assert.throws(() => { paservice.getResource(null, cacheListener); }, "should have a channel");
run_next_test();
}
@ -201,14 +215,14 @@ function test_bad_args() {
function test_callback_gets_called() {
packagePath = "/package";
let url = uri + packagePath + "!//index.html";
paservice.getResource(getPrincipal(url), getLoadInfo(url), 0, LoadContextInfo.default, cacheListener);
paservice.getResource(getChannelForURL(url), cacheListener);
}
// Tests that requesting the same resource returns the same content
function test_same_content() {
packagePath = "/package";
let url = uri + packagePath + "!//index.html";
paservice.getResource(getPrincipal(url), getLoadInfo(url), 0, LoadContextInfo.default, cacheListener);
paservice.getResource(getChannelForURL(url), cacheListener);
}
// Check the content handler has been called the expected number of times.
@ -221,8 +235,8 @@ function test_request_number() {
function test_updated_package() {
packagePath = "/package";
let url = uri + packagePath + "!//index.html";
paservice.getResource(getPrincipal(url), getLoadInfo(url), 0, LoadContextInfo.default,
new packagedResourceListener(testData.content[0].data.replace(/\.\.\./g, 'xxx')));
paservice.getResource(getChannelForURL(url),
new packagedResourceListener(testData.content[0].data.replace(/\.\.\./g, 'xxx')));
}
// ----------------------------------------------------------------------------
@ -246,14 +260,14 @@ var listener404 = {
function test_package_does_not_exist() {
packagePath = "/package_non_existent";
let url = uri + packagePath + "!//index.html";
paservice.getResource(getPrincipal(url), getLoadInfo(url), 0, LoadContextInfo.default, listener404);
paservice.getResource(getChannelForURL(url), listener404);
}
// Tests that an error is returned for a non existing resource in a package
function test_file_does_not_exist() {
packagePath = "/package"; // This package exists
let url = uri + packagePath + "!//file_non_existent.html";
paservice.getResource(getPrincipal(url), getLoadInfo(url), 0, LoadContextInfo.default, listener404);
paservice.getResource(getChannelForURL(url), listener404);
}
// ----------------------------------------------------------------------------
@ -295,14 +309,23 @@ function packagedAppBadContentHandler(metadata, response)
function test_bad_package() {
packagePath = "/badPackage";
let url = uri + packagePath + "!//index.html";
paservice.getResource(getPrincipal(url), getLoadInfo(url), 0, LoadContextInfo.default, cacheListener);
paservice.getResource(getChannelForURL(url), cacheListener);
}
// Checks that the request for a non-existent resource doesn't hang for a bad package
function test_bad_package_404() {
packagePath = "/badPackage";
let url = uri + packagePath + "!//file_non_existent.html";
paservice.getResource(getPrincipal(url), getLoadInfo(url), 0, LoadContextInfo.default, listener404);
paservice.getResource(getChannelForURL(url), listener404);
}
// ----------------------------------------------------------------------------
// NOTE: This test only runs in NON-DEBUG mode.
function test_channel_no_loadinfo() {
packagePath = "/package";
let url = uri + packagePath + "!//index.html";
let channel = getChannelForURL(url);
channel.loadInfo = null;
paservice.getResource(channel, cacheListener);
}

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

@ -12,16 +12,24 @@ function packagedAppContentHandler(metadata, response)
gRequestNo++;
}
function getPrincipal(url) {
function getChannelForURL(url) {
let uri = createURI(url);
let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
let uri = createURI(url);
return ssm.createCodebasePrincipal(uri, {});
}
let principal = ssm.createCodebasePrincipal(uri, {});
let tmpChannel =
NetUtil.newChannel({
uri: url,
loadingPrincipal: principal,
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER
});
function getLoadInfo(url) {
let tmpChannel = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true});
return tmpChannel.loadInfo;
tmpChannel.notificationCallbacks =
new LoadContextCallback(principal.appId,
principal.isInBrowserElement,
false,
false);
return tmpChannel;
}
var subresourcePaths = [
@ -126,8 +134,7 @@ function test_paths() {
packagePath = "/package/" + i;
dump("Iteration " + i + "\n");
let url = uri + packagePath + "!//" + subresourcePaths[i][1];
paservice.getResource(getPrincipal(url), getLoadInfo(url), 0,
LoadContextInfo.default,
paservice.getResource(getChannelForURL(url),
new packagedResourceListener(subresourcePaths[i][1], content));
yield undefined;
}