Bumping manifests a=b2g-bump
[gecko.git] / uriloader / prefetch / nsPrefetchService.cpp
blob7b64348bdb8c17a108edc70919876ce01e3f76b7
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"
32 using namespace mozilla;
34 #if defined(PR_LOGGING)
36 // To enable logging (see prlog.h for full details):
38 // set NSPR_LOG_MODULES=nsPrefetch:5
39 // set NSPR_LOG_FILE=prefetch.log
41 // this enables PR_LOG_ALWAYS level information and places all output in
42 // the file http.log
44 static PRLogModuleInfo *gPrefetchLog;
45 #endif
47 #undef LOG
48 #define LOG(args) PR_LOG(gPrefetchLog, 4, args)
50 #undef LOG_ENABLED
51 #define LOG_ENABLED() PR_LOG_TEST(gPrefetchLog, 4)
53 #define PREFETCH_PREF "network.prefetch-next"
55 //-----------------------------------------------------------------------------
56 // helpers
57 //-----------------------------------------------------------------------------
59 static inline uint32_t
60 PRTimeToSeconds(PRTime t_usec)
62 PRTime usec_per_sec = PR_USEC_PER_SEC;
63 return uint32_t(t_usec /= usec_per_sec);
66 #define NowInSeconds() PRTimeToSeconds(PR_Now())
68 //-----------------------------------------------------------------------------
69 // nsPrefetchQueueEnumerator
70 //-----------------------------------------------------------------------------
71 class nsPrefetchQueueEnumerator MOZ_FINAL : public nsISimpleEnumerator
73 public:
74 NS_DECL_ISUPPORTS
75 NS_DECL_NSISIMPLEENUMERATOR
76 nsPrefetchQueueEnumerator(nsPrefetchService *aService);
78 private:
79 ~nsPrefetchQueueEnumerator();
81 void Increment();
83 nsRefPtr<nsPrefetchService> mService;
84 nsRefPtr<nsPrefetchNode> mCurrent;
85 bool mStarted;
88 //-----------------------------------------------------------------------------
89 // nsPrefetchQueueEnumerator <public>
90 //-----------------------------------------------------------------------------
91 nsPrefetchQueueEnumerator::nsPrefetchQueueEnumerator(nsPrefetchService *aService)
92 : mService(aService)
93 , mStarted(false)
95 Increment();
98 nsPrefetchQueueEnumerator::~nsPrefetchQueueEnumerator()
102 //-----------------------------------------------------------------------------
103 // nsPrefetchQueueEnumerator::nsISimpleEnumerator
104 //-----------------------------------------------------------------------------
105 NS_IMETHODIMP
106 nsPrefetchQueueEnumerator::HasMoreElements(bool *aHasMore)
108 *aHasMore = (mCurrent != nullptr);
109 return NS_OK;
112 NS_IMETHODIMP
113 nsPrefetchQueueEnumerator::GetNext(nsISupports **aItem)
115 if (!mCurrent) return NS_ERROR_FAILURE;
117 NS_ADDREF(*aItem = static_cast<nsIStreamListener*>(mCurrent.get()));
119 Increment();
121 return NS_OK;
124 //-----------------------------------------------------------------------------
125 // nsPrefetchQueueEnumerator <private>
126 //-----------------------------------------------------------------------------
128 void
129 nsPrefetchQueueEnumerator::Increment()
131 if (!mStarted) {
132 // If the service is currently serving a request, it won't be in
133 // the pending queue, so we return it first. If it isn't, we'll
134 // just start with the pending queue.
135 mStarted = true;
136 mCurrent = mService->GetCurrentNode();
137 if (!mCurrent)
138 mCurrent = mService->GetQueueHead();
139 return;
142 if (mCurrent) {
143 if (mCurrent == mService->GetCurrentNode()) {
144 // If we just returned the node being processed by the service,
145 // start with the pending queue
146 mCurrent = mService->GetQueueHead();
148 else {
149 // Otherwise just advance to the next item in the queue
150 mCurrent = mCurrent->mNext;
155 //-----------------------------------------------------------------------------
156 // nsPrefetchQueueEnumerator::nsISupports
157 //-----------------------------------------------------------------------------
159 NS_IMPL_ISUPPORTS(nsPrefetchQueueEnumerator, nsISimpleEnumerator)
161 //-----------------------------------------------------------------------------
162 // nsPrefetchNode <public>
163 //-----------------------------------------------------------------------------
165 nsPrefetchNode::nsPrefetchNode(nsPrefetchService *aService,
166 nsIURI *aURI,
167 nsIURI *aReferrerURI,
168 nsIDOMNode *aSource)
169 : mNext(nullptr)
170 , mURI(aURI)
171 , mReferrerURI(aReferrerURI)
172 , mService(aService)
173 , mChannel(nullptr)
174 , mBytesRead(0)
176 mSource = do_GetWeakReference(aSource);
179 nsresult
180 nsPrefetchNode::OpenChannel()
182 nsCOMPtr<nsINode> source = do_QueryReferent(mSource);
183 if (!source) {
184 // Don't attempt to prefetch if we don't have a source node
185 // (which should never happen).
186 return NS_ERROR_FAILURE;
188 nsCOMPtr<nsILoadGroup> loadGroup = source->OwnerDoc()->GetDocumentLoadGroup();
189 nsresult rv = NS_NewChannel(getter_AddRefs(mChannel),
190 mURI,
191 nullptr, loadGroup, this,
192 nsIRequest::LOAD_BACKGROUND |
193 nsICachingChannel::LOAD_ONLY_IF_MODIFIED);
194 NS_ENSURE_SUCCESS(rv, rv);
196 // configure HTTP specific stuff
197 nsCOMPtr<nsIHttpChannel> httpChannel =
198 do_QueryInterface(mChannel);
199 if (httpChannel) {
200 httpChannel->SetReferrer(mReferrerURI);
201 httpChannel->SetRequestHeader(
202 NS_LITERAL_CSTRING("X-Moz"),
203 NS_LITERAL_CSTRING("prefetch"),
204 false);
207 rv = mChannel->AsyncOpen(this, nullptr);
208 NS_ENSURE_SUCCESS(rv, rv);
210 return NS_OK;
213 nsresult
214 nsPrefetchNode::CancelChannel(nsresult error)
216 mChannel->Cancel(error);
217 mChannel = nullptr;
219 return NS_OK;
222 //-----------------------------------------------------------------------------
223 // nsPrefetchNode::nsISupports
224 //-----------------------------------------------------------------------------
226 NS_IMPL_ISUPPORTS(nsPrefetchNode,
227 nsIRequestObserver,
228 nsIStreamListener,
229 nsIInterfaceRequestor,
230 nsIChannelEventSink,
231 nsIRedirectResultListener)
233 //-----------------------------------------------------------------------------
234 // nsPrefetchNode::nsIStreamListener
235 //-----------------------------------------------------------------------------
237 NS_IMETHODIMP
238 nsPrefetchNode::OnStartRequest(nsIRequest *aRequest,
239 nsISupports *aContext)
241 nsresult rv;
243 nsCOMPtr<nsICachingChannel> cachingChannel =
244 do_QueryInterface(aRequest, &rv);
245 if (NS_FAILED(rv)) return rv;
247 // no need to prefetch a document that is already in the cache
248 bool fromCache;
249 if (NS_SUCCEEDED(cachingChannel->IsFromCache(&fromCache)) &&
250 fromCache) {
251 LOG(("document is already in the cache; canceling prefetch\n"));
252 return NS_BINDING_ABORTED;
256 // no need to prefetch a document that must be requested fresh each
257 // and every time.
259 nsCOMPtr<nsISupports> cacheToken;
260 cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
261 if (!cacheToken)
262 return NS_ERROR_ABORT; // bail, no cache entry
264 nsCOMPtr<nsICacheEntry> entryInfo =
265 do_QueryInterface(cacheToken, &rv);
266 if (NS_FAILED(rv)) return rv;
268 uint32_t expTime;
269 if (NS_SUCCEEDED(entryInfo->GetExpirationTime(&expTime))) {
270 if (NowInSeconds() >= expTime) {
271 LOG(("document cannot be reused from cache; "
272 "canceling prefetch\n"));
273 return NS_BINDING_ABORTED;
277 return NS_OK;
280 NS_IMETHODIMP
281 nsPrefetchNode::OnDataAvailable(nsIRequest *aRequest,
282 nsISupports *aContext,
283 nsIInputStream *aStream,
284 uint64_t aOffset,
285 uint32_t aCount)
287 uint32_t bytesRead = 0;
288 aStream->ReadSegments(NS_DiscardSegment, nullptr, aCount, &bytesRead);
289 mBytesRead += bytesRead;
290 LOG(("prefetched %u bytes [offset=%llu]\n", bytesRead, aOffset));
291 return NS_OK;
295 NS_IMETHODIMP
296 nsPrefetchNode::OnStopRequest(nsIRequest *aRequest,
297 nsISupports *aContext,
298 nsresult aStatus)
300 LOG(("done prefetching [status=%x]\n", aStatus));
302 if (mBytesRead == 0 && aStatus == NS_OK) {
303 // we didn't need to read (because LOAD_ONLY_IF_MODIFIED was
304 // specified), but the object should report loadedSize as if it
305 // did.
306 mChannel->GetContentLength(&mBytesRead);
309 mService->NotifyLoadCompleted(this);
310 mService->ProcessNextURI();
311 return NS_OK;
314 //-----------------------------------------------------------------------------
315 // nsPrefetchNode::nsIInterfaceRequestor
316 //-----------------------------------------------------------------------------
318 NS_IMETHODIMP
319 nsPrefetchNode::GetInterface(const nsIID &aIID, void **aResult)
321 if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
322 NS_ADDREF_THIS();
323 *aResult = static_cast<nsIChannelEventSink *>(this);
324 return NS_OK;
327 if (aIID.Equals(NS_GET_IID(nsIRedirectResultListener))) {
328 NS_ADDREF_THIS();
329 *aResult = static_cast<nsIRedirectResultListener *>(this);
330 return NS_OK;
333 return NS_ERROR_NO_INTERFACE;
336 //-----------------------------------------------------------------------------
337 // nsPrefetchNode::nsIChannelEventSink
338 //-----------------------------------------------------------------------------
340 NS_IMETHODIMP
341 nsPrefetchNode::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
342 nsIChannel *aNewChannel,
343 uint32_t aFlags,
344 nsIAsyncVerifyRedirectCallback *callback)
346 nsCOMPtr<nsIURI> newURI;
347 nsresult rv = aNewChannel->GetURI(getter_AddRefs(newURI));
348 if (NS_FAILED(rv))
349 return rv;
351 bool match;
352 rv = newURI->SchemeIs("http", &match);
353 if (NS_FAILED(rv) || !match) {
354 rv = newURI->SchemeIs("https", &match);
355 if (NS_FAILED(rv) || !match) {
356 LOG(("rejected: URL is not of type http/https\n"));
357 return NS_ERROR_ABORT;
361 // HTTP request headers are not automatically forwarded to the new channel.
362 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aNewChannel);
363 NS_ENSURE_STATE(httpChannel);
365 httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
366 NS_LITERAL_CSTRING("prefetch"),
367 false);
369 // Assign to mChannel after we get notification about success of the
370 // redirect in OnRedirectResult.
371 mRedirectChannel = aNewChannel;
373 callback->OnRedirectVerifyCallback(NS_OK);
374 return NS_OK;
377 //-----------------------------------------------------------------------------
378 // nsPrefetchNode::nsIRedirectResultListener
379 //-----------------------------------------------------------------------------
381 NS_IMETHODIMP
382 nsPrefetchNode::OnRedirectResult(bool proceeding)
384 if (proceeding && mRedirectChannel)
385 mChannel = mRedirectChannel;
387 mRedirectChannel = nullptr;
389 return NS_OK;
392 //-----------------------------------------------------------------------------
393 // nsPrefetchService <public>
394 //-----------------------------------------------------------------------------
396 nsPrefetchService::nsPrefetchService()
397 : mQueueHead(nullptr)
398 , mQueueTail(nullptr)
399 , mStopCount(0)
400 , mHaveProcessed(false)
401 , mDisabled(true)
405 nsPrefetchService::~nsPrefetchService()
407 Preferences::RemoveObserver(this, PREFETCH_PREF);
408 // cannot reach destructor if prefetch in progress (listener owns reference
409 // to this service)
410 EmptyQueue();
413 nsresult
414 nsPrefetchService::Init()
416 #if defined(PR_LOGGING)
417 if (!gPrefetchLog)
418 gPrefetchLog = PR_NewLogModule("nsPrefetch");
419 #endif
421 nsresult rv;
423 // read prefs and hook up pref observer
424 mDisabled = !Preferences::GetBool(PREFETCH_PREF, !mDisabled);
425 Preferences::AddWeakObserver(this, PREFETCH_PREF);
427 // Observe xpcom-shutdown event
428 nsCOMPtr<nsIObserverService> observerService =
429 mozilla::services::GetObserverService();
430 if (!observerService)
431 return NS_ERROR_FAILURE;
433 rv = observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
434 NS_ENSURE_SUCCESS(rv, rv);
436 if (!mDisabled)
437 AddProgressListener();
439 return NS_OK;
442 void
443 nsPrefetchService::ProcessNextURI()
445 nsresult rv;
446 nsCOMPtr<nsIURI> uri, referrer;
448 mCurrentNode = nullptr;
450 do {
451 rv = DequeueNode(getter_AddRefs(mCurrentNode));
453 if (NS_FAILED(rv)) break;
455 #if defined(PR_LOGGING)
456 if (LOG_ENABLED()) {
457 nsAutoCString spec;
458 mCurrentNode->mURI->GetSpec(spec);
459 LOG(("ProcessNextURI [%s]\n", spec.get()));
461 #endif
464 // if opening the channel fails, then just skip to the next uri
466 nsRefPtr<nsPrefetchNode> node = mCurrentNode;
467 rv = node->OpenChannel();
469 while (NS_FAILED(rv));
472 void
473 nsPrefetchService::NotifyLoadRequested(nsPrefetchNode *node)
475 nsCOMPtr<nsIObserverService> observerService =
476 mozilla::services::GetObserverService();
477 if (!observerService)
478 return;
480 observerService->NotifyObservers(static_cast<nsIStreamListener*>(node),
481 "prefetch-load-requested", nullptr);
484 void
485 nsPrefetchService::NotifyLoadCompleted(nsPrefetchNode *node)
487 nsCOMPtr<nsIObserverService> observerService =
488 mozilla::services::GetObserverService();
489 if (!observerService)
490 return;
492 observerService->NotifyObservers(static_cast<nsIStreamListener*>(node),
493 "prefetch-load-completed", nullptr);
496 //-----------------------------------------------------------------------------
497 // nsPrefetchService <private>
498 //-----------------------------------------------------------------------------
500 void
501 nsPrefetchService::AddProgressListener()
503 // Register as an observer for the document loader
504 nsCOMPtr<nsIWebProgress> progress =
505 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
506 if (progress)
507 progress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
510 void
511 nsPrefetchService::RemoveProgressListener()
513 // Register as an observer for the document loader
514 nsCOMPtr<nsIWebProgress> progress =
515 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
516 if (progress)
517 progress->RemoveProgressListener(this);
520 nsresult
521 nsPrefetchService::EnqueueNode(nsPrefetchNode *aNode)
523 NS_ADDREF(aNode);
525 if (!mQueueTail) {
526 mQueueHead = aNode;
527 mQueueTail = aNode;
529 else {
530 mQueueTail->mNext = aNode;
531 mQueueTail = aNode;
534 return NS_OK;
537 nsresult
538 nsPrefetchService::EnqueueURI(nsIURI *aURI,
539 nsIURI *aReferrerURI,
540 nsIDOMNode *aSource,
541 nsPrefetchNode **aNode)
543 nsPrefetchNode *node = new nsPrefetchNode(this, aURI, aReferrerURI,
544 aSource);
545 if (!node)
546 return NS_ERROR_OUT_OF_MEMORY;
548 NS_ADDREF(*aNode = node);
550 return EnqueueNode(node);
553 nsresult
554 nsPrefetchService::DequeueNode(nsPrefetchNode **node)
556 if (!mQueueHead)
557 return NS_ERROR_NOT_AVAILABLE;
559 // give the ref to the caller
560 *node = mQueueHead;
561 mQueueHead = mQueueHead->mNext;
562 (*node)->mNext = nullptr;
564 if (!mQueueHead)
565 mQueueTail = nullptr;
567 return NS_OK;
570 void
571 nsPrefetchService::EmptyQueue()
573 do {
574 nsRefPtr<nsPrefetchNode> node;
575 DequeueNode(getter_AddRefs(node));
576 } while (mQueueHead);
579 void
580 nsPrefetchService::StartPrefetching()
583 // at initialization time we might miss the first DOCUMENT START
584 // notification, so we have to be careful to avoid letting our
585 // stop count go negative.
587 if (mStopCount > 0)
588 mStopCount--;
590 LOG(("StartPrefetching [stopcount=%d]\n", mStopCount));
592 // only start prefetching after we've received enough DOCUMENT
593 // STOP notifications. we do this inorder to defer prefetching
594 // until after all sub-frames have finished loading.
595 if (mStopCount == 0 && !mCurrentNode) {
596 mHaveProcessed = true;
597 ProcessNextURI();
601 void
602 nsPrefetchService::StopPrefetching()
604 mStopCount++;
606 LOG(("StopPrefetching [stopcount=%d]\n", mStopCount));
608 // only kill the prefetch queue if we've actually started prefetching.
609 if (!mCurrentNode)
610 return;
612 mCurrentNode->CancelChannel(NS_BINDING_ABORTED);
613 mCurrentNode = nullptr;
614 EmptyQueue();
617 //-----------------------------------------------------------------------------
618 // nsPrefetchService::nsISupports
619 //-----------------------------------------------------------------------------
621 NS_IMPL_ISUPPORTS(nsPrefetchService,
622 nsIPrefetchService,
623 nsIWebProgressListener,
624 nsIObserver,
625 nsISupportsWeakReference)
627 //-----------------------------------------------------------------------------
628 // nsPrefetchService::nsIPrefetchService
629 //-----------------------------------------------------------------------------
631 nsresult
632 nsPrefetchService::Prefetch(nsIURI *aURI,
633 nsIURI *aReferrerURI,
634 nsIDOMNode *aSource,
635 bool aExplicit)
637 nsresult rv;
639 NS_ENSURE_ARG_POINTER(aURI);
640 NS_ENSURE_ARG_POINTER(aReferrerURI);
642 #if defined(PR_LOGGING)
643 if (LOG_ENABLED()) {
644 nsAutoCString spec;
645 aURI->GetSpec(spec);
646 LOG(("PrefetchURI [%s]\n", spec.get()));
648 #endif
650 if (mDisabled) {
651 LOG(("rejected: prefetch service is disabled\n"));
652 return NS_ERROR_ABORT;
656 // XXX we should really be asking the protocol handler if it supports
657 // caching, so we can determine if there is any value to prefetching.
658 // for now, we'll only prefetch http links since we know that's the
659 // most common case. ignore https links since https content only goes
660 // into the memory cache.
662 // XXX we might want to either leverage nsIProtocolHandler::protocolFlags
663 // or possibly nsIRequest::loadFlags to determine if this URI should be
664 // prefetched.
666 bool match;
667 rv = aURI->SchemeIs("http", &match);
668 if (NS_FAILED(rv) || !match) {
669 rv = aURI->SchemeIs("https", &match);
670 if (NS_FAILED(rv) || !match) {
671 LOG(("rejected: URL is not of type http/https\n"));
672 return NS_ERROR_ABORT;
677 // the referrer URI must be http:
679 rv = aReferrerURI->SchemeIs("http", &match);
680 if (NS_FAILED(rv) || !match) {
681 rv = aReferrerURI->SchemeIs("https", &match);
682 if (NS_FAILED(rv) || !match) {
683 LOG(("rejected: referrer URL is neither http nor https\n"));
684 return NS_ERROR_ABORT;
688 // skip URLs that contain query strings, except URLs for which prefetching
689 // has been explicitly requested.
690 if (!aExplicit) {
691 nsCOMPtr<nsIURL> url(do_QueryInterface(aURI, &rv));
692 if (NS_FAILED(rv)) return rv;
693 nsAutoCString query;
694 rv = url->GetQuery(query);
695 if (NS_FAILED(rv) || !query.IsEmpty()) {
696 LOG(("rejected: URL has a query string\n"));
697 return NS_ERROR_ABORT;
702 // cancel if being prefetched
704 if (mCurrentNode) {
705 bool equals;
706 if (NS_SUCCEEDED(mCurrentNode->mURI->Equals(aURI, &equals)) && equals) {
707 LOG(("rejected: URL is already being prefetched\n"));
708 return NS_ERROR_ABORT;
713 // cancel if already on the prefetch queue
715 nsPrefetchNode *node = mQueueHead;
716 for (; node; node = node->mNext) {
717 bool equals;
718 if (NS_SUCCEEDED(node->mURI->Equals(aURI, &equals)) && equals) {
719 LOG(("rejected: URL is already on prefetch queue\n"));
720 return NS_ERROR_ABORT;
724 nsRefPtr<nsPrefetchNode> enqueuedNode;
725 rv = EnqueueURI(aURI, aReferrerURI, aSource,
726 getter_AddRefs(enqueuedNode));
727 NS_ENSURE_SUCCESS(rv, rv);
729 NotifyLoadRequested(enqueuedNode);
731 // if there are no pages loading, kick off the request immediately
732 if (mStopCount == 0 && mHaveProcessed)
733 ProcessNextURI();
735 return NS_OK;
738 NS_IMETHODIMP
739 nsPrefetchService::PrefetchURI(nsIURI *aURI,
740 nsIURI *aReferrerURI,
741 nsIDOMNode *aSource,
742 bool aExplicit)
744 return Prefetch(aURI, aReferrerURI, aSource, aExplicit);
747 NS_IMETHODIMP
748 nsPrefetchService::EnumerateQueue(nsISimpleEnumerator **aEnumerator)
750 *aEnumerator = new nsPrefetchQueueEnumerator(this);
751 if (!*aEnumerator) return NS_ERROR_OUT_OF_MEMORY;
753 NS_ADDREF(*aEnumerator);
755 return NS_OK;
758 //-----------------------------------------------------------------------------
759 // nsPrefetchService::nsIWebProgressListener
760 //-----------------------------------------------------------------------------
762 NS_IMETHODIMP
763 nsPrefetchService::OnProgressChange(nsIWebProgress *aProgress,
764 nsIRequest *aRequest,
765 int32_t curSelfProgress,
766 int32_t maxSelfProgress,
767 int32_t curTotalProgress,
768 int32_t maxTotalProgress)
770 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
771 return NS_OK;
774 NS_IMETHODIMP
775 nsPrefetchService::OnStateChange(nsIWebProgress* aWebProgress,
776 nsIRequest *aRequest,
777 uint32_t progressStateFlags,
778 nsresult aStatus)
780 if (progressStateFlags & STATE_IS_DOCUMENT) {
781 if (progressStateFlags & STATE_STOP)
782 StartPrefetching();
783 else if (progressStateFlags & STATE_START)
784 StopPrefetching();
787 return NS_OK;
791 NS_IMETHODIMP
792 nsPrefetchService::OnLocationChange(nsIWebProgress* aWebProgress,
793 nsIRequest* aRequest,
794 nsIURI *location,
795 uint32_t aFlags)
797 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
798 return NS_OK;
801 NS_IMETHODIMP
802 nsPrefetchService::OnStatusChange(nsIWebProgress* aWebProgress,
803 nsIRequest* aRequest,
804 nsresult aStatus,
805 const char16_t* aMessage)
807 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
808 return NS_OK;
811 NS_IMETHODIMP
812 nsPrefetchService::OnSecurityChange(nsIWebProgress *aWebProgress,
813 nsIRequest *aRequest,
814 uint32_t state)
816 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
817 return NS_OK;
820 //-----------------------------------------------------------------------------
821 // nsPrefetchService::nsIObserver
822 //-----------------------------------------------------------------------------
824 NS_IMETHODIMP
825 nsPrefetchService::Observe(nsISupports *aSubject,
826 const char *aTopic,
827 const char16_t *aData)
829 LOG(("nsPrefetchService::Observe [topic=%s]\n", aTopic));
831 if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
832 StopPrefetching();
833 EmptyQueue();
834 mDisabled = true;
836 else if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
837 if (Preferences::GetBool(PREFETCH_PREF, false)) {
838 if (mDisabled) {
839 LOG(("enabling prefetching\n"));
840 mDisabled = false;
841 AddProgressListener();
844 else {
845 if (!mDisabled) {
846 LOG(("disabling prefetching\n"));
847 StopPrefetching();
848 EmptyQueue();
849 mDisabled = true;
850 RemoveProgressListener();
855 return NS_OK;
858 // vim: ts=4 sw=4 expandtab