Follow up fix for bug 623435. (r=brendan)
[mozilla-central.git] / chrome / src / nsChromeProtocolHandler.cpp
blob16c36a7a0ea8e27add3ed6971d4eddf36546523a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:set ts=4 sw=4 sts=4 et cin: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
41 A protocol handler for ``chrome:''
45 #include "nsAutoPtr.h"
46 #include "nsChromeProtocolHandler.h"
47 #include "nsChromeRegistry.h"
48 #include "nsCOMPtr.h"
49 #include "nsContentCID.h"
50 #include "nsCRT.h"
51 #include "nsThreadUtils.h"
52 #include "nsIChannel.h"
53 #include "nsIChromeRegistry.h"
54 #include "nsIComponentManager.h"
55 #include "nsIFastLoadService.h"
56 #include "nsIFile.h"
57 #include "nsIFileURL.h"
58 #include "nsIFileChannel.h"
59 #include "nsIIOService.h"
60 #include "nsIJARChannel.h"
61 #include "nsIJARURI.h"
62 #include "nsILoadGroup.h"
63 #include "nsIObjectOutputStream.h"
64 #include "nsIScriptSecurityManager.h"
65 #include "nsIServiceManager.h"
66 #include "nsIStandardURL.h"
67 #include "nsIStreamListener.h"
68 #include "nsNetUtil.h"
69 #include "nsXPIDLString.h"
70 #include "nsString.h"
71 #include "prlog.h"
73 #ifdef MOZ_XUL
74 #include "nsIXULPrototypeCache.h"
75 #endif
77 //----------------------------------------------------------------------
79 static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
81 ////////////////////////////////////////////////////////////////////////////////
83 NS_IMPL_THREADSAFE_ISUPPORTS2(nsChromeProtocolHandler,
84 nsIProtocolHandler,
85 nsISupportsWeakReference)
87 ////////////////////////////////////////////////////////////////////////////////
88 // nsIProtocolHandler methods:
90 NS_IMETHODIMP
91 nsChromeProtocolHandler::GetScheme(nsACString &result)
93 result.AssignLiteral("chrome");
94 return NS_OK;
97 NS_IMETHODIMP
98 nsChromeProtocolHandler::GetDefaultPort(PRInt32 *result)
100 *result = -1; // no port for chrome: URLs
101 return NS_OK;
104 NS_IMETHODIMP
105 nsChromeProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
107 // don't override anything.
108 *_retval = PR_FALSE;
109 return NS_OK;
112 NS_IMETHODIMP
113 nsChromeProtocolHandler::GetProtocolFlags(PRUint32 *result)
115 *result = URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE;
116 return NS_OK;
119 NS_IMETHODIMP
120 nsChromeProtocolHandler::NewURI(const nsACString &aSpec,
121 const char *aCharset,
122 nsIURI *aBaseURI,
123 nsIURI **result)
125 nsresult rv;
127 // Chrome: URLs (currently) have no additional structure beyond that provided
128 // by standard URLs, so there is no "outer" given to CreateInstance
130 nsCOMPtr<nsIStandardURL> surl(do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv));
131 NS_ENSURE_SUCCESS(rv, rv);
133 rv = surl->Init(nsIStandardURL::URLTYPE_STANDARD, -1, aSpec, aCharset, aBaseURI);
134 if (NS_FAILED(rv))
135 return rv;
137 nsCOMPtr<nsIURL> url(do_QueryInterface(surl, &rv));
138 NS_ENSURE_SUCCESS(rv, rv);
140 // Canonify the "chrome:" URL; e.g., so that we collapse
141 // "chrome://navigator/content/" and "chrome://navigator/content"
142 // and "chrome://navigator/content/navigator.xul".
144 rv = nsChromeRegistry::Canonify(url);
145 if (NS_FAILED(rv))
146 return rv;
148 surl->SetMutable(PR_FALSE);
150 NS_ADDREF(*result = url);
151 return NS_OK;
154 NS_IMETHODIMP
155 nsChromeProtocolHandler::NewChannel(nsIURI* aURI,
156 nsIChannel* *aResult)
158 nsresult rv;
160 NS_ENSURE_ARG_POINTER(aURI);
161 NS_PRECONDITION(aResult, "Null out param");
163 #ifdef DEBUG
164 // Check that the uri we got is already canonified
165 nsresult debug_rv;
166 nsCOMPtr<nsIURI> debugClone;
167 debug_rv = aURI->Clone(getter_AddRefs(debugClone));
168 if (NS_SUCCEEDED(debug_rv)) {
169 nsCOMPtr<nsIURL> debugURL (do_QueryInterface(debugClone));
170 debug_rv = nsChromeRegistry::Canonify(debugURL);
171 if (NS_SUCCEEDED(debug_rv)) {
172 PRBool same;
173 debug_rv = aURI->Equals(debugURL, &same);
174 if (NS_SUCCEEDED(debug_rv)) {
175 NS_ASSERTION(same, "Non-canonified chrome uri passed to nsChromeProtocolHandler::NewChannel!");
179 #endif
181 nsCOMPtr<nsIChannel> result;
183 if (!nsChromeRegistry::gChromeRegistry) {
184 // We don't actually want this ref, we just want the service to
185 // initialize if it hasn't already.
186 nsCOMPtr<nsIChromeRegistry> reg =
187 mozilla::services::GetChromeRegistryService();
188 NS_ENSURE_TRUE(nsChromeRegistry::gChromeRegistry, NS_ERROR_FAILURE);
191 nsCOMPtr<nsIURI> resolvedURI;
192 rv = nsChromeRegistry::gChromeRegistry->ConvertChromeURL(aURI, getter_AddRefs(resolvedURI));
193 if (NS_FAILED(rv)) {
194 #ifdef DEBUG
195 nsCAutoString spec;
196 aURI->GetSpec(spec);
197 printf("Couldn't convert chrome URL: %s\n", spec.get());
198 #endif
199 return rv;
202 nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv));
203 NS_ENSURE_SUCCESS(rv, rv);
205 rv = ioServ->NewChannelFromURI(resolvedURI, getter_AddRefs(result));
206 if (NS_FAILED(rv)) return rv;
208 #ifdef DEBUG
209 nsCOMPtr<nsIFileChannel> fileChan(do_QueryInterface(result));
210 if (fileChan) {
211 nsCOMPtr<nsIFile> file;
212 fileChan->GetFile(getter_AddRefs(file));
214 PRBool exists = PR_FALSE;
215 file->Exists(&exists);
216 if (!exists) {
217 nsCAutoString path;
218 file->GetNativePath(path);
219 printf("Chrome file doesn't exist: %s\n", path.get());
222 #endif
224 // Make sure that the channel remembers where it was
225 // originally loaded from.
226 rv = result->SetOriginalURI(aURI);
227 if (NS_FAILED(rv)) return rv;
229 // Get a system principal for content files and set the owner
230 // property of the result
231 nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
232 nsCAutoString path;
233 rv = url->GetPath(path);
234 if (StringBeginsWith(path, NS_LITERAL_CSTRING("/content/")))
236 nsCOMPtr<nsIScriptSecurityManager> securityManager =
237 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
238 if (NS_FAILED(rv)) return rv;
240 nsCOMPtr<nsIPrincipal> principal;
241 rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal));
242 if (NS_FAILED(rv)) return rv;
244 nsCOMPtr<nsISupports> owner = do_QueryInterface(principal);
245 result->SetOwner(owner);
248 #ifdef MOZ_XUL
249 // Track FastLoad file dependencies.
251 // This is harder than it ought to be! While an nsResChannel "is-a"
252 // nsIFileChannel, an nsJARChannel is not. Once you unravel the jar:
253 // URI, you may have a resource: URL -- but without a channel for it,
254 // you can't get the URI that it yields through substitution!
256 // XXXbe fix nsResChannel.cpp to move the substitution code into a new
257 // nsResURL class?
258 nsCOMPtr<nsIFastLoadService> fastLoadServ(do_GetFastLoadService());
259 if (fastLoadServ) {
260 nsCOMPtr<nsIObjectOutputStream> objectOutput;
261 fastLoadServ->GetOutputStream(getter_AddRefs(objectOutput));
262 if (objectOutput) {
263 nsCOMPtr<nsIFile> file;
265 nsCOMPtr<nsIURI> uri;
266 result->GetURI(getter_AddRefs(uri));
267 uri = NS_GetInnermostURI(uri);
269 // Here we have a URL of the form resource:/chrome/A.jar
270 // or file:/some/path/to/A.jar.
271 nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(uri));
272 if (fileURL)
273 fileURL->GetFile(getter_AddRefs(file));
275 if (file) {
276 rv = fastLoadServ->AddDependency(file);
277 if (NS_FAILED(rv)) {
278 nsCOMPtr<nsIXULPrototypeCache> cache
279 (do_GetService(kXULPrototypeCacheCID));
280 if (cache)
281 cache->AbortFastLoads();
286 #endif
288 *aResult = result;
289 NS_ADDREF(*aResult);
290 return NS_OK;
293 ////////////////////////////////////////////////////////////////////////////////