diff --git a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp index 9dabcc36be68..93de4453245b 100644 --- a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp +++ b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp @@ -425,7 +425,27 @@ SubstitutingProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result) rv = baseURI->GetSpec(result); } else { // Make sure we always resolve the path as file-relative to our target URI. - path.Insert('.', 0); + // When the baseURI is a nsIFileURL, and the directory it points to doesn't + // exist, it doesn't end with a /. In that case, a file-relative resolution + // is going to pick something in the parent directory, so we resolve using + // an absolute path derived from the full path in that case. + nsCOMPtr baseDir = do_QueryInterface(baseURI); + if (baseDir) { + nsAutoCString basePath; + rv = baseURI->GetFilePath(basePath); + if (NS_SUCCEEDED(rv) && !StringEndsWith(basePath, NS_LITERAL_CSTRING("/"))) { + // Cf. the assertion above, path already starts with a /, so prefixing + // with a string that doesn't end with one will leave us wit the right + // amount of /. + path.Insert(basePath, 0); + } else { + // Allow to fall through below. + baseDir = nullptr; + } + } + if (!baseDir) { + path.Insert('.', 0); + } rv = baseURI->Resolve(path, result); } diff --git a/netwerk/test/unit/test_bug337744.js b/netwerk/test/unit/test_bug337744.js index b100f68438b8..bb71a9f87da3 100644 --- a/netwerk/test/unit/test_bug337744.js +++ b/netwerk/test/unit/test_bug337744.js @@ -94,9 +94,14 @@ function run_test() { let rootFile = Services.dirsvc.get("GreD", Ci.nsIFile); let rootURI = Services.io.newFileURI(rootFile); + rootFile.appendRelativePath("this/directory/does/not/exist"); + let inexistentURI = Services.io.newFileURI(rootFile); + resProto.setSubstitution("res-test", rootURI); + resProto.setSubstitution("res-inexistent", inexistentURI); do_register_cleanup(() => { resProto.setSubstitution("res-test", null); + resProto.setSubstitution("res-inexistent", null); }); let baseRoot = resProto.resolveURI(Services.io.newURI("resource:///")); @@ -104,6 +109,7 @@ function run_test() { for (var spec of specs) { check_safe_resolution(spec, rootURI.spec); + check_safe_resolution(spec.replace("res-test", "res-inexistent"), inexistentURI.spec); check_safe_resolution(spec.replace("res-test", ""), baseRoot); check_safe_resolution(spec.replace("res-test", "gre"), greRoot); }