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