michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim:set ts=4 sw=4 sts=4 et cin: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: michael@0: A protocol handler for ``chrome:'' michael@0: michael@0: */ michael@0: michael@0: #include "nsChromeProtocolHandler.h" michael@0: #include "nsChromeRegistry.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsIChannel.h" michael@0: #include "nsIChromeRegistry.h" michael@0: #include "nsIFile.h" michael@0: #include "nsIFileChannel.h" michael@0: #include "nsIIOService.h" michael@0: #include "nsILoadGroup.h" michael@0: #include "nsIScriptSecurityManager.h" michael@0: #include "nsIStandardURL.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsString.h" michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: NS_IMPL_ISUPPORTS(nsChromeProtocolHandler, michael@0: nsIProtocolHandler, michael@0: nsISupportsWeakReference) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIProtocolHandler methods: michael@0: michael@0: NS_IMETHODIMP michael@0: nsChromeProtocolHandler::GetScheme(nsACString &result) michael@0: { michael@0: result.AssignLiteral("chrome"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsChromeProtocolHandler::GetDefaultPort(int32_t *result) michael@0: { michael@0: *result = -1; // no port for chrome: URLs michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsChromeProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval) michael@0: { michael@0: // don't override anything. michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsChromeProtocolHandler::GetProtocolFlags(uint32_t *result) michael@0: { michael@0: *result = URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsChromeProtocolHandler::NewURI(const nsACString &aSpec, michael@0: const char *aCharset, michael@0: nsIURI *aBaseURI, michael@0: nsIURI **result) michael@0: { michael@0: nsresult rv; michael@0: michael@0: // Chrome: URLs (currently) have no additional structure beyond that provided michael@0: // by standard URLs, so there is no "outer" given to CreateInstance michael@0: michael@0: nsCOMPtr surl(do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = surl->Init(nsIStandardURL::URLTYPE_STANDARD, -1, aSpec, aCharset, aBaseURI); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsCOMPtr url(do_QueryInterface(surl, &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Canonify the "chrome:" URL; e.g., so that we collapse michael@0: // "chrome://navigator/content/" and "chrome://navigator/content" michael@0: // and "chrome://navigator/content/navigator.xul". michael@0: michael@0: rv = nsChromeRegistry::Canonify(url); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: surl->SetMutable(false); michael@0: michael@0: NS_ADDREF(*result = url); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsChromeProtocolHandler::NewChannel(nsIURI* aURI, michael@0: nsIChannel* *aResult) michael@0: { michael@0: nsresult rv; michael@0: michael@0: NS_ENSURE_ARG_POINTER(aURI); michael@0: NS_PRECONDITION(aResult, "Null out param"); michael@0: michael@0: #ifdef DEBUG michael@0: // Check that the uri we got is already canonified michael@0: nsresult debug_rv; michael@0: nsCOMPtr debugClone; michael@0: debug_rv = aURI->Clone(getter_AddRefs(debugClone)); michael@0: if (NS_SUCCEEDED(debug_rv)) { michael@0: nsCOMPtr debugURL (do_QueryInterface(debugClone)); michael@0: debug_rv = nsChromeRegistry::Canonify(debugURL); michael@0: if (NS_SUCCEEDED(debug_rv)) { michael@0: bool same; michael@0: debug_rv = aURI->Equals(debugURL, &same); michael@0: if (NS_SUCCEEDED(debug_rv)) { michael@0: NS_ASSERTION(same, "Non-canonified chrome uri passed to nsChromeProtocolHandler::NewChannel!"); michael@0: } michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: nsCOMPtr result; michael@0: michael@0: if (!nsChromeRegistry::gChromeRegistry) { michael@0: // We don't actually want this ref, we just want the service to michael@0: // initialize if it hasn't already. michael@0: nsCOMPtr reg = michael@0: mozilla::services::GetChromeRegistryService(); michael@0: NS_ENSURE_TRUE(nsChromeRegistry::gChromeRegistry, NS_ERROR_FAILURE); michael@0: } michael@0: michael@0: nsCOMPtr resolvedURI; michael@0: rv = nsChromeRegistry::gChromeRegistry->ConvertChromeURL(aURI, getter_AddRefs(resolvedURI)); michael@0: if (NS_FAILED(rv)) { michael@0: #ifdef DEBUG michael@0: nsAutoCString spec; michael@0: aURI->GetSpec(spec); michael@0: printf("Couldn't convert chrome URL: %s\n", spec.get()); michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: nsCOMPtr ioServ(do_GetIOService(&rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = ioServ->NewChannelFromURI(resolvedURI, getter_AddRefs(result)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: #ifdef DEBUG michael@0: nsCOMPtr fileChan(do_QueryInterface(result)); michael@0: if (fileChan) { michael@0: nsCOMPtr file; michael@0: fileChan->GetFile(getter_AddRefs(file)); michael@0: michael@0: bool exists = false; michael@0: file->Exists(&exists); michael@0: if (!exists) { michael@0: nsAutoCString path; michael@0: file->GetNativePath(path); michael@0: printf("Chrome file doesn't exist: %s\n", path.get()); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: // Make sure that the channel remembers where it was michael@0: // originally loaded from. michael@0: nsLoadFlags loadFlags = 0; michael@0: result->GetLoadFlags(&loadFlags); michael@0: result->SetLoadFlags(loadFlags & ~nsIChannel::LOAD_REPLACE); michael@0: rv = result->SetOriginalURI(aURI); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // Get a system principal for content files and set the owner michael@0: // property of the result michael@0: nsCOMPtr url = do_QueryInterface(aURI); michael@0: nsAutoCString path; michael@0: rv = url->GetPath(path); michael@0: if (StringBeginsWith(path, NS_LITERAL_CSTRING("/content/"))) michael@0: { michael@0: nsCOMPtr securityManager = michael@0: do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr principal; michael@0: rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr owner = do_QueryInterface(principal); michael@0: result->SetOwner(owner); michael@0: } michael@0: michael@0: // XXX Removed dependency-tracking code from here, because we're not michael@0: // tracking them anyways (with fastload we checked only in DEBUG michael@0: // and with startupcache not at all), but this is where we would start michael@0: // if we need to re-add. michael@0: // See bug 531886, bug 533038. michael@0: result->SetContentCharset(NS_LITERAL_CSTRING("UTF-8")); michael@0: michael@0: *aResult = result; michael@0: NS_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: ////////////////////////////////////////////////////////////////////////////////