/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* vim:set ts=4 sw=4 sts=4 et cin: */ /* ***** 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 mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * 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 ***** */ /* A protocol handler for ``chrome:'' */ #include "nsAutoPtr.h" #include "nsChromeProtocolHandler.h" #include "nsChromeRegistry.h" #include "nsCOMPtr.h" #include "nsContentCID.h" #include "nsCRT.h" #include "nsThreadUtils.h" #include "nsIChannel.h" #include "nsIChromeRegistry.h" #include "nsIComponentManager.h" #include "nsIFastLoadService.h" #include "nsIFile.h" #include "nsIFileURL.h" #include "nsIFileChannel.h" #include "nsIIOService.h" #include "nsIJARChannel.h" #include "nsIJARURI.h" #include "nsILoadGroup.h" #include "nsIObjectOutputStream.h" #include "nsIScriptSecurityManager.h" #include "nsIServiceManager.h" #include "nsIStandardURL.h" #include "nsIStreamListener.h" #include "nsNetUtil.h" #include "nsXPIDLString.h" #include "nsString.h" #include "prlog.h" #ifdef MOZ_XUL #include "nsIXULPrototypeCache.h" #endif //---------------------------------------------------------------------- static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID); //////////////////////////////////////////////////////////////////////////////// NS_IMPL_THREADSAFE_ISUPPORTS2(nsChromeProtocolHandler, nsIProtocolHandler, nsISupportsWeakReference) //////////////////////////////////////////////////////////////////////////////// // nsIProtocolHandler methods: NS_IMETHODIMP nsChromeProtocolHandler::GetScheme(nsACString &result) { result.AssignLiteral("chrome"); return NS_OK; } NS_IMETHODIMP nsChromeProtocolHandler::GetDefaultPort(PRInt32 *result) { *result = -1; // no port for chrome: URLs return NS_OK; } NS_IMETHODIMP nsChromeProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval) { // don't override anything. *_retval = PR_FALSE; return NS_OK; } NS_IMETHODIMP nsChromeProtocolHandler::GetProtocolFlags(PRUint32 *result) { *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) { nsresult rv; // Chrome: URLs (currently) have no additional structure beyond that provided // by standard URLs, so there is no "outer" given to CreateInstance nsCOMPtr<nsIStandardURL> surl(do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, rv); rv = surl->Init(nsIStandardURL::URLTYPE_STANDARD, -1, aSpec, aCharset, aBaseURI); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIURL> url(do_QueryInterface(surl, &rv)); NS_ENSURE_SUCCESS(rv, rv); // Canonify the "chrome:" URL; e.g., so that we collapse // "chrome://navigator/content/" and "chrome://navigator/content" // and "chrome://navigator/content/navigator.xul". rv = nsChromeRegistry::Canonify(url); if (NS_FAILED(rv)) return rv; surl->SetMutable(PR_FALSE); NS_ADDREF(*result = url); return NS_OK; } 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); if (NS_SUCCEEDED(debug_rv)) { PRBool same; debug_rv = aURI->Equals(debugURL, &same); if (NS_SUCCEEDED(debug_rv)) { NS_ASSERTION(same, "Non-canonified chrome uri passed to nsChromeProtocolHandler::NewChannel!"); } } } #endif nsCOMPtr<nsIChannel> result; if (!nsChromeRegistry::gChromeRegistry) { // We don't actually want this ref, we just want the service to // initialize if it hasn't already. nsCOMPtr<nsIChromeRegistry> reg(do_GetService(NS_CHROMEREGISTRY_CONTRACTID)); NS_ENSURE_TRUE(nsChromeRegistry::gChromeRegistry, NS_ERROR_FAILURE); } nsCOMPtr<nsIURI> resolvedURI; rv = nsChromeRegistry::gChromeRegistry->ConvertChromeURL(aURI, getter_AddRefs(resolvedURI)); if (NS_FAILED(rv)) { #ifdef DEBUG nsCAutoString spec; aURI->GetSpec(spec); printf("Couldn't convert chrome URL: %s\n", spec.get()); #endif return rv; } nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv)); NS_ENSURE_SUCCESS(rv, rv); rv = ioServ->NewChannelFromURI(resolvedURI, getter_AddRefs(result)); if (NS_FAILED(rv)) return rv; #ifdef DEBUG nsCOMPtr<nsIFileChannel> fileChan(do_QueryInterface(result)); if (fileChan) { 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 // 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); nsCAutoString path; rv = url->GetPath(path); if (StringBeginsWith(path, NS_LITERAL_CSTRING("/content/"))) { nsCOMPtr<nsIScriptSecurityManager> securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIPrincipal> principal; rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal)); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsISupports> owner = do_QueryInterface(principal); result->SetOwner(owner); } #ifdef MOZ_XUL // Track FastLoad file dependencies. // // This is harder than it ought to be! While an nsResChannel "is-a" // nsIFileChannel, an nsJARChannel is not. Once you unravel the jar: // URI, you may have a resource: URL -- but without a channel for it, // you can't get the URI that it yields through substitution! // // XXXbe fix nsResChannel.cpp to move the substitution code into a new // nsResURL class? nsCOMPtr<nsIFastLoadService> fastLoadServ(do_GetFastLoadService()); if (fastLoadServ) { nsCOMPtr<nsIObjectOutputStream> objectOutput; fastLoadServ->GetOutputStream(getter_AddRefs(objectOutput)); if (objectOutput) { nsCOMPtr<nsIFile> file; nsCOMPtr<nsIURI> uri; result->GetURI(getter_AddRefs(uri)); uri = NS_GetInnermostURI(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)); if (file) { rv = fastLoadServ->AddDependency(file); if (NS_FAILED(rv)) { nsCOMPtr<nsIXULPrototypeCache> cache (do_GetService(kXULPrototypeCacheCID)); if (cache) cache->AbortFastLoads(); } } } } #endif *aResult = result; NS_ADDREF(*aResult); return NS_OK; } ////////////////////////////////////////////////////////////////////////////////