From 1e73e39a9d4b99978c222ada1508efadb5c1aa9b Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Sat, 8 Aug 2015 07:11:56 +0200 Subject: [PATCH] Bug 1187159 - Pass principal and flags from the requesting channel to the packaged app channel r=honzab --- netwerk/base/nsIPackagedAppService.idl | 38 +++++++++++-------- netwerk/protocol/http/PackagedAppService.cpp | 36 +++++++++--------- netwerk/protocol/http/PackagedAppService.h | 5 +-- netwerk/protocol/http/nsHttpChannel.cpp | 7 +++- .../test/unit/test_packaged_app_service.js | 35 ++++++++++------- 5 files changed, 69 insertions(+), 52 deletions(-) diff --git a/netwerk/base/nsIPackagedAppService.idl b/netwerk/base/nsIPackagedAppService.idl index fb2112f35b46..1c20ebd576ca 100644 --- a/netwerk/base/nsIPackagedAppService.idl +++ b/netwerk/base/nsIPackagedAppService.idl @@ -5,7 +5,7 @@ #include "nsISupports.idl" -interface nsIURI; +interface nsIPrincipal; interface nsILoadContextInfo; interface nsICacheEntryOpenCallback; @@ -16,27 +16,35 @@ interface nsICacheEntryOpenCallback; /** * nsIPackagedAppService */ -[scriptable, builtinclass, uuid(77f9a34d-d082-43f1-9f83-e852d0173cd5)] +[scriptable, builtinclass, uuid(f35e5229-d08a-46eb-a574-2db4e22aee98)] interface nsIPackagedAppService : nsISupports { /** - * @aURI is a URL to a packaged resource - * - format: package_url + PACKAGED_APP_TOKEN + resource_path - * - example: http://test.com/path/to/package!//resource.html - * @aCallback is an object implementing nsICacheEntryOpenCallback - * - this is the target of the async result of the operation - * - aCallback->OnCacheEntryCheck() is called to verify the entry is valid - * - aCallback->OnCacheEntryAvailable() is called with a pointer to the - * the cached entry, if one exists, or an error code otherwise - * - aCallback is kept alive using an nsCOMPtr until OnCacheEntryAvailable - * is called - * @aInfo is an object used to determine the cache jar this resource goes in. - * - usually created by calling GetLoadContextInfo(requestingChannel) + * @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 aCallback + * an object implementing nsICacheEntryOpenCallback + * this is the target of the async result of the operation + * aCallback->OnCacheEntryCheck() is called to verify the entry is valid + * aCallback->OnCacheEntryAvailable() is called with a pointer to the + * 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 requestURI(in nsIURI aURI, in nsILoadContextInfo aInfo, in nsICacheEntryOpenCallback aCallback); + void getResource(in nsIPrincipal aPrincipal, + in uint32_t aFlags, + in nsILoadContextInfo aInfo, + in nsICacheEntryOpenCallback aCallback); }; diff --git a/netwerk/protocol/http/PackagedAppService.cpp b/netwerk/protocol/http/PackagedAppService.cpp index d3840754d052..67d31803ab12 100644 --- a/netwerk/protocol/http/PackagedAppService.cpp +++ b/netwerk/protocol/http/PackagedAppService.cpp @@ -605,23 +605,30 @@ PackagedAppService::GetPackageURI(nsIURI *aURI, nsIURI **aPackageURI) } NS_IMETHODIMP -PackagedAppService::RequestURI(nsIURI *aURI, - nsILoadContextInfo *aInfo, - nsICacheEntryOpenCallback *aCallback) +PackagedAppService::GetResource(nsIPrincipal *aPrincipal, + uint32_t aLoadFlags, + nsILoadContextInfo *aInfo, + nsICacheEntryOpenCallback *aCallback) { // Check arguments are not null - if (!aURI || !aCallback || !aInfo) { + if (!aPrincipal || !aCallback || !aInfo) { return NS_ERROR_INVALID_ARG; } - nsresult rv; - LogURI("PackagedAppService::RequestURI", this, aURI, aInfo); + + nsCOMPtr uri; + rv = aPrincipal->GetURI(getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + LogURI("PackagedAppService::GetResource", this, uri, aInfo); MOZ_RELEASE_ASSERT(NS_IsMainThread(), "mDownloadingPackages hashtable is not thread safe"); nsCOMPtr packageURI; - rv = GetPackageURI(aURI, getter_AddRefs(packageURI)); + rv = GetPackageURI(uri, getter_AddRefs(packageURI)); if (NS_FAILED(rv)) { return rv; } @@ -643,22 +650,15 @@ PackagedAppService::RequestURI(nsIURI *aURI, // downloaded, we will add the callback to the package's queue, and it will // be called once the file is processed and saved in the cache. - downloader->AddCallback(aURI, aCallback); + downloader->AddCallback(uri, aCallback); return NS_OK; } - // We need to set this flag, because the package metadata - // needs to have a separate entry for anonymous channels. - uint32_t extra_flags = 0; - if (aInfo->IsAnonymous()) { - extra_flags = nsIRequest::LOAD_ANONYMOUS; - } - nsCOMPtr channel; rv = NS_NewChannel( - getter_AddRefs(channel), packageURI, nsContentUtils::GetSystemPrincipal(), + getter_AddRefs(channel), packageURI, aPrincipal, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_OTHER, nullptr, nullptr, - nsIRequest::LOAD_NORMAL | extra_flags); + aLoadFlags); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -678,7 +678,7 @@ PackagedAppService::RequestURI(nsIURI *aURI, return rv; } - downloader->AddCallback(aURI, aCallback); + downloader->AddCallback(uri, aCallback); nsCOMPtr streamconv = do_GetService("@mozilla.org/streamConverters;1", &rv); diff --git a/netwerk/protocol/http/PackagedAppService.h b/netwerk/protocol/http/PackagedAppService.h index db3e20660da9..07fa002233b0 100644 --- a/netwerk/protocol/http/PackagedAppService.h +++ b/netwerk/protocol/http/PackagedAppService.h @@ -23,10 +23,7 @@ class nsHttpResponseHead; // or downloads the package. // The package format is defined at: // https://w3ctag.github.io/packaging-on-the-web/#streamable-package-format -// Downloading the package is triggered by calling requestURI(aURI, aInfo, aCallback) -// aURI is the subresource uri - http://domain.com/path/package!//resource.html -// aInfo is a nsILoadContextInfo used to pick the cache jar the resource goes into -// aCallback is the target of the async call to requestURI +// Downloading the package is triggered by calling getResource() class PackagedAppService final : public nsIPackagedAppService { diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 9b1deca8392b..de382a55ebee 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -5197,6 +5197,10 @@ nsHttpChannel::BeginConnect() // If this is a packaged app resource, the content will be fetched // 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; @@ -5207,7 +5211,8 @@ nsHttpChannel::BeginConnect() return rv; } - rv = pas->RequestURI(mURI, GetLoadContextInfo(this), this); + nsCOMPtr principal = GetURIPrincipal(); + rv = pas->GetResource(principal, loadFlags, GetLoadContextInfo(this), this); if (NS_FAILED(rv)) { AsyncAbort(rv); } diff --git a/netwerk/test/unit/test_packaged_app_service.js b/netwerk/test/unit/test_packaged_app_service.js index 493e973f2d4d..dfa3ab3bd047 100644 --- a/netwerk/test/unit/test_packaged_app_service.js +++ b/netwerk/test/unit/test_packaged_app_service.js @@ -7,14 +7,14 @@ // ---------------------------------------------------------------------------- // // test_bad_args -// - checks that calls to nsIPackagedAppService::requestURI do not accept a null argument +// - checks that calls to nsIPackagedAppService::GetResource do not accept a null argument // test_callback_gets_called // - checks the regular use case -> requesting a resource should asynchronously return an entry // test_same_content // - makes another request for the same file, and checks that the same content is returned // test_request_number // - this test does not make a request, but checks that the package has only -// been requested once. The entry returned by the call to requestURI in +// been requested once. The entry returned by the call to getResource in // test_same_content should be returned from the cache. // // test_package_does_not_exist @@ -59,6 +59,13 @@ function packagedAppContentHandler(metadata, response) response.bodyOutputStream.write(body, body.length); } +function getPrincipal(url) { + let uri = createURI(url); + return Components.classes["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager) + .getNoAppCodebasePrincipal(uri); +} + // The package content // getData formats it as described at http://www.w3.org/TR/web-packaging/#streamable-package-format var testData = { @@ -92,7 +99,7 @@ XPCOMUtils.defineLazyGetter(this, "uri", function() { var httpserver = null; // The packaged app service initialized in run_test var paservice = null; -// This variable is set before requestURI is called. The listener uses this variable +// This variable is set before getResource is called. The listener uses this variable // to check the correct resource path for the returned entry var packagePath = null; @@ -170,10 +177,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() { - Assert.throws(() => { paservice.requestURI(createURI("http://test.com"), LoadContextInfo.default, cacheListener); }, "url's with no !// aren't allowed"); - Assert.throws(() => { paservice.requestURI(createURI("http://test.com/package!//test"), LoadContextInfo.default, null); }, "should have a callback"); - Assert.throws(() => { paservice.requestURI(null, LoadContextInfo.default, cacheListener); }, "should have a URI"); - Assert.throws(() => { paservice.requestURI(createURI("http://test.com/package!//test"), null, cacheListener); }, "should have a LoadContextInfo"); + Assert.throws(() => { paservice.getResource(getPrincipal("http://test.com"), 0, LoadContextInfo.default, cacheListener); }, "url's with no !// aren't allowed"); + Assert.throws(() => { paservice.getResource(getPrincipal("http://test.com/package!//test"), 0, LoadContextInfo.default, null); }, "should have a callback"); + Assert.throws(() => { paservice.getResource(null, 0, LoadContextInfo.default, cacheListener); }, "should have a URI"); + Assert.throws(() => { paservice.getResource(getPrincipal("http://test.com/package!//test"), null, cacheListener); }, "should have a LoadContextInfo"); run_next_test(); } @@ -182,13 +189,13 @@ function test_bad_args() { // This tests that the callback gets called, and the cacheListener gets the proper content. function test_callback_gets_called() { packagePath = "/package"; - paservice.requestURI(createURI(uri + packagePath + "!//index.html"), LoadContextInfo.default, cacheListener); + paservice.getResource(getPrincipal(uri + packagePath + "!//index.html"), 0, LoadContextInfo.default, cacheListener); } // Tests that requesting the same resource returns the same content function test_same_content() { packagePath = "/package"; - paservice.requestURI(createURI(uri + packagePath + "!//index.html"), LoadContextInfo.default, cacheListener); + paservice.getResource(getPrincipal(uri + packagePath + "!//index.html"), 0, LoadContextInfo.default, cacheListener); } // Check the content handler has been called the expected number of times. @@ -200,7 +207,7 @@ function test_request_number() { // This tests that new content is returned if the package has been updated function test_updated_package() { packagePath = "/package"; - paservice.requestURI(createURI(uri + packagePath + "!//index.html"), LoadContextInfo.default, + paservice.getResource(getPrincipal(uri + packagePath + "!//index.html"), 0, LoadContextInfo.default, new packagedResourceListener(testData.content[0].data.replace(/\.\.\./g, 'xxx'))); } @@ -224,13 +231,13 @@ var listener404 = { // Tests that an error is returned for a non existing package function test_package_does_not_exist() { packagePath = "/package_non_existent"; - paservice.requestURI(createURI(uri + packagePath + "!//index.html"), LoadContextInfo.default, listener404); + paservice.getResource(getPrincipal(uri + packagePath + "!//index.html"), 0, LoadContextInfo.default, 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 - paservice.requestURI(createURI(uri + packagePath + "!//file_non_existent.html"), LoadContextInfo.default, listener404); + paservice.getResource(getPrincipal(uri + packagePath + "!//file_non_existent.html"), 0, LoadContextInfo.default, listener404); } // ---------------------------------------------------------------------------- @@ -271,13 +278,13 @@ function packagedAppBadContentHandler(metadata, response) // Checks that the resource with the proper headers inside the bad package is still returned function test_bad_package() { packagePath = "/badPackage"; - paservice.requestURI(createURI(uri + packagePath + "!//index.html"), LoadContextInfo.default, cacheListener); + paservice.getResource(getPrincipal(uri + packagePath + "!//index.html"), 0, LoadContextInfo.default, cacheListener); } // Checks that the request for a non-existent resource doesn't hang for a bad package function test_bad_package_404() { packagePath = "/badPackage"; - paservice.requestURI(createURI(uri + packagePath + "!//file_non_existent.html"), LoadContextInfo.default, listener404); + paservice.getResource(getPrincipal(uri + packagePath + "!//file_non_existent.html"), 0, LoadContextInfo.default, listener404); } // ----------------------------------------------------------------------------