--- a/chrome/src/nsChromeProtocolHandler.cpp
+++ b/chrome/src/nsChromeProtocolHandler.cpp
@@ -413,17 +413,17 @@ nsChromeProtocolHandler::AllowPort(PRInt
// don't override anything.
*_retval = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsChromeProtocolHandler::GetProtocolFlags(PRUint32 *result)
{
- *result = URI_STD | URI_IS_UI_RESOURCE;
+ *result = URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE;
return NS_OK;
}
NS_IMETHODIMP
nsChromeProtocolHandler::NewURI(const nsACString &aSpec,
const char *aCharset,
nsIURI *aBaseURI,
nsIURI **result)
@@ -460,17 +460,17 @@ nsChromeProtocolHandler::NewURI(const ns
NS_IMETHODIMP
nsChromeProtocolHandler::NewChannel(nsIURI* aURI,
nsIChannel* *aResult)
{
nsresult rv;
NS_ENSURE_ARG_POINTER(aURI);
NS_PRECONDITION(aResult, "Null out param");
-
+
#ifdef DEBUG
// Check that the uri we got is already canonified
nsresult debug_rv;
nsCOMPtr<nsIURI> debugClone;
debug_rv = aURI->Clone(getter_AddRefs(debugClone));
if (NS_SUCCEEDED(debug_rv)) {
nsCOMPtr<nsIURL> debugURL (do_QueryInterface(debugClone));
debug_rv = nsChromeRegistry::Canonify(debugURL);
@@ -549,48 +549,16 @@ nsChromeProtocolHandler::NewChannel(nsIU
}
nsCOMPtr<nsIIOService> ioServ (do_GetIOService(&rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = ioServ->NewChannelFromURI(resolvedURI, getter_AddRefs(result));
if (NS_FAILED(rv)) return rv;
- // XXX Will be removed someday when we handle remote chrome.
- nsCOMPtr<nsIFileChannel> fileChan
- (do_QueryInterface(result));
- if (fileChan) {
-#ifdef DEBUG
- nsCOMPtr<nsIFile> file;
- fileChan->GetFile(getter_AddRefs(file));
-
- PRBool exists = PR_FALSE;
- file->Exists(&exists);
- if (!exists) {
- nsCAutoString path;
- file->GetNativePath(path);
- printf("Chrome file doesn't exist: %s\n", path.get());
- }
-#endif
- }
- else {
- nsCOMPtr<nsIJARChannel> jarChan
- (do_QueryInterface(result));
- if (!jarChan) {
- nsRefPtr<nsCachedChromeChannel> cachedChannel;
- if (NS_FAILED(CallQueryInterface(result.get(),
- static_cast<nsCachedChromeChannel**>(
- getter_AddRefs(cachedChannel))))) {
- NS_WARNING("Remote chrome not allowed! Only file:, resource:, jar:, and cached chrome channels are valid.\n");
- result = nsnull;
- return NS_ERROR_FAILURE;
- }
- }
- }
-
// Make sure that the channel remembers where it was
// originally loaded from.
rv = result->SetOriginalURI(aURI);
if (NS_FAILED(rv)) return rv;
// Get a system principal for content files and set the owner
// property of the result
nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
@@ -622,34 +590,25 @@ nsChromeProtocolHandler::NewChannel(nsIU
// nsResURL class?
nsCOMPtr<nsIFastLoadService> fastLoadServ(do_GetFastLoadService());
if (fastLoadServ) {
nsCOMPtr<nsIObjectOutputStream> objectOutput;
fastLoadServ->GetOutputStream(getter_AddRefs(objectOutput));
if (objectOutput) {
nsCOMPtr<nsIFile> file;
- if (fileChan) {
- fileChan->GetFile(getter_AddRefs(file));
- } else {
- nsCOMPtr<nsIURI> uri;
- result->GetURI(getter_AddRefs(uri));
+ nsCOMPtr<nsIURI> uri;
+ result->GetURI(getter_AddRefs(uri));
+ uri = NS_GetInnermostURI(uri);
- // Loop, jar URIs can nest (e.g. jar:jar:A.jar!B.jar!C.xml).
- // Often, however, we have jar:resource:/chrome/A.jar!C.xml.
- nsCOMPtr<nsIJARURI> jarURI;
- while ((jarURI = do_QueryInterface(uri)) != nsnull)
- jarURI->GetJARFile(getter_AddRefs(uri));
-
- // Here we have a URL of the form resource:/chrome/A.jar
- // or file:/some/path/to/A.jar.
- nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(uri));
- if (fileURL)
- fileURL->GetFile(getter_AddRefs(file));
- }
+ // Here we have a URL of the form resource:/chrome/A.jar
+ // or file:/some/path/to/A.jar.
+ nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(uri));
+ if (fileURL)
+ fileURL->GetFile(getter_AddRefs(file));
if (file) {
rv = fastLoadServ->AddDependency(file);
if (NS_FAILED(rv))
cache->AbortFastLoads();
}
}
}
--- a/chrome/src/nsChromeRegistry.cpp
+++ b/chrome/src/nsChromeRegistry.cpp
@@ -247,16 +247,26 @@ LanguagesMatch(const nsACString& a, cons
// "b" is short
if (bs == be)
return (*as == '-');
}
return PR_FALSE;
}
+static PRBool
+CanLoadResource(nsIURI* aResourceURI)
+{
+ PRBool isLocalResource = PR_FALSE;
+ (void)NS_URIChainHasFlags(aResourceURI,
+ nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
+ &isLocalResource);
+ return isLocalResource;
+}
+
nsChromeRegistry::ProviderEntry*
nsChromeRegistry::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
{
PRInt32 i = mArray.Count();
if (!i)
return nsnull;
ProviderEntry* found = nsnull; // Only set if we find a partial-match locale
@@ -2329,16 +2339,23 @@ nsChromeRegistry::ProcessManifestBuffer(
continue;
nsCOMPtr<nsIURI> resolved;
rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
getter_AddRefs(resolved));
if (NS_FAILED(rv))
continue;
+ if (!CanLoadResource(resolved)) {
+ LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
+ "Warning: cannot register non-local URI '%s' as content.",
+ uri);
+ continue;
+ }
+
PackageEntry* entry =
static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
& (const nsACString&) nsDependentCString(package),
PL_DHASH_ADD));
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
entry->baseURI = resolved;
@@ -2404,16 +2421,23 @@ nsChromeRegistry::ProcessManifestBuffer(
continue;
nsCOMPtr<nsIURI> resolved;
rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
getter_AddRefs(resolved));
if (NS_FAILED(rv))
continue;
+ if (!CanLoadResource(resolved)) {
+ LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
+ "Warning: cannot register non-local URI '%s' as a locale.",
+ uri);
+ continue;
+ }
+
PackageEntry* entry =
static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
& (const nsACString&) nsDependentCString(package),
PL_DHASH_ADD));
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
entry->locales.SetBase(nsDependentCString(provider), resolved);
@@ -2459,16 +2483,23 @@ nsChromeRegistry::ProcessManifestBuffer(
continue;
nsCOMPtr<nsIURI> resolved;
rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
getter_AddRefs(resolved));
if (NS_FAILED(rv))
continue;
+ if (!CanLoadResource(resolved)) {
+ LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
+ "Warning: cannot register non-local URI '%s' as a skin.",
+ uri);
+ continue;
+ }
+
PackageEntry* entry =
static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
& (const nsACString&) nsDependentCString(package),
PL_DHASH_ADD));
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
entry->skins.SetBase(nsDependentCString(provider), resolved);
@@ -2520,16 +2551,23 @@ nsChromeRegistry::ProcessManifestBuffer(
getter_AddRefs(baseuri));
rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
getter_AddRefs(overlayuri));
if (NS_FAILED(rv)) {
NS_WARNING("Could not make URIs for overlay directive. Ignoring.");
continue;
}
+ if (!CanLoadResource(overlayuri)) {
+ LogMessageWithContext(overlayuri, line, nsIScriptError::warningFlag,
+ "Warning: cannot register non-local URI '%s' as an overlay.",
+ overlay);
+ continue;
+ }
+
mOverlayHash.Add(baseuri, overlayuri);
}
else if (!strcmp(token, "style")) {
char *base = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
if (!base || !overlay) {
LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
"Warning: malformed chrome style instruction.");
@@ -2567,16 +2605,23 @@ nsChromeRegistry::ProcessManifestBuffer(
nsCOMPtr<nsIURI> baseuri, overlayuri;
rv = io->NewURI(nsDependentCString(base), nsnull, nsnull,
getter_AddRefs(baseuri));
rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
getter_AddRefs(overlayuri));
if (NS_FAILED(rv))
continue;
+ if (!CanLoadResource(overlayuri)) {
+ LogMessageWithContext(overlayuri, line, nsIScriptError::warningFlag,
+ "Warning: cannot register non-local URI '%s' as a style overlay.",
+ overlay);
+ continue;
+ }
+
mStyleHash.Add(baseuri, overlayuri);
}
else if (!strcmp(token, "override")) {
if (aSkinOnly) {
LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
"Warning: Ignoring override registration in skin-only manifest.");
continue;
}
@@ -2620,16 +2665,23 @@ nsChromeRegistry::ProcessManifestBuffer(
nsCOMPtr<nsIURI> chromeuri, resolveduri;
rv = io->NewURI(nsDependentCString(chrome), nsnull, nsnull,
getter_AddRefs(chromeuri));
rv |= io->NewURI(nsDependentCString(resolved), nsnull, manifestURI,
getter_AddRefs(resolveduri));
if (NS_FAILED(rv))
continue;
+ if (!CanLoadResource(resolveduri)) {
+ LogMessageWithContext(resolveduri, line, nsIScriptError::warningFlag,
+ "Warning: cannot register non-local URI '%s' as an override.",
+ resolved);
+ continue;
+ }
+
mOverrideTable.Put(chromeuri, resolveduri);
}
else if (!strcmp(token, "resource")) {
if (aSkinOnly) {
LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
"Warning: Ignoring resource registration in skin-only manifest.");
continue;
}
@@ -2685,16 +2737,23 @@ nsChromeRegistry::ProcessManifestBuffer(
}
nsCOMPtr<nsIURI> resolved;
rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
getter_AddRefs(resolved));
if (NS_FAILED(rv))
continue;
+ if (!CanLoadResource(resolved)) {
+ LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
+ "Warning: cannot register non-local URI '%s' as a resource.",
+ uri);
+ continue;
+ }
+
rv = rph->SetSubstitution(host, resolved);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
"Warning: Ignoring unrecognized chrome manifest instruction.");
}
}
--- a/chrome/test/unit/data/test_bug401153.manifest
+++ b/chrome/test/unit/data/test_bug401153.manifest
@@ -1,17 +1,14 @@
# Should work
resource test1 test1/
# Duplicates should be ignored
resource test1 foo/
-# Mapping off file system should work
-resource test2 http://www.mozilla.org/
-
# Mapping into jar files should work
resource test3 jar:test3.jar!/resources/
# Invalid line
resource test4
# Check we made it through the whole manifest
resource test5 test5/
new file mode 100644
--- /dev/null
+++ b/chrome/test/unit/data/test_data_protocol_registration.manifest
@@ -0,0 +1,5 @@
+# package used only for valid override
+content good-package bar/
+
+# Local resource (should work)
+override chrome://good-package/content/test.xul data:application/vnd.mozilla.xul+xml,
new file mode 100644
--- /dev/null
+++ b/chrome/test/unit/data/test_no_remote_registration.manifest
@@ -0,0 +1,30 @@
+# package used only for valid overlaying and overrides
+content good-package bar/
+
+# UI Resource URIs (should work)
+content moz-protocol-ui-resource moz-protocol-ui-resource://foo/
+locale moz-protocol-ui-resource en-us moz-protocol-ui-resource://foo/
+skin moz-protocol-ui-resource skin1 moz-protocol-ui-resource://foo/
+override chrome://good-package/content/override-moz-protocol-ui-resource.xul moz-protocol-ui-resource://foo/
+resource moz-protocol-ui-resource moz-protocol-ui-resource://foo/
+
+# Local file URIs (should work)
+content moz-protocol-local-file moz-protocol-local-file://foo/
+locale moz-protocol-local-file en-us moz-protocol-local-file://foo/
+skin moz-protocol-local-file skin1 moz-protocol-local-file://foo/
+override chrome://good-package/content/override-moz-protocol-local-file.xul moz-protocol-local-file://foo/
+resource moz-protocol-local-file moz-protocol-local-file://foo/
+
+# Loadable by anyone URIs (should not work)
+content moz-protocol-loadable-by-anyone moz-protocol-loadable-by-anyone://foo/
+locale moz-protocol-loadable-by-anyone en-us moz-protocol-loadable-by-anyone://foo/
+skin moz-protocol-loadable-by-anyone skin1 moz-protocol-loadable-by-anyone://foo/
+override chrome://good-package/content/override-moz-protocol-loadable-by-anyone.xul moz-protocol-loadable-by-anyone://foo/
+resource moz-protocol-loadable-by-anyone moz-protocol-loadable-by-anyone://foo/
+
+# Local resource (should work)
+content moz-protocol-local-resource moz-protocol-local-resource://foo/
+locale moz-protocol-local-resource en-us moz-protocol-local-resource://foo/
+skin moz-protocol-local-resource skin1 moz-protocol-local-resource://foo/
+override chrome://good-package/content/override-moz-protocol-local-resource.xul moz-protocol-local-resource://foo/
+resource moz-protocol-local-resource moz-protocol-local-resource://foo/
--- a/chrome/test/unit/test_bug401153.js
+++ b/chrome/test/unit/test_bug401153.js
@@ -84,32 +84,31 @@ chromeReg.checkForNewChrome();
var rph = gIOS.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
function test_succeeded_mapping(namespace, target)
{
try {
do_check_true(rph.hasSubstitution(namespace));
- var thistarget = target + "/test.js";
- var uri = gIOS.newURI("resource://" + namespace + "/test.js",
- null, null);
- do_check_eq(rph.resolveURI(uri), thistarget);
+ var uri = gIOS.newURI("resource://" + namespace, null, null);
+ dump("### checking for " + target + ", getting " + rph.resolveURI(uri) + "\n");
+ do_check_eq(rph.resolveURI(uri), target);
}
catch (ex) {
+ dump(ex + "\n");
do_throw(namespace);
}
}
function test_failed_mapping(namespace)
{
do_check_false(rph.hasSubstitution(namespace));
}
function run_test()
{
var data = gIOS.newFileURI(do_get_file("chrome/test/unit/data")).spec;
- test_succeeded_mapping("test1", data + "test1");
- test_succeeded_mapping("test2", "http://www.mozilla.org");
- test_succeeded_mapping("test3", "jar:" + data + "test3.jar!/resources");
+ test_succeeded_mapping("test1", data + "test1/");
+ test_succeeded_mapping("test3", "jar:" + data + "test3.jar!/resources/");
test_failed_mapping("test4");
- test_succeeded_mapping("test5", data + "test5");
+ test_succeeded_mapping("test5", data + "test5/");
}
new file mode 100644
--- /dev/null
+++ b/chrome/test/unit/test_data_protocol_registration.js
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=2 sts=2 tw=78 expandtab :
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Chrome Registration Test Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Shawn Wilsher <me@shawnwilsher.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+let manifests = [
+ do_get_file("chrome/test/unit/data/test_data_protocol_registration.manifest"),
+];
+registerManifests(manifests);
+
+let XULAppInfoFactory = {
+ // These two are used when we register all our factories (and unregister)
+ CID: XULAPPINFO_CID,
+ scheme: "XULAppInfo",
+ contractID: XULAPPINFO_CONTRACTID,
+ createInstance: function (outer, iid) {
+ if (outer != null)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ return XULAppInfo.QueryInterface(iid);
+ }
+};
+
+function run_test()
+{
+ // Add our XULAppInfo factory
+ let factories = [XULAppInfoFactory];
+
+ // Register our factories
+ for (let i = 0; i < factories.length; i++) {
+ let factory = factories[i];
+ Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
+ .registerFactory(factory.CID, "test-" + factory.scheme,
+ factory.contractID, factory);
+ }
+
+ // Check for new chrome
+ let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(Ci.nsIChromeRegistry);
+ cr.checkForNewChrome();
+
+ // Check that our override worked
+ let expectedURI = "data:application/vnd.mozilla.xul+xml,";
+ let sourceURI = "chrome://good-package/content/test.xul";
+ try {
+ let ios = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+ sourceURI = ios.newURI(sourceURI, null, null);
+ // this throws for packages that are not registered
+ let uri = cr.convertChromeURL(sourceURI).spec;
+
+ do_check_eq(expectedURI, uri);
+ }
+ catch (e) {
+ dump(e + "\n");
+ do_throw("Should have registered our URI!");
+ }
+
+ // Unregister our factories so we do not leak
+ for (let i = 0; i < factories.length; i++) {
+ let factory = factories[i];
+ Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
+ .unregisterFactory(factory.CID, factory);
+ }
+}
new file mode 100644
--- /dev/null
+++ b/chrome/test/unit/test_no_remote_registration.js
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=2 sts=2 tw=78 expandtab :
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Chrome Registration Test Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Shawn Wilsher <me@shawnwilsher.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+let manifests = [
+ do_get_file("chrome/test/unit/data/test_no_remote_registration.manifest"),
+];
+registerManifests(manifests);
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+let XULAppInfo = {
+ vendor: "Mozilla",
+ name: "XPCShell",
+ ID: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
+ version: "5",
+ appBuildID: "2007010101",
+ platformVersion: "1.9",
+ platformBuildID: "2007010101",
+ inSafeMode: false,
+ logConsoleErrors: true,
+ OS: "XPCShell",
+ XPCOMABI: "noarch-spidermonkey",
+ QueryInterface: XPCOMUtils.generateQI([
+ Ci.nsIXULAppInfo,
+ Ci.nsIXULRuntime,
+ ])
+};
+
+let XULAppInfoFactory = {
+ // These two are used when we register all our factories (and unregister)
+ CID: XULAPPINFO_CID,
+ scheme: "XULAppInfo",
+ contractID: XULAPPINFO_CONTRACTID,
+ createInstance: function (outer, iid) {
+ if (outer != null)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ return XULAppInfo.QueryInterface(iid);
+ }
+};
+
+function ProtocolHandler(aScheme, aFlags)
+{
+ this.scheme = aScheme;
+ this.protocolFlags = aFlags;
+ this.contractID = "@mozilla.org/network/protocol;1?name=" + aScheme;
+}
+
+ProtocolHandler.prototype =
+{
+ defaultPort: -1,
+ allowPort: function() false,
+ newURI: function(aSpec, aCharset, aBaseURI)
+ {
+ let uri = Cc["@mozilla.org/network/standard-url;1"].
+ createInstance(Ci.nsIURI);
+ uri.spec = aSpec;
+ if (!uri.scheme) {
+ // We got a partial uri, so let's resolve it with the base one
+ uri.spec = aBaseURI.resolve(aSpec);
+ }
+ return uri;
+ },
+ newChannel: function() { throw Cr.NS_ERROR_NOT_IMPLEMENTED },
+ QueryInterface: XPCOMUtils.generateQI([
+ Ci.nsIProtocolHandler
+ ])
+};
+
+let testProtocols = [
+ {scheme: "moz-protocol-ui-resource",
+ flags: Ci.nsIProtocolHandler.URI_IS_UI_RESOURCE,
+ CID: Components.ID("{d6dedc93-558f-44fe-90f4-3b4bba8a0b14}"),
+ shouldRegister: true
+ },
+ {scheme: "moz-protocol-local-file",
+ flags: Ci.nsIProtocolHandler.URI_IS_LOCAL_FILE,
+ CID: Components.ID("{ee30d594-0a2d-4f47-89cc-d4cde320ab69}"),
+ shouldRegister: true
+ },
+ {scheme: "moz-protocol-loadable-by-anyone",
+ flags: Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE,
+ CID: Components.ID("{c3735f23-3b0c-4a33-bfa0-79436dcd40b2}"),
+ shouldRegister: false
+ },
+ {scheme: "moz-protocol-local-resource",
+ flags: Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE,
+ CID: Components.ID("{b79e977c-f840-469a-b413-0125cc1b62a5}"),
+ shouldRegister: true
+ },
+];
+function run_test()
+{
+ // Create factories
+ let factories = [];
+ for (let i = 0; i < testProtocols.length; i++) {
+ factories[i] = {
+ scheme: testProtocols[i].scheme,
+ flags: testProtocols[i].flags,
+ CID: testProtocols[i].CID,
+ contractID: "@mozilla.org/network/protocol;1?name=" + testProtocols[i].scheme,
+ createInstance: function(aOuter, aIID)
+ {
+ if (aOuter != null)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ let handler = new ProtocolHandler(this.scheme, this.flags, this.CID);
+ return handler.QueryInterface(aIID);
+ }
+ };
+ }
+ // Add our XULAppInfo factory
+ factories.push(XULAppInfoFactory);
+
+ // Register our factories
+ for (let i = 0; i < factories.length; i++) {
+ let factory = factories[i];
+ Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
+ .registerFactory(factory.CID, "test-" + factory.scheme,
+ factory.contractID, factory);
+ }
+
+ // Check for new chrome
+ let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(Ci.nsIChromeRegistry);
+ cr.checkForNewChrome();
+
+ // See if our various things were able to register
+ let registrationTypes = [
+ "content",
+ "locale",
+ "skin",
+ "override",
+ "resource",
+ ];
+ for (let i = 0; i < testProtocols.length; i++) {
+ let protocol = testProtocols[i];
+ for (let j = 0; j < registrationTypes.length; j++) {
+ let type = registrationTypes[j];
+ dump("Testing protocol '" + protocol.scheme + "' with type '" + type +
+ "'\n");
+ let expectedURI = protocol.scheme + "://foo/";
+ let sourceURI = "chrome://" + protocol.scheme + "/" + type + "/";
+ switch (type) {
+ case "content":
+ expectedURI += protocol.scheme + ".xul";
+ break;
+ case "locale":
+ expectedURI += protocol.scheme + ".dtd";
+ break;
+ case "skin":
+ expectedURI += protocol.scheme + ".css";
+ break;
+ case "override":
+ sourceURI = "chrome://good-package/content/override-" +
+ protocol.scheme + ".xul";
+ break;
+ case "resource":
+ sourceURI = "resource://" + protocol.scheme + "/";
+ break;
+ };
+ try {
+ let ios = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+ sourceURI = ios.newURI(sourceURI, null, null);
+ let uri;
+ if (type == "resource") {
+ // resources go about a slightly different way than everything else
+ let rph = ios.getProtocolHandler("resource").
+ QueryInterface(Ci.nsIResProtocolHandler);
+ // this throws for packages that are not registered
+ uri = rph.resolveURI(sourceURI);
+ }
+ else {
+ // this throws for packages that are not registered
+ uri = cr.convertChromeURL(sourceURI).spec;
+ }
+
+ if (protocol.shouldRegister) {
+ do_check_eq(expectedURI, uri);
+ }
+ else {
+ // Overrides will not throw, so we'll get to here. We want to make
+ // sure that the two strings are not the same in this situation.
+ do_check_neq(expectedURI, uri);
+ }
+ }
+ catch (e) {
+ if (protocol.shouldRegister) {
+ dump(e + "\n");
+ do_throw("Should have registered our URI for protocol " +
+ protocol.scheme);
+ }
+ }
+ }
+ }
+
+ // Unregister our factories so we do not leak
+ for (let i = 0; i < factories.length; i++) {
+ let factory = factories[i];
+ Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
+ .unregisterFactory(factory.CID, factory);
+ }
+}
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -9700,16 +9700,22 @@ nsClassifierCallback::Run()
if (hasFlags) return NS_OK;
rv = NS_URIChainHasFlags(uri,
nsIProtocolHandler::URI_IS_UI_RESOURCE,
&hasFlags);
NS_ENSURE_SUCCESS(rv, rv);
if (hasFlags) return NS_OK;
+ rv = NS_URIChainHasFlags(uri,
+ nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
+ &hasFlags);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (hasFlags) return NS_OK;
+
nsCOMPtr<nsIURIClassifier> uriClassifier =
do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
PRBool expectCallback;
rv = uriClassifier->Classify(uri, this, &expectCallback);
if (NS_FAILED(rv)) return rv;
--- a/modules/libpr0n/decoders/icon/nsIconProtocolHandler.cpp
+++ b/modules/libpr0n/decoders/icon/nsIconProtocolHandler.cpp
@@ -76,19 +76,20 @@ NS_IMETHODIMP nsIconProtocolHandler::Get
NS_IMETHODIMP nsIconProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
{
// don't override anything.
*_retval = PR_FALSE;
return NS_OK;
}
-NS_IMETHODIMP nsIconProtocolHandler::GetProtocolFlags(PRUint32 *result)
+NS_IMETHODIMP nsIconProtocolHandler::GetProtocolFlags(PRUint32 *result)
{
- *result = URI_NORELATIVE | URI_NOAUTH | URI_IS_UI_RESOURCE;
+ *result = URI_NORELATIVE | URI_NOAUTH | URI_IS_UI_RESOURCE |
+ URI_IS_LOCAL_RESOURCE;
return NS_OK;
}
NS_IMETHODIMP nsIconProtocolHandler::NewURI(const nsACString &aSpec,
const char *aOriginCharset, // ignored
nsIURI *aBaseURI,
nsIURI **result)
{
--- a/netwerk/base/public/nsIProtocolHandler.idl
+++ b/netwerk/base/public/nsIProtocolHandler.idl
@@ -216,17 +216,24 @@ interface nsIProtocolHandler : nsISuppor
const unsigned long URI_NON_PERSISTABLE = (1<<10);
/**
* Channels using this protocol never call OnDataAvailable
* on the listener passed to AsyncOpen and they therefore
* do not return any data that we can use.
*/
const unsigned long URI_DOES_NOT_RETURN_DATA = (1<<11);
-
+
+ /**
+ * URIs for this protocol are considered to be local resources. This could
+ * be a local file (URI_IS_LOCAL_FILE), a UI resource (URI_IS_UI_RESOURCE),
+ * or something else that would not hit the network.
+ */
+ const unsigned long URI_IS_LOCAL_RESOURCE = (1<<12);
+
/**
* This protocol handler can be proxied via a proxy (socks or http)
* (e.g., irc, smtp, http, etc.). If the protocol supports transparent
* proxying, the handler should implement nsIProxiedProtocolHandler.
*
* If it supports only HTTP proxying, then it need not support
* nsIProxiedProtocolHandler, but should instead set the ALLOWS_PROXY_HTTP
* flag (see below).
--- a/netwerk/protocol/data/src/nsDataHandler.cpp
+++ b/netwerk/protocol/data/src/nsDataHandler.cpp
@@ -86,17 +86,17 @@ nsDataHandler::GetDefaultPort(PRInt32 *r
// no ports for data protocol
*result = -1;
return NS_OK;
}
NS_IMETHODIMP
nsDataHandler::GetProtocolFlags(PRUint32 *result) {
*result = URI_NORELATIVE | URI_NOAUTH | URI_INHERITS_SECURITY_CONTEXT |
- URI_LOADABLE_BY_ANYONE | URI_NON_PERSISTABLE;
+ URI_LOADABLE_BY_ANYONE | URI_NON_PERSISTABLE | URI_IS_LOCAL_RESOURCE;
return NS_OK;
}
NS_IMETHODIMP
nsDataHandler::NewURI(const nsACString &aSpec,
const char *aCharset, // ignore charset info
nsIURI *aBaseURI,
nsIURI **result) {
--- a/netwerk/protocol/file/src/nsFileProtocolHandler.cpp
+++ b/netwerk/protocol/file/src/nsFileProtocolHandler.cpp
@@ -246,17 +246,17 @@ nsFileProtocolHandler::GetDefaultPort(PR
{
*result = -1; // no port for file: URLs
return NS_OK;
}
NS_IMETHODIMP
nsFileProtocolHandler::GetProtocolFlags(PRUint32 *result)
{
- *result = URI_NOAUTH | URI_IS_LOCAL_FILE;
+ *result = URI_NOAUTH | URI_IS_LOCAL_FILE | URI_IS_LOCAL_RESOURCE;
return NS_OK;
}
NS_IMETHODIMP
nsFileProtocolHandler::NewURI(const nsACString &spec,
const char *charset,
nsIURI *baseURI,
nsIURI **result)
--- a/netwerk/protocol/res/src/nsResProtocolHandler.cpp
+++ b/netwerk/protocol/res/src/nsResProtocolHandler.cpp
@@ -210,17 +210,17 @@ nsResProtocolHandler::GetDefaultPort(PRI
return NS_OK;
}
NS_IMETHODIMP
nsResProtocolHandler::GetProtocolFlags(PRUint32 *result)
{
// XXXbz Is this really true for all resource: URIs? Could we
// somehow give different flags to some of them?
- *result = URI_STD | URI_IS_UI_RESOURCE;
+ *result = URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE;
return NS_OK;
}
NS_IMETHODIMP
nsResProtocolHandler::NewURI(const nsACString &aSpec,
const char *aCharset,
nsIURI *aBaseURI,
nsIURI **result)
--- a/toolkit/components/places/src/nsAnnoProtocolHandler.cpp
+++ b/toolkit/components/places/src/nsAnnoProtocolHandler.cpp
@@ -82,17 +82,18 @@ nsAnnoProtocolHandler::GetDefaultPort(PR
}
// nsAnnoProtocolHandler::GetProtocolFlags
NS_IMETHODIMP
nsAnnoProtocolHandler::GetProtocolFlags(PRUint32 *aProtocolFlags)
{
- *aProtocolFlags = (URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD);
+ *aProtocolFlags = (URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD |
+ URI_IS_LOCAL_RESOURCE);
return NS_OK;
}
// nsAnnoProtocolHandler::NewURI
NS_IMETHODIMP
nsAnnoProtocolHandler::NewURI(const nsACString& aSpec,