Bug 1172701 - Make GetSubresourceURI normalize the path for packaged resources r=mcmanus
authorValentin Gosu <valentin.gosu@gmail.com>
Wed, 12 Aug 2015 00:43:48 +0200
changeset 289987 846e76b0e711b7b7640f41ddcf45904fe737d24a
parent 289986 751d8abf0b7666484bbfd3397ae1e54e758d3fc9
child 289988 762524f4d9ff68d8a5e19f2a1281b584c0ba7f62
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus
bugs1172701
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1172701 - Make GetSubresourceURI normalize the path for packaged resources r=mcmanus
netwerk/protocol/http/PackagedAppService.cpp
netwerk/test/unit/test_packaged_app_service_paths.js
netwerk/test/unit/xpcshell.ini
--- a/netwerk/protocol/http/PackagedAppService.cpp
+++ b/netwerk/protocol/http/PackagedAppService.cpp
@@ -407,18 +407,25 @@ PackagedAppService::PackagedAppDownloade
   nsAutoCString path;
   rv = uri->GetPath(path);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   path += PACKAGED_APP_TOKEN;
 
-  // TODO: make sure the path is normalized
-  if (StringBeginsWith(contentLocation, NS_LITERAL_CSTRING("/"))) {
+  {
+    // We use this temp URI to generate a path that is relative
+    // to the package URI and not to the root of the domain.
+    nsCOMPtr<nsIURI> tempURI;
+    NS_NewURI(getter_AddRefs(tempURI), "http://temp-domain.local/");
+    tempURI->SetPath(contentLocation);
+    // The path is now normalized.
+    tempURI->GetPath(contentLocation);
+    // Remove the leading slash.
     contentLocation = Substring(contentLocation, 1);
   }
 
   path += contentLocation;
 
   nsCOMPtr<nsIURI> partURI;
   rv = uri->CloneIgnoringRef(getter_AddRefs(partURI));
   if (NS_FAILED(rv)) {
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_packaged_app_service_paths.js
@@ -0,0 +1,127 @@
+Cu.import('resource://gre/modules/LoadContextInfo.jsm');
+Cu.import("resource://testing-common/httpd.js");
+Cu.import("resource://gre/modules/Services.jsm");
+
+var gRequestNo = 0;
+function packagedAppContentHandler(metadata, response)
+{
+  response.setHeader("Content-Type", 'application/package');
+  var body = testData.getData();
+  response.bodyOutputStream.write(body, body.length);
+  gRequestNo++;
+}
+
+function getPrincipal(url) {
+  let uri = createURI(url);
+  return Components.classes["@mozilla.org/scriptsecuritymanager;1"]
+         .getService(Ci.nsIScriptSecurityManager)
+         .getNoAppCodebasePrincipal(uri);
+}
+
+var subresourcePaths = [
+  [ "/index.html", "index.html" ],
+  [ "index.html",  "index.html" ],
+  [ "/../../index.html", "index.html" ],
+  [ "../../index.html", "index.html" ],
+  [ "/hello/./.././index.html", "index.html" ],
+  [ "hello/./.././index.html", "index.html" ],
+  [ "../hello/index.html", "hello/index.html" ],
+  [ "/../hello/index.html", "hello/index.html" ],
+  [ "/./././index.html", "index.html" ],
+]
+
+var content = "<html><body> Test </body></html>";
+
+// The package content
+// getData formats it as described at http://www.w3.org/TR/web-packaging/#streamable-package-format
+var testData = {
+  token : "gc0pJq0M:08jU534c0p",
+  getData: function() {
+    var str = "";
+
+    str += "--" + this.token + "\r\n";
+    str += "Content-Location: " + subresourcePaths[gRequestNo][0] + "\r\n";
+    str += "Content-Type: text/html" + "\r\n";
+    str += "\r\n";
+
+    str += content + "\r\n";
+    str += "--" + this.token + "--";
+
+    return str;
+  }
+}
+
+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 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.registerPrefixHandler("/package/", packagedAppContentHandler);
+  httpserver.start(-1);
+
+  paservice = Cc["@mozilla.org/network/packaged-app-service;1"]
+                     .getService(Ci.nsIPackagedAppService);
+
+  var testuri = createURI("http://localhost/");
+
+  add_test(continueTest);
+  // run tests
+  run_next_test();
+}
+
+// A listener we use to check the proper cache entry is returned by the service
+function packagedResourceListener(path, content) {
+  this.path = path;
+  this.content = content;
+}
+
+packagedResourceListener.prototype = {
+  QueryInterface: function (iid) {
+    if (iid.equals(Ci.nsICacheEntryOpenCallback) ||
+        iid.equals(Ci.nsISupports))
+      return this;
+    throw Cr.NS_ERROR_NO_INTERFACE;
+  },
+  onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
+  onCacheEntryAvailable: function (entry, isnew, appcache, status) {
+    equal(status, Cr.NS_OK, "status is NS_OK");
+    ok(!!entry, "Needs to have an entry");
+    equal(entry.key, uri + packagePath + "!//" + this.path, "Check entry has correct name");
+    var inputStream = entry.openInputStream(0);
+    pumpReadStream(inputStream, (read) => {
+        inputStream.close();
+        equal(read, this.content); // not using do_check_eq since logger will fail for the 1/4MB string
+        continueTest();
+    });
+  }
+};
+
+var gGenerator = test_paths();
+function continueTest() {
+  try {
+    gGenerator.next();
+  } catch (e if e instanceof StopIteration) {
+    run_next_test();
+  }
+}
+function test_paths() {
+  for (var i in subresourcePaths) {
+    packagePath = "/package/" + i;
+    dump("Iteration " + i + "\n");
+    paservice.getResource(getPrincipal(uri + packagePath + "!//" + subresourcePaths[i][1]), 0,
+      LoadContextInfo.default,
+      new packagedResourceListener(subresourcePaths[i][1], content));
+    yield undefined;
+  }
+}
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -321,8 +321,9 @@ skip-if = os == "android"
 [test_1073747.js]
 [test_multipart_streamconv_application_package.js]
 [test_safeoutputstream_append.js]
 [test_packaged_app_service.js]
 [test_suspend_channel_before_connect.js]
 [test_inhibit_caching.js]
 [test_dns_disable_ipv4.js]
 [test_dns_disable_ipv6.js]
+[test_packaged_app_service_paths.js]