Bug 1187159 - Pass principal and flags from the requesting channel to the packaged app channel r=honzab
authorValentin Gosu <valentin.gosu@gmail.com>
Sat, 08 Aug 2015 07:11:56 +0200
changeset 256978 ca1510a96cc66300e01798b376da2884d1ddca6f
parent 256960 d263ff7885e9270e42320ecf5b64d801edb30134
child 256979 78a61d56adaeb9a8beb4583026463f1dc6945197
push id14559
push userphilringnalda@gmail.com
push dateSun, 09 Aug 2015 23:41:14 +0000
treeherderfx-team@0e269a1f1beb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershonzab
bugs1187159
milestone42.0a1
Bug 1187159 - Pass principal and flags from the requesting channel to the packaged app channel r=honzab
netwerk/base/nsIPackagedAppService.idl
netwerk/protocol/http/PackagedAppService.cpp
netwerk/protocol/http/PackagedAppService.h
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/test/unit/test_packaged_app_service.js
--- a/netwerk/base/nsIPackagedAppService.idl
+++ b/netwerk/base/nsIPackagedAppService.idl
@@ -1,42 +1,50 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-interface nsIURI;
+interface nsIPrincipal;
 interface nsILoadContextInfo;
 interface nsICacheEntryOpenCallback;
 
 %{C++
   #define PACKAGED_APP_TOKEN "!//"
 %}
 
 /**
  * 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);
 };
--- a/netwerk/protocol/http/PackagedAppService.cpp
+++ b/netwerk/protocol/http/PackagedAppService.cpp
@@ -600,33 +600,40 @@ PackagedAppService::GetPackageURI(nsIURI
   }
 
   packageURI.forget(aPackageURI);
 
   return NS_OK;
 }
 
 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;
 
-  nsresult rv;
-  LogURI("PackagedAppService::RequestURI", this, aURI, aInfo);
+  nsCOMPtr<nsIURI> 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<nsIURI> packageURI;
-  rv = GetPackageURI(aURI, getter_AddRefs(packageURI));
+  rv = GetPackageURI(uri, getter_AddRefs(packageURI));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   nsAutoCString key;
   CacheFileUtils::AppendKeyPrefix(aInfo, key);
 
   {
@@ -638,32 +645,25 @@ PackagedAppService::RequestURI(nsIURI *a
 
   nsRefPtr<PackagedAppDownloader> downloader;
   if (mDownloadingPackages.Get(key, getter_AddRefs(downloader))) {
     // We have determined that the file is not in the cache.
     // If we find that the package that the file belongs to is currently being
     // 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<nsIChannel> 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;
   }
 
   nsCOMPtr<nsICachingChannel> cacheChan(do_QueryInterface(channel));
   if (cacheChan) {
     // Each resource in the package will be put in its own cache entry
@@ -673,17 +673,17 @@ PackagedAppService::RequestURI(nsIURI *a
   }
 
   downloader = new PackagedAppDownloader();
   rv = downloader->Init(aInfo, key);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  downloader->AddCallback(aURI, aCallback);
+  downloader->AddCallback(uri, aCallback);
 
   nsCOMPtr<nsIStreamConverterService> streamconv =
     do_GetService("@mozilla.org/streamConverters;1", &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsCOMPtr<nsIStreamListener> mimeConverter;
--- a/netwerk/protocol/http/PackagedAppService.h
+++ b/netwerk/protocol/http/PackagedAppService.h
@@ -18,20 +18,17 @@ class nsHttpResponseHead;
 
 // This service is used to download packages from the web.
 // Individual resources in the package are saved in the browser cache. It also
 // provides an interface to asynchronously request resources from packages,
 // which are either returned from the cache if they exist and are valid,
 // 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
 {
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIPACKAGEDAPPSERVICE
 
   PackagedAppService();
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -5192,27 +5192,32 @@ nsHttpChannel::BeginConnect()
     // clear the already recorded AsyncOpen value for consistency.
     if (!mTimingEnabled)
         mAsyncOpenTime = TimeStamp();
 
     if (mIsPackagedAppResource) {
         // 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;
         nsCOMPtr<nsIPackagedAppService> pas =
             do_GetService("@mozilla.org/network/packaged-app-service;1", &rv);
         if (NS_WARN_IF(NS_FAILED(rv))) {
             AsyncAbort(rv);
             return rv;
         }
 
-        rv = pas->RequestURI(mURI, GetLoadContextInfo(this), this);
+        nsCOMPtr<nsIPrincipal> principal = GetURIPrincipal();
+        rv = pas->GetResource(principal, loadFlags, GetLoadContextInfo(this), this);
         if (NS_FAILED(rv)) {
             AsyncAbort(rv);
         }
         return rv;
     }
 
     // when proxying only use the pipeline bit if ProxyPipelining() allows it.
     if (!mConnectionInfo->UsingConnect() && mConnectionInfo->UsingHttpProxy()) {
--- a/netwerk/test/unit/test_packaged_app_service.js
+++ b/netwerk/test/unit/test_packaged_app_service.js
@@ -2,24 +2,24 @@
 // This file tests the packaged app service - nsIPackagedAppService
 // NOTE: The order in which tests are run is important
 //       If you need to add more tests, it's best to define them at the end
 //       of the file and to add them at the end of run_test
 //
 // ----------------------------------------------------------------------------
 //
 // 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
 //     - checks that requesting a file from a <package that does not exist>
 //       calls the listener with an error code
 // test_file_does_not_exist
 //     - checks that requesting a <subresource that doesn't exist> inside a
 //       package calls the listener with an error code
@@ -54,16 +54,23 @@ function packagedAppContentHandler(metad
 
   if (packagedAppRequestsMade == 3) {
     // The third request returns a 200 OK response with a slightly different content
     body = body.replace(/\.\.\./g, 'xxx');
   }
   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 = {
   content: [
    { headers: ["Content-Location: /index.html", "Content-Type: text/html"], data: "<html>\r\n  <head>\r\n    <script src=\"/scripts/app.js\"></script>\r\n    ...\r\n  </head>\r\n  ...\r\n</html>\r\n", type: "text/html" },
    { headers: ["Content-Location: /scripts/app.js", "Content-Type: text/javascript"], data: "module Math from '/scripts/helpers/math.js';\r\n...\r\n", type: "text/javascript" },
    { headers: ["Content-Location: /scripts/helpers/math.js", "Content-Type: text/javascript"], data: "export function sum(nums) { ... }\r\n...\r\n", type: "text/javascript" }
   ],
@@ -87,17 +94,17 @@ var testData = {
 XPCOMUtils.defineLazyGetter(this, "uri", function() {
   return "http://localhost:" + httpserver.identity.primaryPort;
 });
 
 // The active http server initialized in run_test
 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;
 
 function run_test()
 {
   // setup test
   httpserver = new HttpServer();
   httpserver.registerPathHandler("/package", packagedAppContentHandler);
@@ -165,47 +172,47 @@ packagedResourceListener.prototype = {
   }
 };
 
 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();
 }
 
 // ----------------------------------------------------------------------------
 
 // 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.
 function test_request_number() {
   equal(packagedAppRequestsMade, 2, "2 requests are expected. First with content, second is a 304 not modified.");
   run_next_test();
 }
 
 // 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')));
 }
 
 // ----------------------------------------------------------------------------
 
 // This listener checks that the requested resources are not returned
 // either because the package does not exist, or because the requested resource
 // is not contained in the package.
@@ -219,23 +226,23 @@ var listener404 = {
     ok(!entry, "There should be no entry");
     run_next_test();
   }
 };
 
 // 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);
 }
 
 // ----------------------------------------------------------------------------
 
 // Broken package. The first and last resources do not contain a "Content-Location" header
 // and should be ignored.
 var badTestData = {
   content: [
@@ -266,18 +273,18 @@ function packagedAppBadContentHandler(me
   response.setHeader("Content-Type", 'application/package');
   var body = badTestData.getData();
   response.bodyOutputStream.write(body, body.length);
 }
 
 // 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);
 }
 
 // ----------------------------------------------------------------------------