Bumping manifests a=b2g-bump
[gecko.git] / uriloader / prefetch / nsPrefetchService.cpp
blob71d04d8dbcf1b2f1f7ee583dbaba8b1cab414a12
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsPrefetchService.h"
6 #include "nsICacheEntry.h"
7 #include "nsIServiceManager.h"
8 #include "nsICategoryManager.h"
9 #include "nsIObserverService.h"
10 #include "nsIWebProgress.h"
11 #include "nsCURILoader.h"
12 #include "nsICachingChannel.h"
13 #include "nsIHttpChannel.h"
14 #include "nsIURL.h"
15 #include "nsISimpleEnumerator.h"
16 #include "nsNetUtil.h"
17 #include "nsString.h"
18 #include "nsXPIDLString.h"
19 #include "nsReadableUtils.h"
20 #include "nsStreamUtils.h"
21 #include "nsAutoPtr.h"
22 #include "prtime.h"
23 #include "prlog.h"
24 #include "plstr.h"
25 #include "nsIAsyncVerifyRedirectCallback.h"
26 #include "mozilla/Preferences.h"
27 #include "mozilla/Attributes.h"
28 #include "nsIDOMNode.h"
29 #include "nsINode.h"
30 #include "nsIDocument.h"
31 #include "nsContentUtils.h"
33 using namespace mozilla;
35 #if defined(PR_LOGGING)
37 // To enable logging (see prlog.h for full details):
39 // set NSPR_LOG_MODULES=nsPrefetch:5
40 // set NSPR_LOG_FILE=prefetch.log
42 // this enables PR_LOG_ALWAYS level information and places all output in
43 // the file http.log
45 static PRLogModuleInfo *gPrefetchLog;
46 #endif
48 #undef LOG
49 #define LOG(args) PR_LOG(gPrefetchLog, 4, args)
51 #undef LOG_ENABLED
52 #define LOG_ENABLED() PR_LOG_TEST(gPrefetchLog, 4)
54 #define PREFETCH_PREF "network.prefetch-next"
56 //-----------------------------------------------------------------------------
57 // helpers
58 //-----------------------------------------------------------------------------
60 static inline uint32_t
61 PRTimeToSeconds(PRTime t_usec)
63 PRTime usec_per_sec = PR_USEC_PER_SEC;
64 return uint32_t(t_usec /= usec_per_sec);
67 #define NowInSeconds() PRTimeToSeconds(PR_Now())
69 //-----------------------------------------------------------------------------
70 // nsPrefetchQueueEnumerator
71 //-----------------------------------------------------------------------------
72 class nsPrefetchQueueEnumerator MOZ_FINAL : public nsISimpleEnumerator
74 public:
75 NS_DECL_ISUPPORTS
76 NS_DECL_NSISIMPLEENUMERATOR
77 explicit nsPrefetchQueueEnumerator(nsPrefetchService *aService);
79 private:
80 ~nsPrefetchQueueEnumerator();
82 void Increment();
84 nsRefPtr<nsPrefetchService> mService;
85 nsRefPtr<nsPrefetchNode> mCurrent;
86 bool mStarted;
89 //-----------------------------------------------------------------------------
90 // nsPrefetchQueueEnumerator <public>
91 //-----------------------------------------------------------------------------
92 nsPrefetchQueueEnumerator::nsPrefetchQueueEnumerator(nsPrefetchService *aService)
93 : mService(aService)
94 , mStarted(false)
96 Increment();
99 nsPrefetchQueueEnumerator::~nsPrefetchQueueEnumerator()
103 //-----------------------------------------------------------------------------
104 // nsPrefetchQueueEnumerator::nsISimpleEnumerator
105 //-----------------------------------------------------------------------------
106 NS_IMETHODIMP
107 nsPrefetchQueueEnumerator::HasMoreElements(bool *aHasMore)
109 *aHasMore = (mCurrent != nullptr);
110 return NS_OK;
113 NS_IMETHODIMP
114 nsPrefetchQueueEnumerator::GetNext(nsISupports **aItem)
116 if (!mCurrent) return NS_ERROR_FAILURE;
118 NS_ADDREF(*aItem = static_cast<nsIStreamListener*>(mCurrent.get()));
120 Increment();
122 return NS_OK;
125 //-----------------------------------------------------------------------------
126 // nsPrefetchQueueEnumerator <private>
127 //-----------------------------------------------------------------------------
129 void
130 nsPrefetchQueueEnumerator::Increment()
132 if (!mStarted) {
133 // If the service is currently serving a request, it won't be in
134 // the pending queue, so we return it first. If it isn't, we'll
135 // just start with the pending queue.
136 mStarted = true;
137 mCurrent = mService->GetCurrentNode();
138 if (!mCurrent)
139 mCurrent = mService->GetQueueHead();
140 return;
143 if (mCurrent) {
144 if (mCurrent == mService->GetCurrentNode()) {
145 // If we just returned the node being processed by the service,
146 // start with the pending queue
147 mCurrent = mService->GetQueueHead();
149 else {
150 // Otherwise just advance to the next item in the queue
151 mCurrent = mCurrent->mNext;
156 //-----------------------------------------------------------------------------
157 // nsPrefetchQueueEnumerator::nsISupports
158 //-----------------------------------------------------------------------------
160 NS_IMPL_ISUPPORTS(nsPrefetchQueueEnumerator, nsISimpleEnumerator)
162 //-----------------------------------------------------------------------------
163 // nsPrefetchNode <public>
164 //-----------------------------------------------------------------------------
166 nsPrefetchNode::nsPrefetchNode(nsPrefetchService *aService,
167 nsIURI *aURI,
168 nsIURI *aReferrerURI,
169 nsIDOMNode *aSource)
170 : mNext(nullptr)
171 , mURI(aURI)
172 , mReferrerURI(aReferrerURI)
173 , mService(aService)
174 , mChannel(nullptr)
175 , mBytesRead(0)
177 mSource = do_GetWeakReference(aSource);
180 nsresult
181 nsPrefetchNode::OpenChannel()
183 nsCOMPtr<nsINode> source = do_QueryReferent(mSource);
184 if (!source) {
185 // Don't attempt to prefetch if we don't have a source node
186 // (which should never happen).
187 return NS_ERROR_FAILURE;
189 nsCOMPtr<nsILoadGroup> loadGroup = source->OwnerDoc()->GetDocumentLoadGroup();
190 nsresult rv = NS_NewChannel(getter_AddRefs(mChannel),
191 mURI,
192 nsContentUtils::GetSystemPrincipal(),
193 nsILoadInfo::SEC_NORMAL,
194 nsIContentPolicy::TYPE_OTHER,
195 loadGroup, // aLoadGroup
196 this, // aCallbacks
197 nsIRequest::LOAD_BACKGROUND |
198 nsICachingChannel::LOAD_ONLY_IF_MODIFIED);
200 NS_ENSURE_SUCCESS(rv, rv);
202 // configure HTTP specific stuff
203 nsCOMPtr<nsIHttpChannel> httpChannel =
204 do_QueryInterface(mChannel);
205 if (httpChannel) {
206 httpChannel->SetReferrer(mReferrerURI);
207 httpChannel->SetRequestHeader(
208 NS_LITERAL_CSTRING("X-Moz"),
209 NS_LITERAL_CSTRING("prefetch"),
210 false);
213 rv = mChannel->AsyncOpen(this, nullptr);
214 NS_ENSURE_SUCCESS(rv, rv);
216 return NS_OK;
219 nsresult
220 nsPrefetchNode::CancelChannel(nsresult error)
222 mChannel->Cancel(error);
223 mChannel = nullptr;
225 return NS_OK;
228 //-----------------------------------------------------------------------------
229 // nsPrefetchNode::nsISupports
230 //-----------------------------------------------------------------------------
232 NS_IMPL_ISUPPORTS(nsPrefetchNode,
233 nsIRequestObserver,
234 nsIStreamListener,
235 nsIInterfaceRequestor,
236 nsIChannelEventSink,
237 nsIRedirectResultListener)
239 //-----------------------------------------------------------------------------
240 // nsPrefetchNode::nsIStreamListener
241 //-----------------------------------------------------------------------------
243 NS_IMETHODIMP
244 nsPrefetchNode::OnStartRequest(nsIRequest *aRequest,
245 nsISupports *aContext)
247 nsresult rv;
249 nsCOMPtr<nsICachingChannel> cachingChannel =
250 do_QueryInterface(aRequest, &rv);
251 if (NS_FAILED(rv)) return rv;
253 // no need to prefetch a document that is already in the cache
254 bool fromCache;
255 if (NS_SUCCEEDED(cachingChannel->IsFromCache(&fromCache)) &&
256 fromCache) {
257 LOG(("document is already in the cache; canceling prefetch\n"));
258 return NS_BINDING_ABORTED;
262 // no need to prefetch a document that must be requested fresh each
263 // and every time.
265 nsCOMPtr<nsISupports> cacheToken;
266 cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
267 if (!cacheToken)
268 return NS_ERROR_ABORT; // bail, no cache entry
270 nsCOMPtr<nsICacheEntry> entryInfo =
271 do_QueryInterface(cacheToken, &rv);
272 if (NS_FAILED(rv)) return rv;
274 uint32_t expTime;
275 if (NS_SUCCEEDED(entryInfo->GetExpirationTime(&expTime))) {
276 if (NowInSeconds() >= expTime) {
277 LOG(("document cannot be reused from cache; "
278 "canceling prefetch\n"));
279 return NS_BINDING_ABORTED;
283 return NS_OK;
286 NS_IMETHODIMP
287 nsPrefetchNode::OnDataAvailable(nsIRequest *aRequest,
288 nsISupports *aContext,
289 nsIInputStream *aStream,
290 uint64_t aOffset,
291 uint32_t aCount)
293 uint32_t bytesRead = 0;
294 aStream->ReadSegments(NS_DiscardSegment, nullptr, aCount, &bytesRead);
295 mBytesRead += bytesRead;
296 LOG(("prefetched %u bytes [offset=%llu]\n", bytesRead, aOffset));
297 return NS_OK;
301 NS_IMETHODIMP
302 nsPrefetchNode::OnStopRequest(nsIRequest *aRequest,
303 nsISupports *aContext,
304 nsresult aStatus)
306 LOG(("done prefetching [status=%x]\n", aStatus));
308 if (mBytesRead == 0 && aStatus == NS_OK) {
309 // we didn't need to read (because LOAD_ONLY_IF_MODIFIED was
310 // specified), but the object should report loadedSize as if it
311 // did.
312 mChannel->GetContentLength(&mBytesRead);
315 mService->NotifyLoadCompleted(this);
316 mService->ProcessNextURI();
317 return NS_OK;
320 //-----------------------------------------------------------------------------
321 // nsPrefetchNode::nsIInterfaceRequestor
322 //-----------------------------------------------------------------------------
324 NS_IMETHODIMP
325 nsPrefetchNode::GetInterface(const nsIID &aIID, void **aResult)
327 if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
328 NS_ADDREF_THIS();
329 *aResult = static_cast<nsIChannelEventSink *>(this);
330 return NS_OK;
333 if (aIID.Equals(NS_GET_IID(nsIRedirectResultListener))) {
334 NS_ADDREF_THIS();
335 *aResult = static_cast<nsIRedirectResultListener *>(this);
336 return NS_OK;
339 return NS_ERROR_NO_INTERFACE;
342 //-----------------------------------------------------------------------------
343 // nsPrefetchNode::nsIChannelEventSink
344 //-----------------------------------------------------------------------------
346 NS_IMETHODIMP
347 nsPrefetchNode::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
348 nsIChannel *aNewChannel,
349 uint32_t aFlags,
350 nsIAsyncVerifyRedirectCallback *callback)
352 nsCOMPtr<nsIURI> newURI;
353 nsresult rv = aNewChannel->GetURI(getter_AddRefs(newURI));
354 if (NS_FAILED(rv))
355 return rv;
357 bool match;
358 rv = newURI->SchemeIs("http", &match);
359 if (NS_FAILED(rv) || !match) {
360 rv = newURI->SchemeIs("https", &match);
361 if (NS_FAILED(rv) || !match) {
362 LOG(("rejected: URL is not of type http/https\n"));
363 return NS_ERROR_ABORT;
367 // HTTP request headers are not automatically forwarded to the new channel.
368 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aNewChannel);
369 NS_ENSURE_STATE(httpChannel);
371 httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
372 NS_LITERAL_CSTRING("prefetch"),
373 false);
375 // Assign to mChannel after we get notification about success of the
376 // redirect in OnRedirectResult.
377 mRedirectChannel = aNewChannel;
379 callback->OnRedirectVerifyCallback(NS_OK);
380 return NS_OK;
383 //-----------------------------------------------------------------------------
384 // nsPrefetchNode::nsIRedirectResultListener
385 //-----------------------------------------------------------------------------
387 NS_IMETHODIMP
388 nsPrefetchNode::OnRedirectResult(bool proceeding)
390 if (proceeding && mRedirectChannel)
391 mChannel = mRedirectChannel;
393 mRedirectChannel = nullptr;
395 return NS_OK;
398 //-----------------------------------------------------------------------------
399 // nsPrefetchService <public>
400 //-----------------------------------------------------------------------------
402 nsPrefetchService::nsPrefetchService()
403 : mQueueHead(nullptr)
404 , mQueueTail(nullptr)
405 , mStopCount(0)
406 , mHaveProcessed(false)
407 , mDisabled(true)
411 nsPrefetchService::~nsPrefetchService()
413 Preferences::RemoveObserver(this, PREFETCH_PREF);
414 // cannot reach destructor if prefetch in progress (listener owns reference
415 // to this service)
416 EmptyQueue();
419 nsresult
420 nsPrefetchService::Init()
422 #if defined(PR_LOGGING)
423 if (!gPrefetchLog)
424 gPrefetchLog = PR_NewLogModule("nsPrefetch");
425 #endif
427 nsresult rv;
429 // read prefs and hook up pref observer
430 mDisabled = !Preferences::GetBool(PREFETCH_PREF, !mDisabled);
431 Preferences::AddWeakObserver(this, PREFETCH_PREF);
433 // Observe xpcom-shutdown event
434 nsCOMPtr<nsIObserverService> observerService =
435 mozilla::services::GetObserverService();
436 if (!observerService)
437 return NS_ERROR_FAILURE;
439 rv = observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
440 NS_ENSURE_SUCCESS(rv, rv);
442 if (!mDisabled)
443 AddProgressListener();
445 return NS_OK;
448 void
449 nsPrefetchService::ProcessNextURI()
451 nsresult rv;
452 nsCOMPtr<nsIURI> uri, referrer;
454 mCurrentNode = nullptr;
456 do {
457 rv = DequeueNode(getter_AddRefs(mCurrentNode));
459 if (NS_FAILED(rv)) break;
461 #if defined(PR_LOGGING)
462 if (LOG_ENABLED()) {
463 nsAutoCString spec;
464 mCurrentNode->mURI->GetSpec(spec);
465 LOG(("ProcessNextURI [%s]\n", spec.get()));
467 #endif
470 // if opening the channel fails, then just skip to the next uri
472 nsRefPtr<nsPrefetchNode> node = mCurrentNode;
473 rv = node->OpenChannel();
475 while (NS_FAILED(rv));
478 void
479 nsPrefetchService::NotifyLoadRequested(nsPrefetchNode *node)
481 nsCOMPtr<nsIObserverService> observerService =
482 mozilla::services::GetObserverService();
483 if (!observerService)
484 return;
486 observerService->NotifyObservers(static_cast<nsIStreamListener*>(node),
487 "prefetch-load-requested", nullptr);
490 void
491 nsPrefetchService::NotifyLoadCompleted(nsPrefetchNode *node)
493 nsCOMPtr<nsIObserverService> observerService =
494 mozilla::services::GetObserverService();
495 if (!observerService)
496 return;
498 observerService->NotifyObservers(static_cast<nsIStreamListener*>(node),
499 "prefetch-load-completed", nullptr);
502 //-----------------------------------------------------------------------------
503 // nsPrefetchService <private>
504 //-----------------------------------------------------------------------------
506 void
507 nsPrefetchService::AddProgressListener()
509 // Register as an observer for the document loader
510 nsCOMPtr<nsIWebProgress> progress =
511 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
512 if (progress)
513 progress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
516 void
517 nsPrefetchService::RemoveProgressListener()
519 // Register as an observer for the document loader
520 nsCOMPtr<nsIWebProgress> progress =
521 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
522 if (progress)
523 progress->RemoveProgressListener(this);
526 nsresult
527 nsPrefetchService::EnqueueNode(nsPrefetchNode *aNode)
529 NS_ADDREF(aNode);
531 if (!mQueueTail) {
532 mQueueHead = aNode;
533 mQueueTail = aNode;
535 else {
536 mQueueTail->mNext = aNode;
537 mQueueTail = aNode;
540 return NS_OK;
543 nsresult
544 nsPrefetchService::EnqueueURI(nsIURI *aURI,
545 nsIURI *aReferrerURI,
546 nsIDOMNode *aSource,
547 nsPrefetchNode **aNode)
549 nsPrefetchNode *node = new nsPrefetchNode(this, aURI, aReferrerURI,
550 aSource);
551 if (!node)
552 return NS_ERROR_OUT_OF_MEMORY;
554 NS_ADDREF(*aNode = node);
556 return EnqueueNode(node);
559 nsresult
560 nsPrefetchService::DequeueNode(nsPrefetchNode **node)
562 if (!mQueueHead)
563 return NS_ERROR_NOT_AVAILABLE;
565 // give the ref to the caller
566 *node = mQueueHead;
567 mQueueHead = mQueueHead->mNext;
568 (*node)->mNext = nullptr;
570 if (!mQueueHead)
571 mQueueTail = nullptr;
573 return NS_OK;
576 void
577 nsPrefetchService::EmptyQueue()
579 do {
580 nsRefPtr<nsPrefetchNode> node;
581 DequeueNode(getter_AddRefs(node));
582 } while (mQueueHead);
585 void
586 nsPrefetchService::StartPrefetching()
589 // at initialization time we might miss the first DOCUMENT START
590 // notification, so we have to be careful to avoid letting our
591 // stop count go negative.
593 if (mStopCount > 0)
594 mStopCount--;
596 LOG(("StartPrefetching [stopcount=%d]\n", mStopCount));
598 // only start prefetching after we've received enough DOCUMENT
599 // STOP notifications. we do this inorder to defer prefetching
600 // until after all sub-frames have finished loading.
601 if (mStopCount == 0 && !mCurrentNode) {
602 mHaveProcessed = true;
603 ProcessNextURI();
607 void
608 nsPrefetchService::StopPrefetching()
610 mStopCount++;
612 LOG(("StopPrefetching [stopcount=%d]\n", mStopCount));
614 // only kill the prefetch queue if we've actually started prefetching.
615 if (!mCurrentNode)
616 return;
618 mCurrentNode->CancelChannel(NS_BINDING_ABORTED);
619 mCurrentNode = nullptr;
620 EmptyQueue();
623 //-----------------------------------------------------------------------------
624 // nsPrefetchService::nsISupports
625 //-----------------------------------------------------------------------------
627 NS_IMPL_ISUPPORTS(nsPrefetchService,
628 nsIPrefetchService,
629 nsIWebProgressListener,
630 nsIObserver,
631 nsISupportsWeakReference)
633 //-----------------------------------------------------------------------------
634 // nsPrefetchService::nsIPrefetchService
635 //-----------------------------------------------------------------------------
637 nsresult
638 nsPrefetchService::Prefetch(nsIURI *aURI,
639 nsIURI *aReferrerURI,
640 nsIDOMNode *aSource,
641 bool aExplicit)
643 nsresult rv;
645 NS_ENSURE_ARG_POINTER(aURI);
646 NS_ENSURE_ARG_POINTER(aReferrerURI);
648 #if defined(PR_LOGGING)
649 if (LOG_ENABLED()) {
650 nsAutoCString spec;
651 aURI->GetSpec(spec);
652 LOG(("PrefetchURI [%s]\n", spec.get()));
654 #endif
656 if (mDisabled) {
657 LOG(("rejected: prefetch service is disabled\n"));
658 return NS_ERROR_ABORT;
662 // XXX we should really be asking the protocol handler if it supports
663 // caching, so we can determine if there is any value to prefetching.
664 // for now, we'll only prefetch http links since we know that's the
665 // most common case. ignore https links since https content only goes
666 // into the memory cache.
668 // XXX we might want to either leverage nsIProtocolHandler::protocolFlags
669 // or possibly nsIRequest::loadFlags to determine if this URI should be
670 // prefetched.
672 bool match;
673 rv = aURI->SchemeIs("http", &match);
674 if (NS_FAILED(rv) || !match) {
675 rv = aURI->SchemeIs("https", &match);
676 if (NS_FAILED(rv) || !match) {
677 LOG(("rejected: URL is not of type http/https\n"));
678 return NS_ERROR_ABORT;
683 // the referrer URI must be http:
685 rv = aReferrerURI->SchemeIs("http", &match);
686 if (NS_FAILED(rv) || !match) {
687 rv = aReferrerURI->SchemeIs("https", &match);
688 if (NS_FAILED(rv) || !match) {
689 LOG(("rejected: referrer URL is neither http nor https\n"));
690 return NS_ERROR_ABORT;
694 // skip URLs that contain query strings, except URLs for which prefetching
695 // has been explicitly requested.
696 if (!aExplicit) {
697 nsCOMPtr<nsIURL> url(do_QueryInterface(aURI, &rv));
698 if (NS_FAILED(rv)) return rv;
699 nsAutoCString query;
700 rv = url->GetQuery(query);
701 if (NS_FAILED(rv) || !query.IsEmpty()) {
702 LOG(("rejected: URL has a query string\n"));
703 return NS_ERROR_ABORT;
708 // cancel if being prefetched
710 if (mCurrentNode) {
711 bool equals;
712 if (NS_SUCCEEDED(mCurrentNode->mURI->Equals(aURI, &equals)) && equals) {
713 LOG(("rejected: URL is already being prefetched\n"));
714 return NS_ERROR_ABORT;
719 // cancel if already on the prefetch queue
721 nsPrefetchNode *node = mQueueHead;
722 for (; node; node = node->mNext) {
723 bool equals;
724 if (NS_SUCCEEDED(node->mURI->Equals(aURI, &equals)) && equals) {
725 LOG(("rejected: URL is already on prefetch queue\n"));
726 return NS_ERROR_ABORT;
730 nsRefPtr<nsPrefetchNode> enqueuedNode;
731 rv = EnqueueURI(aURI, aReferrerURI, aSource,
732 getter_AddRefs(enqueuedNode));
733 NS_ENSURE_SUCCESS(rv, rv);
735 NotifyLoadRequested(enqueuedNode);
737 // if there are no pages loading, kick off the request immediately
738 if (mStopCount == 0 && mHaveProcessed)
739 ProcessNextURI();
741 return NS_OK;
744 NS_IMETHODIMP
745 nsPrefetchService::PrefetchURI(nsIURI *aURI,
746 nsIURI *aReferrerURI,
747 nsIDOMNode *aSource,
748 bool aExplicit)
750 return Prefetch(aURI, aReferrerURI, aSource, aExplicit);
753 NS_IMETHODIMP
754 nsPrefetchService::EnumerateQueue(nsISimpleEnumerator **aEnumerator)
756 *aEnumerator = new nsPrefetchQueueEnumerator(this);
757 if (!*aEnumerator) return NS_ERROR_OUT_OF_MEMORY;
759 NS_ADDREF(*aEnumerator);
761 return NS_OK;
764 //-----------------------------------------------------------------------------
765 // nsPrefetchService::nsIWebProgressListener
766 //-----------------------------------------------------------------------------
768 NS_IMETHODIMP
769 nsPrefetchService::OnProgressChange(nsIWebProgress *aProgress,
770 nsIRequest *aRequest,
771 int32_t curSelfProgress,
772 int32_t maxSelfProgress,
773 int32_t curTotalProgress,
774 int32_t maxTotalProgress)
776 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
777 return NS_OK;
780 NS_IMETHODIMP
781 nsPrefetchService::OnStateChange(nsIWebProgress* aWebProgress,
782 nsIRequest *aRequest,
783 uint32_t progressStateFlags,
784 nsresult aStatus)
786 if (progressStateFlags & STATE_IS_DOCUMENT) {
787 if (progressStateFlags & STATE_STOP)
788 StartPrefetching();
789 else if (progressStateFlags & STATE_START)
790 StopPrefetching();
793 return NS_OK;
797 NS_IMETHODIMP
798 nsPrefetchService::OnLocationChange(nsIWebProgress* aWebProgress,
799 nsIRequest* aRequest,
800 nsIURI *location,
801 uint32_t aFlags)
803 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
804 return NS_OK;
807 NS_IMETHODIMP
808 nsPrefetchService::OnStatusChange(nsIWebProgress* aWebProgress,
809 nsIRequest* aRequest,
810 nsresult aStatus,
811 const char16_t* aMessage)
813 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
814 return NS_OK;
817 NS_IMETHODIMP
818 nsPrefetchService::OnSecurityChange(nsIWebProgress *aWebProgress,
819 nsIRequest *aRequest,
820 uint32_t state)
822 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
823 return NS_OK;
826 //-----------------------------------------------------------------------------
827 // nsPrefetchService::nsIObserver
828 //-----------------------------------------------------------------------------
830 NS_IMETHODIMP
831 nsPrefetchService::Observe(nsISupports *aSubject,
832 const char *aTopic,
833 const char16_t *aData)
835 LOG(("nsPrefetchService::Observe [topic=%s]\n", aTopic));
837 if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
838 StopPrefetching();
839 EmptyQueue();
840 mDisabled = true;
842 else if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
843 if (Preferences::GetBool(PREFETCH_PREF, false)) {
844 if (mDisabled) {
845 LOG(("enabling prefetching\n"));
846 mDisabled = false;
847 AddProgressListener();
850 else {
851 if (!mDisabled) {
852 LOG(("disabling prefetching\n"));
853 StopPrefetching();
854 EmptyQueue();
855 mDisabled = true;
856 RemoveProgressListener();
861 return NS_OK;
864 // vim: ts=4 sw=4 expandtab