Back to index

lightning-sunbird  0.9+nobinonly
nsChromeProtocolHandler.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vim:set ts=4 sw=4 sts=4 et cin: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /*
00040 
00041   A protocol handler for ``chrome:''
00042 
00043 */
00044 
00045 #include "nsChromeProtocolHandler.h"
00046 #include "nsChromeRegistry.h"
00047 #include "nsCOMPtr.h"
00048 #include "nsContentCID.h"
00049 #include "nsCRT.h"
00050 #include "nsEventQueueUtils.h"
00051 #include "nsIChannel.h"
00052 #include "nsIChromeRegistry.h"
00053 #include "nsIComponentManager.h"
00054 #include "nsIEventQueue.h"
00055 #include "nsIEventQueueService.h"
00056 #include "nsIFastLoadService.h"
00057 #include "nsIFile.h"
00058 #include "nsIFileURL.h"
00059 #include "nsIFileChannel.h"
00060 #include "nsIIOService.h"
00061 #include "nsIJARChannel.h"
00062 #include "nsIJARURI.h"
00063 #include "nsILoadGroup.h"
00064 #include "nsIObjectOutputStream.h"
00065 #include "nsIScriptSecurityManager.h"
00066 #include "nsIServiceManager.h"
00067 #include "nsIStandardURL.h"
00068 #include "nsIStreamListener.h"
00069 #include "nsIXULPrototypeCache.h"
00070 #include "nsIXULPrototypeDocument.h"
00071 #include "nsNetUtil.h"
00072 #include "nsXPIDLString.h"
00073 #include "nsString.h"
00074 #include "prlog.h"
00075 
00076 //----------------------------------------------------------------------
00077 
00078 static NS_DEFINE_CID(kXULPrototypeCacheCID,      NS_XULPROTOTYPECACHE_CID);
00079 
00080 //----------------------------------------------------------------------
00081 //
00082 //  A channel that's used for loading cached chrome documents. Since a
00083 //  cached chrome document really doesn't have anything to do to load,
00084 //  this is just the puppeteer that pulls the webshell's strings at the
00085 //  right time.
00086 //
00087 //  Specifically, when AsyncOpen() is called, it adds the channel to
00088 //  the load group, and queues an asychronous event to fire the
00089 //  listener's OnStartRequest().
00090 //
00091 //  After triggering OnStartRequest(), it then queues another event
00092 //  which will fire the listener's OnStopRequest() and remove the
00093 //  channel from the load group.
00094 //
00095 //  Each is done asynchronously to allow the stack to unwind back to
00096 //  the main event loop. This avoids any weird re-entrancy that occurs
00097 //  if we try to immediately fire the On[Start|Stop]Request().
00098 //
00099 //  For logging information, NSPR_LOG_MODULES=nsCachedChromeChannel:5
00100 //
00101 #define LOG(args) PR_LOG(gLog, PR_LOG_DEBUG, args)
00102 
00103 class nsCachedChromeChannel : public nsIChannel
00104 {
00105 protected:
00106     ~nsCachedChromeChannel();
00107 
00108     nsCOMPtr<nsIURI>            mURI;
00109     nsCOMPtr<nsIURI>            mOriginalURI;
00110     nsCOMPtr<nsILoadGroup>      mLoadGroup;
00111     nsCOMPtr<nsIStreamListener> mListener;
00112     nsCOMPtr<nsISupports>       mContext;
00113     nsLoadFlags                 mLoadFlags;
00114     nsCOMPtr<nsISupports>       mOwner;
00115     nsresult                    mStatus;
00116 
00117     static NS_HIDDEN_(nsresult)
00118     PostLoadEvent(nsCachedChromeChannel* aChannel, PLHandleEventProc aHandler);
00119 
00120     static void* PR_CALLBACK HandleLoadEvent(PLEvent* aEvent);
00121     static void PR_CALLBACK DestroyLoadEvent(PLEvent* aEvent);
00122 
00123 #ifdef PR_LOGGING
00124     static PRLogModuleInfo* gLog;
00125 #endif
00126 
00127 public:
00128     nsCachedChromeChannel(nsIURI* aURI);
00129 
00130     NS_DECL_ISUPPORTS
00131 
00132     // nsIRequest
00133     NS_IMETHOD GetName(nsACString &result) { return mURI->GetSpec(result); }
00134     NS_IMETHOD IsPending(PRBool *_retval) { *_retval = (mListener != nsnull); return NS_OK; }
00135     NS_IMETHOD GetStatus(nsresult *status) { *status = mStatus; return NS_OK; }
00136     NS_IMETHOD Cancel(nsresult status)  { mStatus = status; return NS_OK; }
00137     NS_IMETHOD Suspend(void) { return NS_OK; } // XXX technically wrong
00138     NS_IMETHOD Resume(void)  { return NS_OK; } // XXX technically wrong
00139     NS_IMETHOD GetLoadGroup(nsILoadGroup **);
00140     NS_IMETHOD SetLoadGroup(nsILoadGroup *);
00141     NS_IMETHOD GetLoadFlags(nsLoadFlags *);
00142     NS_IMETHOD SetLoadFlags(nsLoadFlags);
00143 
00144 // nsIChannel
00145     NS_DECL_NSICHANNEL
00146 
00147 };
00148 
00149 #ifdef PR_LOGGING
00150 PRLogModuleInfo* nsCachedChromeChannel::gLog;
00151 #endif
00152 
00153 NS_IMPL_ISUPPORTS2(nsCachedChromeChannel,
00154                    nsIChannel,
00155                    nsIRequest)
00156 
00157 nsCachedChromeChannel::nsCachedChromeChannel(nsIURI* aURI)
00158     : mURI(aURI)
00159     , mLoadFlags(nsIRequest::LOAD_NORMAL)
00160     , mStatus(NS_OK)
00161 {
00162 #ifdef PR_LOGGING
00163     if (! gLog)
00164         gLog = PR_NewLogModule("nsCachedChromeChannel");
00165 #endif
00166 
00167     LOG(("nsCachedChromeChannel[%p]: created", this));
00168 }
00169 
00170 
00171 nsCachedChromeChannel::~nsCachedChromeChannel()
00172 {
00173     LOG(("nsCachedChromeChannel[%p]: destroyed", this));
00174 }
00175 
00176 
00177 NS_IMETHODIMP
00178 nsCachedChromeChannel::GetOriginalURI(nsIURI* *aOriginalURI)
00179 {
00180     *aOriginalURI = mOriginalURI ? mOriginalURI : mURI;
00181     NS_ADDREF(*aOriginalURI);
00182     return NS_OK;
00183 }
00184 
00185 NS_IMETHODIMP
00186 nsCachedChromeChannel::SetOriginalURI(nsIURI* aOriginalURI)
00187 {
00188     mOriginalURI = aOriginalURI;
00189     return NS_OK;
00190 }
00191 
00192 NS_IMETHODIMP
00193 nsCachedChromeChannel::GetURI(nsIURI* *aURI)
00194 {
00195     *aURI = mURI;
00196     NS_ADDREF(*aURI);
00197     return NS_OK;
00198 }
00199 
00200 NS_IMETHODIMP
00201 nsCachedChromeChannel::Open(nsIInputStream **_retval)
00202 {
00203 //    NS_NOTREACHED("don't do that");
00204     *_retval = nsnull;
00205     return NS_ERROR_FAILURE;
00206 }
00207 
00208 NS_IMETHODIMP
00209 nsCachedChromeChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
00210 {
00211     NS_ENSURE_ARG_POINTER(listener);
00212 
00213     nsresult rv;
00214 
00215     // Fire OnStartRequest and OnStopRequest, which will cause the XUL
00216     // document to get embedded.
00217     LOG(("nsCachedChromeChannel[%p]: posting load event for %p",
00218         this, listener));
00219 
00220     // Queue an event to ourselves to let the stack unwind before
00221     // calling OnStartRequest(). This allows embedding to occur
00222     // before we fire OnStopRequest().
00223     rv = PostLoadEvent(this, HandleLoadEvent);
00224     if (NS_FAILED(rv))
00225         return rv;
00226 
00227     mContext  = ctxt;
00228     mListener = listener;
00229 
00230     if (mLoadGroup) {
00231         LOG(("nsCachedChromeChannel[%p]: adding self to load group %p",
00232             this, mLoadGroup.get()));
00233 
00234         (void) mLoadGroup->AddRequest(this, nsnull);
00235     }
00236     return NS_OK;
00237 }
00238 
00239 NS_IMETHODIMP
00240 nsCachedChromeChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
00241 {
00242     return NS_ERROR_NOT_IMPLEMENTED;
00243 }
00244 
00245 NS_IMETHODIMP
00246 nsCachedChromeChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
00247 {
00248     *aLoadFlags = mLoadFlags;
00249     return NS_OK;
00250 }
00251 
00252 NS_IMETHODIMP
00253 nsCachedChromeChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
00254 {
00255     mLoadFlags = aLoadFlags;
00256     return NS_OK;
00257 }
00258 
00259 NS_IMETHODIMP
00260 nsCachedChromeChannel::GetOwner(nsISupports * *aOwner)
00261 {
00262     *aOwner = mOwner;
00263     NS_IF_ADDREF(*aOwner);
00264     return NS_OK;
00265 }
00266 
00267 NS_IMETHODIMP
00268 nsCachedChromeChannel::SetOwner(nsISupports * aOwner)
00269 {
00270     mOwner = aOwner;
00271     return NS_OK;
00272 }
00273 
00274 NS_IMETHODIMP
00275 nsCachedChromeChannel::GetLoadGroup(nsILoadGroup * *aLoadGroup)
00276 {
00277     *aLoadGroup = mLoadGroup;
00278     NS_IF_ADDREF(*aLoadGroup);
00279     return NS_OK;
00280 }
00281 
00282 NS_IMETHODIMP
00283 nsCachedChromeChannel::SetLoadGroup(nsILoadGroup * aLoadGroup)
00284 {
00285     mLoadGroup = aLoadGroup;
00286     return NS_OK;
00287 }
00288 
00289 NS_IMETHODIMP
00290 nsCachedChromeChannel::GetNotificationCallbacks(nsIInterfaceRequestor * *aNotificationCallbacks)
00291 {
00292     *aNotificationCallbacks = nsnull;
00293     return NS_ERROR_FAILURE;
00294 }
00295 
00296 NS_IMETHODIMP
00297 nsCachedChromeChannel::SetNotificationCallbacks(nsIInterfaceRequestor * aNotificationCallbacks)
00298 {
00299     return NS_OK;    // ignored
00300 }
00301 
00302 NS_IMETHODIMP
00303 nsCachedChromeChannel::GetContentType(nsACString &aContentType)
00304 {
00305     aContentType.AssignLiteral("mozilla.application/cached-xul");
00306     return NS_OK;
00307 }
00308 
00309 NS_IMETHODIMP
00310 nsCachedChromeChannel::SetContentType(const nsACString &aContentType)
00311 {
00312     // Do not allow the content-type to be changed.
00313     NS_NOTREACHED("don't do that");
00314     return NS_ERROR_FAILURE;
00315 }
00316 
00317 NS_IMETHODIMP
00318 nsCachedChromeChannel::GetContentCharset(nsACString &aContentCharset)
00319 {
00320     aContentCharset.Truncate();
00321     return NS_OK;
00322 }
00323 
00324 NS_IMETHODIMP
00325 nsCachedChromeChannel::SetContentCharset(const nsACString &aContentCharset)
00326 {
00327     // Do not allow the content charset to be changed.
00328     NS_NOTREACHED("don't do that");
00329     return NS_ERROR_FAILURE;
00330 }
00331 
00332 NS_IMETHODIMP
00333 nsCachedChromeChannel::GetContentLength(PRInt32 *aContentLength)
00334 {
00335     NS_NOTREACHED("don't do that");
00336     *aContentLength = 0;
00337     return NS_ERROR_FAILURE;
00338 }
00339 
00340 NS_IMETHODIMP
00341 nsCachedChromeChannel::SetContentLength(PRInt32 aContentLength)
00342 {
00343     NS_NOTREACHED("nsCachedChromeChannel::SetContentLength");
00344     return NS_ERROR_NOT_IMPLEMENTED;
00345 }
00346 
00347 nsresult
00348 nsCachedChromeChannel::PostLoadEvent(nsCachedChromeChannel* aChannel,
00349                                      PLHandleEventProc aHandler)
00350 {
00351     nsCOMPtr<nsIEventQueue> queue;
00352     nsresult rv = NS_GetCurrentEventQ(getter_AddRefs(queue));
00353     if (NS_FAILED(rv))
00354         return rv;
00355 
00356     PLEvent* event = new PLEvent;
00357     if (! event)
00358         return NS_ERROR_OUT_OF_MEMORY;
00359 
00360     PL_InitEvent(event,
00361                  aChannel,
00362                  aHandler,
00363                  DestroyLoadEvent);
00364     NS_ADDREF(aChannel);
00365 
00366     rv = queue->PostEvent(event);
00367     if (NS_FAILED(rv))
00368         PL_DestroyEvent(event);
00369     return rv;
00370 }
00371 
00372 void* PR_CALLBACK
00373 nsCachedChromeChannel::HandleLoadEvent(PLEvent* aEvent)
00374 {
00375     // Fire the OnStartRequest() for the cached chrome channel, then
00376     // queue another event to trigger the OnStopRequest()...
00377     nsCachedChromeChannel* channel = (nsCachedChromeChannel*) aEvent->owner;
00378 
00379     // If the load has been cancelled, then just bail now. We won't
00380     // send On[Start|Stop]Request().
00381     if (NS_FAILED(channel->mStatus))
00382         return nsnull;
00383 
00384     LOG(("nsCachedChromeChannel[%p]: firing OnStartRequest for %p",
00385         channel, channel->mListener.get()));
00386 
00387     (void) channel->mListener->OnStartRequest(channel, channel->mContext);
00388 
00389     LOG(("nsCachedChromeChannel[%p]: firing OnStopRequest for %p",
00390         channel, channel->mListener.get()));
00391 
00392     (void) channel->mListener->OnStopRequest(channel, channel->mContext,
00393                                              channel->mStatus);
00394 
00395     if (channel->mLoadGroup) {
00396         LOG(("nsCachedChromeChannel[%p]: removing self from load group %p",
00397             channel, channel->mLoadGroup.get()));
00398 
00399         (void) channel->mLoadGroup->RemoveRequest(channel, nsnull, channel->mStatus);
00400     }
00401 
00402     channel->mListener = nsnull;
00403     channel->mContext  = nsnull;
00404 
00405     return nsnull;
00406 }
00407 
00408 void PR_CALLBACK
00409 nsCachedChromeChannel::DestroyLoadEvent(PLEvent* aEvent)
00410 {
00411     nsCachedChromeChannel* channel = (nsCachedChromeChannel*) aEvent->owner;
00412     NS_RELEASE(channel);
00413     delete aEvent;
00414 }
00415 
00417 
00418 NS_IMPL_THREADSAFE_ISUPPORTS2(nsChromeProtocolHandler, nsIProtocolHandler, nsISupportsWeakReference)
00419 
00420 
00421 // nsIProtocolHandler methods:
00422 
00423 NS_IMETHODIMP
00424 nsChromeProtocolHandler::GetScheme(nsACString &result)
00425 {
00426     result.AssignLiteral("chrome");
00427     return NS_OK;
00428 }
00429 
00430 NS_IMETHODIMP
00431 nsChromeProtocolHandler::GetDefaultPort(PRInt32 *result)
00432 {
00433     *result = -1;        // no port for chrome: URLs
00434     return NS_OK;
00435 }
00436 
00437 NS_IMETHODIMP
00438 nsChromeProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
00439 {
00440     // don't override anything.
00441     *_retval = PR_FALSE;
00442     return NS_OK;
00443 }
00444 
00445 NS_IMETHODIMP
00446 nsChromeProtocolHandler::GetProtocolFlags(PRUint32 *result)
00447 {
00448     *result = URI_STD;
00449     return NS_OK;
00450 }
00451 
00452 NS_IMETHODIMP
00453 nsChromeProtocolHandler::NewURI(const nsACString &aSpec,
00454                                 const char *aCharset,
00455                                 nsIURI *aBaseURI,
00456                                 nsIURI **result)
00457 {
00458     nsresult rv;
00459 
00460     // Chrome: URLs (currently) have no additional structure beyond that provided
00461     // by standard URLs, so there is no "outer" given to CreateInstance
00462 
00463     nsCOMPtr<nsIStandardURL> surl(do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv));
00464     NS_ENSURE_SUCCESS(rv, rv);
00465 
00466     rv = surl->Init(nsIStandardURL::URLTYPE_STANDARD, -1, aSpec, aCharset, aBaseURI);
00467     if (NS_FAILED(rv))
00468         return rv;
00469 
00470     nsCOMPtr<nsIURL> url(do_QueryInterface(surl, &rv));
00471     NS_ENSURE_SUCCESS(rv, rv);
00472 
00473     // Canonify the "chrome:" URL; e.g., so that we collapse
00474     // "chrome://navigator/content/" and "chrome://navigator/content"
00475     // and "chrome://navigator/content/navigator.xul".
00476 
00477     rv = nsChromeRegistry::Canonify(url);
00478     if (NS_FAILED(rv))
00479         return rv;
00480 
00481     surl->SetMutable(PR_FALSE);
00482 
00483     NS_ADDREF(*result = url);
00484     return NS_OK;
00485 }
00486 
00487 NS_IMETHODIMP
00488 nsChromeProtocolHandler::NewChannel(nsIURI* aURI,
00489                                     nsIChannel* *aResult)
00490 {
00491     NS_ENSURE_ARG_POINTER(aURI);
00492     NS_PRECONDITION(aResult, "Null out param");
00493     
00494 #ifdef DEBUG
00495     // Check that the uri we got is already canonified
00496     nsresult debug_rv;
00497     nsCOMPtr<nsIURI> debugClone;
00498     debug_rv = aURI->Clone(getter_AddRefs(debugClone));
00499     if (NS_SUCCEEDED(debug_rv)) {
00500         nsCOMPtr<nsIURL> debugURL (do_QueryInterface(debugClone));
00501         debug_rv = nsChromeRegistry::Canonify(debugURL);
00502         if (NS_SUCCEEDED(debug_rv)) {
00503             PRBool same;
00504             debug_rv = aURI->Equals(debugURL, &same);
00505             if (NS_SUCCEEDED(debug_rv)) {
00506                 NS_ASSERTION(same, "Non-canonified chrome uri passed to nsChromeProtocolHandler::NewChannel!");
00507             }
00508         }
00509     }
00510 #endif
00511 
00512     nsresult rv;
00513     nsCOMPtr<nsIChannel> result;
00514 
00515     // Check the prototype cache to see if we've already got the
00516     // document in the cache.
00517     nsCOMPtr<nsIXULPrototypeCache> cache
00518         (do_GetService(kXULPrototypeCacheCID));
00519     nsCOMPtr<nsIXULPrototypeDocument> proto;
00520 
00521     if (cache)
00522         cache->GetPrototype(aURI, getter_AddRefs(proto));
00523     else
00524         NS_WARNING("Unable to obtain the XUL prototype cache!");
00525 
00526     // Same comment as nsXULDocument::StartDocumentLoad and
00527     // nsXULDocument::ResumeWalk
00528     // - Ben Goodger
00529     //
00530     // We don't abort on failure here because there are too many valid
00531     // cases that can return failure, and the null-ness of |proto| is enough
00532     // to trigger the fail-safe parse-from-disk solution. Example failure cases
00533     // (for reference) include:
00534     //
00535     // NS_ERROR_NOT_AVAILABLE: the URI cannot be found in the FastLoad cache, 
00536     //                         parse from disk
00537     // other: the FastLoad cache file, XUL.mfl, could not be found, probably
00538     //        due to being accessed before a profile has been selected (e.g.
00539     //        loading chrome for the profile manager itself). This must be 
00540     //        parsed from disk. 
00541 
00542     if (proto) {
00543         // ...in which case, we'll create a dummy stream that'll just
00544         // load the thing.
00545         result = new nsCachedChromeChannel(aURI);
00546         if (! result)
00547             return NS_ERROR_OUT_OF_MEMORY;
00548     }
00549     else {
00550         // Miss. Resolve the chrome URL using the registry and do a
00551         // normal necko load.
00552         //nsXPIDLCString oldSpec;
00553         //aURI->GetSpec(getter_Copies(oldSpec));
00554         //printf("*************************** %s\n", (const char*)oldSpec);
00555 
00556         if (!nsChromeRegistry::gChromeRegistry) {
00557             // We don't actually want this ref, we just want the service to
00558             // initialize if it hasn't already.
00559             nsCOMPtr<nsIChromeRegistry> reg (do_GetService(NS_CHROMEREGISTRY_CONTRACTID));
00560         }
00561 
00562         NS_ENSURE_TRUE(nsChromeRegistry::gChromeRegistry, NS_ERROR_FAILURE);
00563 
00564         nsCOMPtr<nsIURI> resolvedURI;
00565         rv = nsChromeRegistry::gChromeRegistry->ConvertChromeURL(aURI, getter_AddRefs(resolvedURI));
00566         if (NS_FAILED(rv)) {
00567 #ifdef DEBUG
00568             nsCAutoString spec;
00569             aURI->GetSpec(spec);
00570             printf("Couldn't convert chrome URL: %s\n", spec.get());
00571 #endif
00572             return rv;
00573         }
00574 
00575         nsCOMPtr<nsIIOService> ioServ (do_GetIOService(&rv));
00576         NS_ENSURE_SUCCESS(rv, rv);
00577 
00578         rv = ioServ->NewChannelFromURI(resolvedURI, getter_AddRefs(result));
00579         if (NS_FAILED(rv)) return rv;
00580 
00581         // XXX Will be removed someday when we handle remote chrome.
00582         nsCOMPtr<nsIFileChannel> fileChan
00583             (do_QueryInterface(result));
00584         if (fileChan) {
00585 #ifdef DEBUG
00586             nsCOMPtr<nsIFile> file;
00587             fileChan->GetFile(getter_AddRefs(file));
00588 
00589             PRBool exists = PR_FALSE;
00590             file->Exists(&exists);
00591             if (!exists) {
00592                 nsCAutoString path;
00593                 file->GetNativePath(path);
00594                 printf("Chrome file doesn't exist: %s\n", path.get());
00595             }
00596 #endif
00597         }
00598         else {
00599             nsCOMPtr<nsIJARChannel> jarChan
00600                 (do_QueryInterface(result));
00601             if (!jarChan) {
00602                 NS_WARNING("Remote chrome not allowed! Only file:, resource:, and jar: are valid.\n");
00603                 result = nsnull;
00604                 return NS_ERROR_FAILURE;
00605             }
00606         }
00607 
00608         // Make sure that the channel remembers where it was
00609         // originally loaded from.
00610         rv = result->SetOriginalURI(aURI);
00611         if (NS_FAILED(rv)) return rv;
00612 
00613         // Get a system principal for content files and set the owner
00614         // property of the result
00615         nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
00616         nsCAutoString path;
00617         rv = url->GetPath(path);
00618         if (StringBeginsWith(path, NS_LITERAL_CSTRING("/content/")))
00619         {
00620             nsCOMPtr<nsIScriptSecurityManager> securityManager =
00621                      do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
00622             if (NS_FAILED(rv)) return rv;
00623 
00624             nsCOMPtr<nsIPrincipal> principal;
00625             rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal));
00626             if (NS_FAILED(rv)) return rv;
00627 
00628             nsCOMPtr<nsISupports> owner = do_QueryInterface(principal);
00629             result->SetOwner(owner);
00630         }
00631 
00632         // Track FastLoad file dependencies.
00633         //
00634         // This is harder than it ought to be!  While an nsResChannel "is-a"
00635         // nsIFileChannel, an nsJARChannel is not.  Once you unravel the jar:
00636         // URI, you may have a resource: URL -- but without a channel for it,
00637         // you can't get the URI that it yields through substitution!
00638         //
00639         // XXXbe fix nsResChannel.cpp to move the substitution code into a new
00640         //       nsResURL class?
00641         nsCOMPtr<nsIFastLoadService> fastLoadServ(do_GetFastLoadService());
00642         if (fastLoadServ) {
00643             nsCOMPtr<nsIObjectOutputStream> objectOutput;
00644             fastLoadServ->GetOutputStream(getter_AddRefs(objectOutput));
00645             if (objectOutput) {
00646                 nsCOMPtr<nsIFile> file;
00647 
00648                 if (fileChan) {
00649                     fileChan->GetFile(getter_AddRefs(file));
00650                 } else {
00651                     nsCOMPtr<nsIURI> uri;
00652                     result->GetURI(getter_AddRefs(uri));
00653 
00654                     // Loop, jar URIs can nest (e.g. jar:jar:A.jar!B.jar!C.xml).
00655                     // Often, however, we have jar:resource:/chrome/A.jar!C.xml.
00656                     nsCOMPtr<nsIJARURI> jarURI;
00657                     while ((jarURI = do_QueryInterface(uri)) != nsnull)
00658                         jarURI->GetJARFile(getter_AddRefs(uri));
00659 
00660                     // Here we have a URL of the form resource:/chrome/A.jar
00661                     // or file:/some/path/to/A.jar.
00662                     nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(uri));
00663                     if (fileURL)
00664                         fileURL->GetFile(getter_AddRefs(file));
00665                 }
00666 
00667                 if (file) {
00668                     rv = fastLoadServ->AddDependency(file);
00669                     if (NS_FAILED(rv))
00670                         cache->AbortFastLoads();
00671                 }
00672             }
00673         }
00674     }
00675 
00676     *aResult = result;
00677     NS_ADDREF(*aResult);
00678     return NS_OK;
00679 }
00680