Back to index

lightning-sunbird  0.9+nobinonly
nsPrefetchService.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2002
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Darin Fisher <darin@netscape.com> (original author)
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * 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 #include "nsPrefetchService.h"
00039 #include "nsIServiceManager.h"
00040 #include "nsICategoryManager.h"
00041 #include "nsIObserverService.h"
00042 #include "nsIPrefService.h"
00043 #include "nsIPrefBranch2.h"
00044 #include "nsIDocCharset.h"
00045 #include "nsIWebProgress.h"
00046 #include "nsCURILoader.h"
00047 #include "nsICachingChannel.h"
00048 #include "nsICacheVisitor.h"
00049 #include "nsIHttpChannel.h"
00050 #include "nsIURL.h"
00051 #include "nsNetUtil.h"
00052 #include "nsString.h"
00053 #include "nsXPIDLString.h"
00054 #include "nsReadableUtils.h"
00055 #include "nsAutoPtr.h"
00056 #include "prtime.h"
00057 #include "prlog.h"
00058 #include "plstr.h"
00059 
00060 #if defined(PR_LOGGING)
00061 //
00062 // To enable logging (see prlog.h for full details):
00063 //
00064 //    set NSPR_LOG_MODULES=nsPrefetch:5
00065 //    set NSPR_LOG_FILE=prefetch.log
00066 //
00067 // this enables PR_LOG_ALWAYS level information and places all output in
00068 // the file http.log
00069 //
00070 static PRLogModuleInfo *gPrefetchLog;
00071 #endif
00072 #define LOG(args) PR_LOG(gPrefetchLog, 4, args)
00073 #define LOG_ENABLED() PR_LOG_TEST(gPrefetchLog, 4)
00074 
00075 static NS_DEFINE_IID(kDocLoaderServiceCID, NS_DOCUMENTLOADER_SERVICE_CID);
00076 static NS_DEFINE_IID(kPrefServiceCID, NS_PREFSERVICE_CID);
00077 
00078 #define PREFETCH_PREF "network.prefetch-next"
00079 
00080 //-----------------------------------------------------------------------------
00081 // helpers
00082 //-----------------------------------------------------------------------------
00083 
00084 static inline PRUint32
00085 PRTimeToSeconds(PRTime t_usec)
00086 {
00087     PRTime usec_per_sec;
00088     PRUint32 t_sec;
00089     LL_I2L(usec_per_sec, PR_USEC_PER_SEC);
00090     LL_DIV(t_usec, t_usec, usec_per_sec);
00091     LL_L2I(t_sec, t_usec);
00092     return t_sec;
00093 }
00094 
00095 #define NowInSeconds() PRTimeToSeconds(PR_Now())
00096 
00097 //-----------------------------------------------------------------------------
00098 // nsPrefetchListener <public>
00099 //-----------------------------------------------------------------------------
00100 
00101 nsPrefetchListener::nsPrefetchListener(nsPrefetchService *aService)
00102 {
00103     NS_ADDREF(mService = aService);
00104 }
00105 
00106 nsPrefetchListener::~nsPrefetchListener()
00107 {
00108     NS_RELEASE(mService);
00109 }
00110 
00111 //-----------------------------------------------------------------------------
00112 // nsPrefetchListener <private>
00113 //-----------------------------------------------------------------------------
00114 
00115 NS_METHOD
00116 nsPrefetchListener::ConsumeSegments(nsIInputStream *aInputStream,
00117                                     void *aClosure,
00118                                     const char *aFromSegment,
00119                                     PRUint32 aOffset,
00120                                     PRUint32 aCount,
00121                                     PRUint32 *aBytesConsumed)
00122 {
00123     *aBytesConsumed = aCount;
00124     return NS_OK;
00125 }
00126 
00127 //-----------------------------------------------------------------------------
00128 // nsPrefetchListener::nsISupports
00129 //-----------------------------------------------------------------------------
00130 
00131 NS_IMPL_ISUPPORTS4(nsPrefetchListener,
00132                    nsIRequestObserver,
00133                    nsIStreamListener,
00134                    nsIInterfaceRequestor,
00135                    nsIChannelEventSink)
00136 
00137 //-----------------------------------------------------------------------------
00138 // nsPrefetchListener::nsIStreamListener
00139 //-----------------------------------------------------------------------------
00140 
00141 NS_IMETHODIMP
00142 nsPrefetchListener::OnStartRequest(nsIRequest *aRequest,
00143                                    nsISupports *aContext)
00144 {
00145     nsresult rv;
00146 
00147     nsCOMPtr<nsICachingChannel> cachingChannel(do_QueryInterface(aRequest, &rv));
00148     if (NS_FAILED(rv)) return rv;
00149 
00150     // no need to prefetch a document that is already in the cache
00151     PRBool fromCache;
00152     if (NS_SUCCEEDED(cachingChannel->IsFromCache(&fromCache)) && fromCache) {
00153         LOG(("document is already in the cache; canceling prefetch\n"));
00154         return NS_BINDING_ABORTED;
00155     }
00156 
00157     //
00158     // no need to prefetch a document that must be requested fresh each
00159     // and every time.
00160     //
00161     nsCOMPtr<nsISupports> cacheToken;
00162     cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
00163     if (!cacheToken)
00164         return NS_ERROR_ABORT; // bail, no cache entry
00165 
00166     nsCOMPtr<nsICacheEntryInfo> entryInfo(do_QueryInterface(cacheToken, &rv));
00167     if (NS_FAILED(rv)) return rv;
00168 
00169     PRUint32 expTime;
00170     if (NS_SUCCEEDED(entryInfo->GetExpirationTime(&expTime))) {
00171         if (NowInSeconds() >= expTime) {
00172             LOG(("document cannot be reused from cache; canceling prefetch\n"));
00173             return NS_BINDING_ABORTED;
00174         }
00175     }
00176     return NS_OK;
00177 }
00178 
00179 NS_IMETHODIMP
00180 nsPrefetchListener::OnDataAvailable(nsIRequest *aRequest,
00181                                     nsISupports *aContext,
00182                                     nsIInputStream *aStream,
00183                                     PRUint32 aOffset,
00184                                     PRUint32 aCount)
00185 {
00186     PRUint32 bytesRead = 0;
00187     aStream->ReadSegments(ConsumeSegments, nsnull, aCount, &bytesRead);
00188     LOG(("prefetched %u bytes [offset=%u]\n", bytesRead, aOffset));
00189     return NS_OK;
00190 }
00191 
00192 NS_IMETHODIMP
00193 nsPrefetchListener::OnStopRequest(nsIRequest *aRequest,
00194                                   nsISupports *aContext,
00195                                   nsresult aStatus)
00196 {
00197     LOG(("done prefetching [status=%x]\n", aStatus));
00198 
00199     mService->ProcessNextURI();
00200     return NS_OK;
00201 }
00202 
00203 //-----------------------------------------------------------------------------
00204 // nsPrefetchListener::nsIInterfaceRequestor
00205 //-----------------------------------------------------------------------------
00206 
00207 NS_IMETHODIMP
00208 nsPrefetchListener::GetInterface(const nsIID &aIID, void **aResult)
00209 {
00210     if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
00211         NS_ADDREF_THIS();
00212         *aResult = NS_STATIC_CAST(nsIChannelEventSink *, this);
00213         return NS_OK;
00214     }
00215 
00216     return NS_ERROR_NO_INTERFACE;
00217 }
00218 
00219 //-----------------------------------------------------------------------------
00220 // nsPrefetchListener::nsIChannelEventSink
00221 //-----------------------------------------------------------------------------
00222 
00223 NS_IMETHODIMP
00224 nsPrefetchListener::OnChannelRedirect(nsIChannel *aOldChannel,
00225                                       nsIChannel *aNewChannel,
00226                                       PRUint32 aFlags)
00227 {
00228     nsCOMPtr<nsIURI> newURI;
00229     nsresult rv = aNewChannel->GetURI(getter_AddRefs(newURI));
00230     if (NS_FAILED(rv))
00231         return rv;
00232 
00233     PRBool match;
00234     rv = newURI->SchemeIs("http", &match); 
00235     if (NS_FAILED(rv) || !match) {
00236         LOG(("rejected: URL is not of type http\n"));
00237         return NS_ERROR_ABORT;
00238     }
00239 
00240     // HTTP request headers are not automatically forwarded to the new channel.
00241     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aNewChannel);
00242     NS_ENSURE_STATE(httpChannel);
00243 
00244     httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
00245                                   NS_LITERAL_CSTRING("prefetch"), PR_FALSE);
00246 
00247     mService->UpdateCurrentChannel(aNewChannel);
00248     return NS_OK;
00249 }
00250 
00251 //-----------------------------------------------------------------------------
00252 // nsPrefetchService <public>
00253 //-----------------------------------------------------------------------------
00254 
00255 nsPrefetchService::nsPrefetchService()
00256     : mQueueHead(nsnull)
00257     , mQueueTail(nsnull)
00258     , mStopCount(0)
00259     , mDisabled(PR_TRUE)
00260 {
00261 }
00262 
00263 nsPrefetchService::~nsPrefetchService()
00264 {
00265     // cannot reach destructor if prefetch in progress (listener owns reference
00266     // to this service)
00267     EmptyQueue();
00268 }
00269 
00270 nsresult
00271 nsPrefetchService::Init()
00272 {
00273 #if defined(PR_LOGGING)
00274     if (!gPrefetchLog)
00275         gPrefetchLog = PR_NewLogModule("nsPrefetch");
00276 #endif
00277 
00278     nsresult rv;
00279 
00280     // read prefs and hook up pref observer
00281     nsCOMPtr<nsIPrefBranch2> prefs(do_GetService(kPrefServiceCID, &rv));
00282     if (NS_SUCCEEDED(rv)) {
00283       PRBool enabled;
00284       rv = prefs->GetBoolPref(PREFETCH_PREF, &enabled);
00285       if (NS_SUCCEEDED(rv) && enabled)
00286         mDisabled = PR_FALSE;
00287 
00288       prefs->AddObserver(PREFETCH_PREF, this, PR_TRUE);
00289     }
00290 
00291     // Observe xpcom-shutdown event
00292     nsCOMPtr<nsIObserverService> observerServ(
00293             do_GetService("@mozilla.org/observer-service;1", &rv));
00294     if (NS_FAILED(rv)) return rv;
00295 
00296     rv = observerServ->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
00297     if (NS_FAILED(rv)) return rv;
00298 
00299     if (!mDisabled)
00300         AddProgressListener();
00301 
00302     return NS_OK;
00303 }
00304 
00305 void
00306 nsPrefetchService::ProcessNextURI()
00307 {
00308     nsresult rv;
00309     nsCOMPtr<nsIURI> uri, referrer;
00310 
00311     mCurrentChannel = nsnull;
00312 
00313     nsRefPtr<nsPrefetchListener> listener(new nsPrefetchListener(this));
00314     if (!listener) return;
00315 
00316     do {
00317         rv = DequeueURI(getter_AddRefs(uri), getter_AddRefs(referrer));
00318         if (NS_FAILED(rv)) break;
00319 
00320 #if defined(PR_LOGGING)
00321         if (LOG_ENABLED()) {
00322             nsCAutoString spec;
00323             uri->GetSpec(spec);
00324             LOG(("ProcessNextURI [%s]\n", spec.get()));
00325         }
00326 #endif
00327 
00328         //
00329         // if opening the channel fails, then just skip to the next uri
00330         //
00331         rv = NS_NewChannel(getter_AddRefs(mCurrentChannel), uri,
00332                            nsnull, nsnull, listener,
00333                            nsIRequest::LOAD_BACKGROUND |
00334                            nsICachingChannel::LOAD_ONLY_IF_MODIFIED);
00335         if (NS_FAILED(rv)) continue;
00336 
00337         // configure HTTP specific stuff
00338         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mCurrentChannel));
00339         if (httpChannel) {
00340             httpChannel->SetReferrer(referrer);
00341             httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
00342                                           NS_LITERAL_CSTRING("prefetch"),
00343                                           PR_FALSE);
00344         }
00345 
00346         rv = mCurrentChannel->AsyncOpen(listener, nsnull);
00347     }
00348     while (NS_FAILED(rv));
00349 }
00350 
00351 //-----------------------------------------------------------------------------
00352 // nsPrefetchService <private>
00353 //-----------------------------------------------------------------------------
00354 
00355 void
00356 nsPrefetchService::AddProgressListener()
00357 {
00358     // Register as an observer for the document loader  
00359     nsCOMPtr<nsIWebProgress> progress(do_GetService(kDocLoaderServiceCID));
00360     if (progress)
00361         progress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
00362 }
00363 
00364 void
00365 nsPrefetchService::RemoveProgressListener()
00366 {
00367     // Register as an observer for the document loader  
00368     nsCOMPtr<nsIWebProgress> progress(do_GetService(kDocLoaderServiceCID));
00369     if (progress)
00370         progress->RemoveProgressListener(this);
00371 }
00372 
00373 nsresult
00374 nsPrefetchService::EnqueueURI(nsIURI *aURI, nsIURI *aReferrerURI)
00375 {
00376     nsPrefetchNode *node = new nsPrefetchNode(aURI, aReferrerURI);
00377     if (!node)
00378         return NS_ERROR_OUT_OF_MEMORY;
00379 
00380     if (!mQueueTail) {
00381         mQueueHead = node;
00382         mQueueTail = node;
00383     }
00384     else {
00385         mQueueTail->mNext = node;
00386         mQueueTail = node;
00387     }
00388 
00389     return NS_OK;
00390 }
00391 
00392 nsresult
00393 nsPrefetchService::DequeueURI(nsIURI **aURI, nsIURI **aReferrerURI)
00394 {
00395     if (!mQueueHead)
00396         return NS_ERROR_NOT_AVAILABLE;
00397 
00398     // remove from the head
00399     NS_ADDREF(*aURI = mQueueHead->mURI);
00400     NS_ADDREF(*aReferrerURI = mQueueHead->mReferrerURI);
00401 
00402     nsPrefetchNode *node = mQueueHead;
00403     mQueueHead = mQueueHead->mNext;
00404     delete node;
00405 
00406     if (!mQueueHead)
00407         mQueueTail = nsnull;
00408 
00409     return NS_OK;
00410 }
00411 
00412 void
00413 nsPrefetchService::EmptyQueue()
00414 {
00415     nsresult rv;
00416     nsCOMPtr<nsIURI> uri, referrer;
00417 
00418     do {
00419         rv = DequeueURI(getter_AddRefs(uri),
00420                         getter_AddRefs(referrer));
00421     }
00422     while (NS_SUCCEEDED(rv));
00423 }
00424 
00425 void
00426 nsPrefetchService::StartPrefetching()
00427 {
00428     //
00429     // at initialization time we might miss the first DOCUMENT START
00430     // notification, so we have to be careful to avoid letting our
00431     // stop count go negative.
00432     //
00433     if (mStopCount > 0)
00434         mStopCount--;
00435 
00436     LOG(("StartPrefetching [stopcount=%d]\n", mStopCount));
00437 
00438     // only start prefetching after we've received enough DOCUMENT
00439     // STOP notifications.  we do this inorder to defer prefetching
00440     // until after all sub-frames have finished loading.
00441     if (mStopCount == 0 && !mCurrentChannel)
00442         ProcessNextURI();
00443 }
00444 
00445 void
00446 nsPrefetchService::StopPrefetching()
00447 {
00448     mStopCount++;
00449 
00450     LOG(("StopPrefetching [stopcount=%d]\n", mStopCount));
00451 
00452     // only kill the prefetch queue if we've actually started prefetching.
00453     if (!mCurrentChannel)
00454         return;
00455 
00456     mCurrentChannel->Cancel(NS_BINDING_ABORTED);
00457     mCurrentChannel = nsnull;
00458     EmptyQueue();
00459 }
00460 
00461 //-----------------------------------------------------------------------------
00462 // nsPrefetchService::nsISupports
00463 //-----------------------------------------------------------------------------
00464 
00465 NS_IMPL_ISUPPORTS4(nsPrefetchService,
00466                    nsIPrefetchService,
00467                    nsIWebProgressListener,
00468                    nsIObserver,
00469                    nsISupportsWeakReference)
00470 
00471 //-----------------------------------------------------------------------------
00472 // nsPrefetchService::nsIPretetchService
00473 //-----------------------------------------------------------------------------
00474 
00475 NS_IMETHODIMP
00476 nsPrefetchService::PrefetchURI(nsIURI *aURI, nsIURI *aReferrerURI, PRBool aExplicit)
00477 {
00478     nsresult rv;
00479 
00480     NS_ENSURE_ARG_POINTER(aURI);
00481     NS_ENSURE_ARG_POINTER(aReferrerURI);
00482 
00483 #if defined(PR_LOGGING)
00484     if (LOG_ENABLED()) {
00485         nsCAutoString spec;
00486         aURI->GetSpec(spec);
00487         LOG(("PrefetchURI [%s]\n", spec.get()));
00488     }
00489 #endif
00490 
00491     if (mDisabled) {
00492         LOG(("rejected: prefetch service is disabled\n"));
00493         return NS_ERROR_ABORT;
00494     }
00495 
00496     //
00497     // XXX we should really be asking the protocol handler if it supports
00498     // caching, so we can determine if there is any value to prefetching.
00499     // for now, we'll only prefetch http links since we know that's the 
00500     // most common case.  ignore https links since https content only goes
00501     // into the memory cache.
00502     //
00503     // XXX we might want to either leverage nsIProtocolHandler::protocolFlags
00504     // or possibly nsIRequest::loadFlags to determine if this URI should be
00505     // prefetched.
00506     //
00507     PRBool match;
00508     rv = aURI->SchemeIs("http", &match); 
00509     if (NS_FAILED(rv) || !match) {
00510         LOG(("rejected: URL is not of type http\n"));
00511         return NS_ERROR_ABORT;
00512     }
00513 
00514     // 
00515     // the referrer URI must be http:
00516     //
00517     rv = aReferrerURI->SchemeIs("http", &match);
00518     if (NS_FAILED(rv) || !match) {
00519         LOG(("rejected: referrer URL is not of type http\n"));
00520         return NS_ERROR_ABORT;
00521     }
00522 
00523     // skip URLs that contain query strings, except URLs for which prefetching
00524     // has been explicitly requested.
00525     if (!aExplicit) {
00526         nsCOMPtr<nsIURL> url(do_QueryInterface(aURI, &rv));
00527         if (NS_FAILED(rv)) return rv;
00528         nsCAutoString query;
00529         rv = url->GetQuery(query);
00530         if (NS_FAILED(rv) || !query.IsEmpty()) {
00531             LOG(("rejected: URL has a query string\n"));
00532             return NS_ERROR_ABORT;
00533         }
00534     }
00535 
00536     // 
00537     // cancel if being prefetched
00538     //
00539     if (mCurrentChannel) {
00540         nsCOMPtr<nsIURI> currentURI;
00541         mCurrentChannel->GetURI(getter_AddRefs(currentURI));
00542         if (currentURI) {
00543             PRBool equals;
00544             if (NS_SUCCEEDED(currentURI->Equals(aURI, &equals)) && equals) {
00545                 LOG(("rejected: URL is already being prefetched\n"));
00546                 return NS_ERROR_ABORT;
00547             }
00548         }
00549     }
00550 
00551     //
00552     // cancel if already on the prefetch queue
00553     //
00554     nsPrefetchNode *node = mQueueHead;
00555     for (; node; node = node->mNext) {
00556         PRBool equals;
00557         if (NS_SUCCEEDED(node->mURI->Equals(aURI, &equals)) && equals) {
00558             LOG(("rejected: URL is already on prefetch queue\n"));
00559             return NS_ERROR_ABORT;
00560         }
00561     }
00562 
00563     return EnqueueURI(aURI, aReferrerURI);
00564 }
00565 
00566 //-----------------------------------------------------------------------------
00567 // nsPrefetchService::nsIWebProgressListener
00568 //-----------------------------------------------------------------------------
00569 
00570 NS_IMETHODIMP
00571 nsPrefetchService::OnProgressChange(nsIWebProgress *aProgress,
00572                                   nsIRequest *aRequest, 
00573                                   PRInt32 curSelfProgress, 
00574                                   PRInt32 maxSelfProgress, 
00575                                   PRInt32 curTotalProgress, 
00576                                   PRInt32 maxTotalProgress)
00577 {
00578     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
00579     return NS_OK;
00580 }
00581 
00582 NS_IMETHODIMP 
00583 nsPrefetchService::OnStateChange(nsIWebProgress* aWebProgress, 
00584                                  nsIRequest *aRequest, 
00585                                  PRUint32 progressStateFlags, 
00586                                  nsresult aStatus)
00587 {
00588     if (progressStateFlags & STATE_IS_DOCUMENT) {
00589         if (progressStateFlags & STATE_STOP)
00590             StartPrefetching();
00591         else if (progressStateFlags & STATE_START)
00592             StopPrefetching();
00593     }
00594             
00595     return NS_OK;
00596 }
00597 
00598 
00599 NS_IMETHODIMP
00600 nsPrefetchService::OnLocationChange(nsIWebProgress* aWebProgress,
00601                                     nsIRequest* aRequest,
00602                                     nsIURI *location)
00603 {
00604     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
00605     return NS_OK;
00606 }
00607 
00608 NS_IMETHODIMP 
00609 nsPrefetchService::OnStatusChange(nsIWebProgress* aWebProgress,
00610                                   nsIRequest* aRequest,
00611                                   nsresult aStatus,
00612                                   const PRUnichar* aMessage)
00613 {
00614     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
00615     return NS_OK;
00616 }
00617 
00618 NS_IMETHODIMP 
00619 nsPrefetchService::OnSecurityChange(nsIWebProgress *aWebProgress, 
00620                                     nsIRequest *aRequest, 
00621                                     PRUint32 state)
00622 {
00623     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
00624     return NS_OK;
00625 }
00626 
00627 //-----------------------------------------------------------------------------
00628 // nsPrefetchService::nsIObserver
00629 //-----------------------------------------------------------------------------
00630 
00631 NS_IMETHODIMP
00632 nsPrefetchService::Observe(nsISupports     *aSubject,
00633                            const char      *aTopic,
00634                            const PRUnichar *aData)
00635 {
00636     LOG(("nsPrefetchService::Observe [topic=%s]\n", aTopic));
00637 
00638     if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
00639         StopPrefetching();
00640         mDisabled = PR_TRUE;
00641     }
00642     else if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
00643         nsCOMPtr<nsIPrefBranch> prefs(do_QueryInterface(aSubject));
00644         PRBool enabled;
00645         nsresult rv = prefs->GetBoolPref(PREFETCH_PREF, &enabled);
00646         if (NS_SUCCEEDED(rv) && enabled) {
00647             if (mDisabled) {
00648                 LOG(("enabling prefetching\n"));
00649                 mDisabled = PR_FALSE;
00650                 AddProgressListener();
00651             }
00652         } 
00653         else {
00654             if (!mDisabled) {
00655                 LOG(("disabling prefetching\n"));
00656                 StopPrefetching();
00657                 mDisabled = PR_TRUE;
00658                 RemoveProgressListener();
00659             }
00660         }
00661     }
00662 
00663     return NS_OK;
00664 }
00665 
00666 // vim: ts=4 sw=4 expandtab