1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is Mozilla.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 2002
19 * the Initial Developer. All Rights Reserved.
22 * Darin Fisher <darin@netscape.com> (original author)
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsPrefetchService.h"
39 #include "nsICacheSession.h"
40 #include "nsICacheService.h"
41 #include "nsIServiceManager.h"
42 #include "nsICategoryManager.h"
43 #include "nsIObserverService.h"
44 #include "nsIPrefService.h"
45 #include "nsIPrefBranch2.h"
46 #include "nsIDocCharset.h"
47 #include "nsIWebProgress.h"
48 #include "nsCURILoader.h"
49 #include "nsICachingChannel.h"
50 #include "nsICacheVisitor.h"
51 #include "nsIHttpChannel.h"
53 #include "nsISimpleEnumerator.h"
54 #include "nsNetUtil.h"
56 #include "nsXPIDLString.h"
57 #include "nsReadableUtils.h"
58 #include "nsStreamUtils.h"
59 #include "nsAutoPtr.h"
64 #if defined(PR_LOGGING)
66 // To enable logging (see prlog.h for full details):
68 // set NSPR_LOG_MODULES=nsPrefetch:5
69 // set NSPR_LOG_FILE=prefetch.log
71 // this enables PR_LOG_ALWAYS level information and places all output in
74 static PRLogModuleInfo
*gPrefetchLog
;
76 #define LOG(args) PR_LOG(gPrefetchLog, 4, args)
77 #define LOG_ENABLED() PR_LOG_TEST(gPrefetchLog, 4)
79 #define PREFETCH_PREF "network.prefetch-next"
81 //-----------------------------------------------------------------------------
83 //-----------------------------------------------------------------------------
85 static inline PRUint32
86 PRTimeToSeconds(PRTime t_usec
)
90 LL_I2L(usec_per_sec
, PR_USEC_PER_SEC
);
91 LL_DIV(t_usec
, t_usec
, usec_per_sec
);
92 LL_L2I(t_sec
, t_usec
);
96 #define NowInSeconds() PRTimeToSeconds(PR_Now())
98 //-----------------------------------------------------------------------------
99 // nsPrefetchQueueEnumerator
100 //-----------------------------------------------------------------------------
101 class nsPrefetchQueueEnumerator
: public nsISimpleEnumerator
105 NS_DECL_NSISIMPLEENUMERATOR
106 nsPrefetchQueueEnumerator(nsPrefetchService
*aService
);
107 ~nsPrefetchQueueEnumerator();
112 nsRefPtr
<nsPrefetchService
> mService
;
113 nsRefPtr
<nsPrefetchNode
> mCurrent
;
117 //-----------------------------------------------------------------------------
118 // nsPrefetchQueueEnumerator <public>
119 //-----------------------------------------------------------------------------
120 nsPrefetchQueueEnumerator::nsPrefetchQueueEnumerator(nsPrefetchService
*aService
)
127 nsPrefetchQueueEnumerator::~nsPrefetchQueueEnumerator()
131 //-----------------------------------------------------------------------------
132 // nsPrefetchQueueEnumerator::nsISimpleEnumerator
133 //-----------------------------------------------------------------------------
135 nsPrefetchQueueEnumerator::HasMoreElements(PRBool
*aHasMore
)
137 *aHasMore
= (mCurrent
!= nsnull
);
142 nsPrefetchQueueEnumerator::GetNext(nsISupports
**aItem
)
144 if (!mCurrent
) return NS_ERROR_FAILURE
;
146 NS_ADDREF(*aItem
= static_cast<nsIDOMLoadStatus
*>(mCurrent
.get()));
153 //-----------------------------------------------------------------------------
154 // nsPrefetchQueueEnumerator <private>
155 //-----------------------------------------------------------------------------
158 nsPrefetchQueueEnumerator::Increment()
162 // If the service is currently serving a request, it won't be
163 // in the pending queue, so we return it first. If it isn't,
164 // we'll just start with the pending queue.
166 mCurrent
= mService
->GetCurrentNode();
168 mCurrent
= mService
->GetQueueHead();
171 if (mCurrent
== mService
->GetCurrentNode()) {
172 // If we just returned the node being processed by the service,
173 // start with the pending queue
174 mCurrent
= mService
->GetQueueHead();
177 // Otherwise just advance to the next item in the queue
178 mCurrent
= mCurrent
->mNext
;
184 //-----------------------------------------------------------------------------
185 // nsPrefetchQueueEnumerator::nsISupports
186 //-----------------------------------------------------------------------------
188 NS_IMPL_ISUPPORTS1(nsPrefetchQueueEnumerator
, nsISimpleEnumerator
)
190 //-----------------------------------------------------------------------------
191 // nsPrefetchNode <public>
192 //-----------------------------------------------------------------------------
194 nsPrefetchNode::nsPrefetchNode(nsPrefetchService
*aService
,
196 nsIURI
*aReferrerURI
,
200 , mReferrerURI(aReferrerURI
)
203 , mState(nsIDOMLoadStatus::UNINITIALIZED
)
206 mSource
= do_GetWeakReference(aSource
);
210 nsPrefetchNode::OpenChannel()
212 nsresult rv
= NS_NewChannel(getter_AddRefs(mChannel
),
214 nsnull
, nsnull
, this,
215 nsIRequest::LOAD_BACKGROUND
|
216 nsICachingChannel::LOAD_ONLY_IF_MODIFIED
);
217 NS_ENSURE_SUCCESS(rv
, rv
);
219 // configure HTTP specific stuff
220 nsCOMPtr
<nsIHttpChannel
> httpChannel
=
221 do_QueryInterface(mChannel
);
223 httpChannel
->SetReferrer(mReferrerURI
);
224 httpChannel
->SetRequestHeader(
225 NS_LITERAL_CSTRING("X-Moz"),
226 NS_LITERAL_CSTRING("prefetch"),
230 rv
= mChannel
->AsyncOpen(this, nsnull
);
231 NS_ENSURE_SUCCESS(rv
, rv
);
233 mState
= nsIDOMLoadStatus::REQUESTED
;
239 nsPrefetchNode::CancelChannel(nsresult error
)
241 mChannel
->Cancel(error
);
244 mState
= nsIDOMLoadStatus::UNINITIALIZED
;
249 //-----------------------------------------------------------------------------
250 // nsPrefetchNode::nsISupports
251 //-----------------------------------------------------------------------------
253 NS_IMPL_ISUPPORTS5(nsPrefetchNode
,
257 nsIInterfaceRequestor
,
260 //-----------------------------------------------------------------------------
261 // nsPrefetchNode::nsIStreamListener
262 //-----------------------------------------------------------------------------
265 nsPrefetchNode::OnStartRequest(nsIRequest
*aRequest
,
266 nsISupports
*aContext
)
270 nsCOMPtr
<nsICachingChannel
> cachingChannel
=
271 do_QueryInterface(aRequest
, &rv
);
272 if (NS_FAILED(rv
)) return rv
;
274 // no need to prefetch a document that is already in the cache
276 if (NS_SUCCEEDED(cachingChannel
->IsFromCache(&fromCache
)) &&
278 LOG(("document is already in the cache; canceling prefetch\n"));
279 return NS_BINDING_ABORTED
;
283 // no need to prefetch a document that must be requested fresh each
286 nsCOMPtr
<nsISupports
> cacheToken
;
287 cachingChannel
->GetCacheToken(getter_AddRefs(cacheToken
));
289 return NS_ERROR_ABORT
; // bail, no cache entry
291 nsCOMPtr
<nsICacheEntryInfo
> entryInfo
=
292 do_QueryInterface(cacheToken
, &rv
);
293 if (NS_FAILED(rv
)) return rv
;
296 if (NS_SUCCEEDED(entryInfo
->GetExpirationTime(&expTime
))) {
297 if (NowInSeconds() >= expTime
) {
298 LOG(("document cannot be reused from cache; "
299 "canceling prefetch\n"));
300 return NS_BINDING_ABORTED
;
304 mState
= nsIDOMLoadStatus::RECEIVING
;
310 nsPrefetchNode::OnDataAvailable(nsIRequest
*aRequest
,
311 nsISupports
*aContext
,
312 nsIInputStream
*aStream
,
316 PRUint32 bytesRead
= 0;
317 aStream
->ReadSegments(NS_DiscardSegment
, nsnull
, aCount
, &bytesRead
);
318 mBytesRead
+= bytesRead
;
319 LOG(("prefetched %u bytes [offset=%u]\n", bytesRead
, aOffset
));
325 nsPrefetchNode::OnStopRequest(nsIRequest
*aRequest
,
326 nsISupports
*aContext
,
329 LOG(("done prefetching [status=%x]\n", aStatus
));
331 mState
= nsIDOMLoadStatus::LOADED
;
333 if (mBytesRead
== 0 && aStatus
== NS_OK
) {
334 // we didn't need to read (because LOAD_ONLY_IF_MODIFIED was
335 // specified), but the object should report loadedSize as if it
337 mChannel
->GetContentLength(&mBytesRead
);
340 mService
->NotifyLoadCompleted(this);
341 mService
->ProcessNextURI();
345 //-----------------------------------------------------------------------------
346 // nsPrefetchNode::nsIInterfaceRequestor
347 //-----------------------------------------------------------------------------
350 nsPrefetchNode::GetInterface(const nsIID
&aIID
, void **aResult
)
352 if (aIID
.Equals(NS_GET_IID(nsIChannelEventSink
))) {
354 *aResult
= static_cast<nsIChannelEventSink
*>(this);
358 return NS_ERROR_NO_INTERFACE
;
361 //-----------------------------------------------------------------------------
362 // nsPrefetchNode::nsIChannelEventSink
363 //-----------------------------------------------------------------------------
366 nsPrefetchNode::OnChannelRedirect(nsIChannel
*aOldChannel
,
367 nsIChannel
*aNewChannel
,
370 nsCOMPtr
<nsIURI
> newURI
;
371 nsresult rv
= aNewChannel
->GetURI(getter_AddRefs(newURI
));
375 nsCOMPtr
<nsICachingChannel
> oldCachingChannel
=
376 do_QueryInterface(aOldChannel
);
379 rv
= newURI
->SchemeIs("http", &match
);
380 if (NS_FAILED(rv
) || !match
) {
381 rv
= newURI
->SchemeIs("https", &match
);
382 if (NS_FAILED(rv
) || !match
) {
383 LOG(("rejected: URL is not of type http/https\n"));
384 return NS_ERROR_ABORT
;
388 // HTTP request headers are not automatically forwarded to the new channel.
389 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aNewChannel
);
390 NS_ENSURE_STATE(httpChannel
);
392 httpChannel
->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
393 NS_LITERAL_CSTRING("prefetch"),
396 mChannel
= aNewChannel
;
402 //-----------------------------------------------------------------------------
403 // nsPrefetchService <public>
404 //-----------------------------------------------------------------------------
406 nsPrefetchService::nsPrefetchService()
410 , mHaveProcessed(PR_FALSE
)
415 nsPrefetchService::~nsPrefetchService()
417 // cannot reach destructor if prefetch in progress (listener owns reference
423 nsPrefetchService::Init()
425 #if defined(PR_LOGGING)
427 gPrefetchLog
= PR_NewLogModule("nsPrefetch");
432 // read prefs and hook up pref observer
433 nsCOMPtr
<nsIPrefBranch2
> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
));
434 if (NS_SUCCEEDED(rv
)) {
436 rv
= prefs
->GetBoolPref(PREFETCH_PREF
, &enabled
);
437 if (NS_SUCCEEDED(rv
) && enabled
)
438 mDisabled
= PR_FALSE
;
440 prefs
->AddObserver(PREFETCH_PREF
, this, PR_TRUE
);
443 // Observe xpcom-shutdown event
444 nsCOMPtr
<nsIObserverService
> observerServ(
445 do_GetService("@mozilla.org/observer-service;1", &rv
));
446 if (NS_FAILED(rv
)) return rv
;
448 rv
= observerServ
->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, PR_TRUE
);
449 if (NS_FAILED(rv
)) return rv
;
452 AddProgressListener();
458 nsPrefetchService::ProcessNextURI()
461 nsCOMPtr
<nsIURI
> uri
, referrer
;
463 mCurrentNode
= nsnull
;
466 rv
= DequeueNode(getter_AddRefs(mCurrentNode
));
468 if (NS_FAILED(rv
)) break;
470 #if defined(PR_LOGGING)
473 mCurrentNode
->mURI
->GetSpec(spec
);
474 LOG(("ProcessNextURI [%s]\n", spec
.get()));
479 // if opening the channel fails, then just skip to the next uri
481 rv
= mCurrentNode
->OpenChannel();
483 while (NS_FAILED(rv
));
487 nsPrefetchService::NotifyLoadRequested(nsPrefetchNode
*node
)
491 nsCOMPtr
<nsIObserverService
> observerService
=
492 do_GetService("@mozilla.org/observer-service;1", &rv
);
493 if (NS_FAILED(rv
)) return;
495 observerService
->NotifyObservers(static_cast<nsIDOMLoadStatus
*>(node
),
496 "prefetch-load-requested", nsnull
);
500 nsPrefetchService::NotifyLoadCompleted(nsPrefetchNode
*node
)
504 nsCOMPtr
<nsIObserverService
> observerService
=
505 do_GetService("@mozilla.org/observer-service;1", &rv
);
506 if (NS_FAILED(rv
)) return;
508 observerService
->NotifyObservers(static_cast<nsIDOMLoadStatus
*>(node
),
509 "prefetch-load-completed", nsnull
);
512 //-----------------------------------------------------------------------------
513 // nsPrefetchService <private>
514 //-----------------------------------------------------------------------------
517 nsPrefetchService::AddProgressListener()
519 // Register as an observer for the document loader
520 nsCOMPtr
<nsIWebProgress
> progress
=
521 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID
);
523 progress
->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT
);
527 nsPrefetchService::RemoveProgressListener()
529 // Register as an observer for the document loader
530 nsCOMPtr
<nsIWebProgress
> progress
=
531 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID
);
533 progress
->RemoveProgressListener(this);
537 nsPrefetchService::EnqueueNode(nsPrefetchNode
*aNode
)
546 mQueueTail
->mNext
= aNode
;
554 nsPrefetchService::EnqueueURI(nsIURI
*aURI
,
555 nsIURI
*aReferrerURI
,
557 nsPrefetchNode
**aNode
)
559 nsPrefetchNode
*node
= new nsPrefetchNode(this, aURI
, aReferrerURI
,
562 return NS_ERROR_OUT_OF_MEMORY
;
564 NS_ADDREF(*aNode
= node
);
566 return EnqueueNode(node
);
570 nsPrefetchService::DequeueNode(nsPrefetchNode
**node
)
573 return NS_ERROR_NOT_AVAILABLE
;
575 // give the ref to the caller
577 mQueueHead
= mQueueHead
->mNext
;
578 (*node
)->mNext
= nsnull
;
587 nsPrefetchService::EmptyQueue()
589 nsPrefetchNode
*prev
= 0;
590 nsPrefetchNode
*node
= mQueueHead
;
593 nsPrefetchNode
*next
= node
->mNext
;
605 nsPrefetchService::StartPrefetching()
608 // at initialization time we might miss the first DOCUMENT START
609 // notification, so we have to be careful to avoid letting our
610 // stop count go negative.
615 LOG(("StartPrefetching [stopcount=%d]\n", mStopCount
));
617 // only start prefetching after we've received enough DOCUMENT
618 // STOP notifications. we do this inorder to defer prefetching
619 // until after all sub-frames have finished loading.
620 if (mStopCount
== 0 && !mCurrentNode
) {
621 mHaveProcessed
= PR_TRUE
;
627 nsPrefetchService::StopPrefetching()
631 LOG(("StopPrefetching [stopcount=%d]\n", mStopCount
));
633 // only kill the prefetch queue if we've actually started prefetching.
637 mCurrentNode
->CancelChannel(NS_BINDING_ABORTED
);
638 mCurrentNode
= nsnull
;
642 //-----------------------------------------------------------------------------
643 // nsPrefetchService::nsISupports
644 //-----------------------------------------------------------------------------
646 NS_IMPL_ISUPPORTS4(nsPrefetchService
,
648 nsIWebProgressListener
,
650 nsISupportsWeakReference
)
652 //-----------------------------------------------------------------------------
653 // nsPrefetchService::nsIPrefetchService
654 //-----------------------------------------------------------------------------
657 nsPrefetchService::Prefetch(nsIURI
*aURI
,
658 nsIURI
*aReferrerURI
,
664 NS_ENSURE_ARG_POINTER(aURI
);
665 NS_ENSURE_ARG_POINTER(aReferrerURI
);
667 #if defined(PR_LOGGING)
671 LOG(("PrefetchURI [%s]\n", spec
.get()));
676 LOG(("rejected: prefetch service is disabled\n"));
677 return NS_ERROR_ABORT
;
681 // XXX we should really be asking the protocol handler if it supports
682 // caching, so we can determine if there is any value to prefetching.
683 // for now, we'll only prefetch http links since we know that's the
684 // most common case. ignore https links since https content only goes
685 // into the memory cache.
687 // XXX we might want to either leverage nsIProtocolHandler::protocolFlags
688 // or possibly nsIRequest::loadFlags to determine if this URI should be
692 rv
= aURI
->SchemeIs("http", &match
);
693 if (NS_FAILED(rv
) || !match
) {
694 rv
= aURI
->SchemeIs("https", &match
);
695 if (NS_FAILED(rv
) || !match
) {
696 LOG(("rejected: URL is not of type http/https\n"));
697 return NS_ERROR_ABORT
;
702 // the referrer URI must be http:
704 rv
= aReferrerURI
->SchemeIs("http", &match
);
705 if (NS_FAILED(rv
) || !match
) {
706 rv
= aReferrerURI
->SchemeIs("https", &match
);
707 if (NS_FAILED(rv
) || !match
) {
708 LOG(("rejected: referrer URL is neither http nor https\n"));
709 return NS_ERROR_ABORT
;
713 // skip URLs that contain query strings, except URLs for which prefetching
714 // has been explicitly requested.
716 nsCOMPtr
<nsIURL
> url(do_QueryInterface(aURI
, &rv
));
717 if (NS_FAILED(rv
)) return rv
;
719 rv
= url
->GetQuery(query
);
720 if (NS_FAILED(rv
) || !query
.IsEmpty()) {
721 LOG(("rejected: URL has a query string\n"));
722 return NS_ERROR_ABORT
;
727 // cancel if being prefetched
731 if (NS_SUCCEEDED(mCurrentNode
->mURI
->Equals(aURI
, &equals
)) && equals
) {
732 LOG(("rejected: URL is already being prefetched\n"));
733 return NS_ERROR_ABORT
;
738 // cancel if already on the prefetch queue
740 nsPrefetchNode
*node
= mQueueHead
;
741 for (; node
; node
= node
->mNext
) {
743 if (NS_SUCCEEDED(node
->mURI
->Equals(aURI
, &equals
)) && equals
) {
744 LOG(("rejected: URL is already on prefetch queue\n"));
745 return NS_ERROR_ABORT
;
749 nsRefPtr
<nsPrefetchNode
> enqueuedNode
;
750 rv
= EnqueueURI(aURI
, aReferrerURI
, aSource
,
751 getter_AddRefs(enqueuedNode
));
752 NS_ENSURE_SUCCESS(rv
, rv
);
754 NotifyLoadRequested(enqueuedNode
);
756 // if there are no pages loading, kick off the request immediately
757 if (mStopCount
== 0 && mHaveProcessed
)
764 nsPrefetchService::PrefetchURI(nsIURI
*aURI
,
765 nsIURI
*aReferrerURI
,
769 return Prefetch(aURI
, aReferrerURI
, aSource
, aExplicit
);
773 nsPrefetchService::PrefetchURIForOfflineUse(nsIURI
*aURI
,
774 nsIURI
*aReferrerURI
,
778 return NS_ERROR_NOT_IMPLEMENTED
;
782 nsPrefetchService::EnumerateQueue(PRBool aIncludeNormalItems
,
783 PRBool aIncludeOfflineItems
,
784 nsISimpleEnumerator
**aEnumerator
)
786 NS_ENSURE_TRUE(aIncludeNormalItems
&& !aIncludeOfflineItems
,
787 NS_ERROR_NOT_IMPLEMENTED
);
789 *aEnumerator
= new nsPrefetchQueueEnumerator(this);
790 if (!*aEnumerator
) return NS_ERROR_OUT_OF_MEMORY
;
792 NS_ADDREF(*aEnumerator
);
797 //-----------------------------------------------------------------------------
798 // nsPrefetchNode::nsIDOMLoadStatus
799 //-----------------------------------------------------------------------------
801 nsPrefetchNode::GetSource(nsIDOMNode
**aSource
)
804 nsCOMPtr
<nsIDOMNode
> source
= do_QueryReferent(mSource
);
806 source
.swap(*aSource
);
812 nsPrefetchNode::GetUri(nsAString
&aURI
)
815 nsresult rv
= mURI
->GetSpec(spec
);
816 NS_ENSURE_SUCCESS(rv
, rv
);
818 CopyUTF8toUTF16(spec
, aURI
);
823 nsPrefetchNode::GetTotalSize(PRInt32
*aTotalSize
)
826 return mChannel
->GetContentLength(aTotalSize
);
834 nsPrefetchNode::GetLoadedSize(PRInt32
*aLoadedSize
)
836 *aLoadedSize
= mBytesRead
;
841 nsPrefetchNode::GetReadyState(PRUint16
*aReadyState
)
843 *aReadyState
= mState
;
848 nsPrefetchNode::GetStatus(PRUint16
*aStatus
)
856 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(mChannel
, &rv
);
857 NS_ENSURE_SUCCESS(rv
, rv
);
860 rv
= httpChannel
->GetResponseStatus(&httpStatus
);
861 if (rv
== NS_ERROR_NOT_AVAILABLE
) {
862 // Someone's calling this before we got a response... Check our
863 // ReadyState. If we're at RECEIVING or LOADED, then this means the
864 // connection errored before we got any data; return a somewhat
865 // sensible error code in that case.
866 if (mState
>= nsIDOMLoadStatus::RECEIVING
) {
867 *aStatus
= NS_ERROR_NOT_AVAILABLE
;
875 NS_ENSURE_SUCCESS(rv
, rv
);
876 *aStatus
= PRUint16(httpStatus
);
880 //-----------------------------------------------------------------------------
881 // nsPrefetchService::nsIWebProgressListener
882 //-----------------------------------------------------------------------------
885 nsPrefetchService::OnProgressChange(nsIWebProgress
*aProgress
,
886 nsIRequest
*aRequest
,
887 PRInt32 curSelfProgress
,
888 PRInt32 maxSelfProgress
,
889 PRInt32 curTotalProgress
,
890 PRInt32 maxTotalProgress
)
892 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
897 nsPrefetchService::OnStateChange(nsIWebProgress
* aWebProgress
,
898 nsIRequest
*aRequest
,
899 PRUint32 progressStateFlags
,
902 if (progressStateFlags
& STATE_IS_DOCUMENT
) {
903 if (progressStateFlags
& STATE_STOP
)
905 else if (progressStateFlags
& STATE_START
)
914 nsPrefetchService::OnLocationChange(nsIWebProgress
* aWebProgress
,
915 nsIRequest
* aRequest
,
918 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
923 nsPrefetchService::OnStatusChange(nsIWebProgress
* aWebProgress
,
924 nsIRequest
* aRequest
,
926 const PRUnichar
* aMessage
)
928 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
933 nsPrefetchService::OnSecurityChange(nsIWebProgress
*aWebProgress
,
934 nsIRequest
*aRequest
,
937 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
941 //-----------------------------------------------------------------------------
942 // nsPrefetchService::nsIObserver
943 //-----------------------------------------------------------------------------
946 nsPrefetchService::Observe(nsISupports
*aSubject
,
948 const PRUnichar
*aData
)
950 LOG(("nsPrefetchService::Observe [topic=%s]\n", aTopic
));
952 if (!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
)) {
956 else if (!strcmp(aTopic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
)) {
957 nsCOMPtr
<nsIPrefBranch
> prefs(do_QueryInterface(aSubject
));
959 nsresult rv
= prefs
->GetBoolPref(PREFETCH_PREF
, &enabled
);
960 if (NS_SUCCEEDED(rv
) && enabled
) {
962 LOG(("enabling prefetching\n"));
963 mDisabled
= PR_FALSE
;
964 AddProgressListener();
969 LOG(("disabling prefetching\n"));
972 RemoveProgressListener();
980 // vim: ts=4 sw=4 expandtab