diff options
author | Matt A. Tobin <email@mattatobin.com> | 2022-04-18 19:26:18 -0500 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2022-04-18 19:26:18 -0500 |
commit | 5970ab8b55d3bf835bcf67d04352a0b3cfa3581d (patch) | |
tree | 948face04d19eb885b07dd3a961e2252a7990215 /system | |
parent | 320e5c434e26a8fa167292cc471f5c63c39daf77 (diff) | |
download | aura-central-5970ab8b55d3bf835bcf67d04352a0b3cfa3581d.tar.gz |
Issue #10 - Move prefetch to components/
Diffstat (limited to 'system')
18 files changed, 1 insertions, 6360 deletions
diff --git a/system/docshell/build/moz.build b/system/docshell/build/moz.build index 82cef31a5..c5acdb900 100644 --- a/system/docshell/build/moz.build +++ b/system/docshell/build/moz.build @@ -13,7 +13,7 @@ SOURCES += [ LOCAL_INCLUDES += [ '../base', - '../prefetch', + '/components/prefetch', '/components/shistory/src', '/components/uriloader', '/system/network/exthandler', diff --git a/system/docshell/moz.build b/system/docshell/moz.build index 37e00e4ae..69f1c8be1 100644 --- a/system/docshell/moz.build +++ b/system/docshell/moz.build @@ -6,7 +6,6 @@ DIRS += [ 'base', 'build', - 'prefetch', 'resources/content', ] diff --git a/system/docshell/prefetch/OfflineCacheUpdateChild.cpp b/system/docshell/prefetch/OfflineCacheUpdateChild.cpp deleted file mode 100644 index 555508c37..000000000 --- a/system/docshell/prefetch/OfflineCacheUpdateChild.cpp +++ /dev/null @@ -1,528 +0,0 @@ -/* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "BackgroundUtils.h" -#include "OfflineCacheUpdateChild.h" -#include "nsOfflineCacheUpdate.h" -#include "mozilla/dom/ContentChild.h" -#include "mozilla/dom/TabChild.h" -#include "mozilla/ipc/URIUtils.h" -#include "mozilla/net/NeckoCommon.h" - -#include "nsIApplicationCacheContainer.h" -#include "nsIApplicationCacheChannel.h" -#include "nsIApplicationCacheService.h" -#include "nsIDocShell.h" -#include "nsIDocShellTreeItem.h" -#include "nsIDocShellTreeOwner.h" -#include "nsPIDOMWindow.h" -#include "nsIDOMOfflineResourceList.h" -#include "nsIDocument.h" -#include "nsIObserverService.h" -#include "nsIURL.h" -#include "nsITabChild.h" -#include "nsNetCID.h" -#include "nsNetUtil.h" -#include "nsServiceManagerUtils.h" -#include "nsStreamUtils.h" -#include "nsThreadUtils.h" -#include "nsProxyRelease.h" -#include "mozilla/Logging.h" -#include "nsIAsyncVerifyRedirectCallback.h" - -using namespace mozilla::ipc; -using namespace mozilla::net; -using mozilla::dom::TabChild; -using mozilla::dom::ContentChild; - -// -// To enable logging (see mozilla/Logging.h for full details): -// -// set MOZ_LOG=nsOfflineCacheUpdate:5 -// set MOZ_LOG_FILE=offlineupdate.log -// -// this enables LogLevel::Debug level information and places all output in -// the file offlineupdate.log -// -extern mozilla::LazyLogModule gOfflineCacheUpdateLog; - -#undef LOG -#define LOG(args) MOZ_LOG(gOfflineCacheUpdateLog, mozilla::LogLevel::Debug, args) - -#undef LOG_ENABLED -#define LOG_ENABLED() MOZ_LOG_TEST(gOfflineCacheUpdateLog, mozilla::LogLevel::Debug) - -namespace mozilla { -namespace docshell { - -//----------------------------------------------------------------------------- -// OfflineCacheUpdateChild::nsISupports -//----------------------------------------------------------------------------- - -NS_INTERFACE_MAP_BEGIN(OfflineCacheUpdateChild) - NS_INTERFACE_MAP_ENTRY(nsISupports) - NS_INTERFACE_MAP_ENTRY(nsIOfflineCacheUpdate) -NS_INTERFACE_MAP_END - -NS_IMPL_ADDREF(OfflineCacheUpdateChild) -NS_IMPL_RELEASE(OfflineCacheUpdateChild) - -//----------------------------------------------------------------------------- -// OfflineCacheUpdateChild <public> -//----------------------------------------------------------------------------- - -OfflineCacheUpdateChild::OfflineCacheUpdateChild(nsPIDOMWindowInner* aWindow) - : mState(STATE_UNINITIALIZED) - , mIsUpgrade(false) - , mSucceeded(false) - , mWindow(aWindow) - , mByteProgress(0) -{ -} - -OfflineCacheUpdateChild::~OfflineCacheUpdateChild() -{ - LOG(("OfflineCacheUpdateChild::~OfflineCacheUpdateChild [%p]", this)); -} - -void -OfflineCacheUpdateChild::GatherObservers(nsCOMArray<nsIOfflineCacheUpdateObserver> &aObservers) -{ - for (int32_t i = 0; i < mWeakObservers.Count(); i++) { - nsCOMPtr<nsIOfflineCacheUpdateObserver> observer = - do_QueryReferent(mWeakObservers[i]); - if (observer) - aObservers.AppendObject(observer); - else - mWeakObservers.RemoveObjectAt(i--); - } - - for (int32_t i = 0; i < mObservers.Count(); i++) { - aObservers.AppendObject(mObservers[i]); - } -} - -void -OfflineCacheUpdateChild::SetDocument(nsIDOMDocument *aDocument) -{ - // The design is one document for one cache update on the content process. - NS_ASSERTION(!mDocument, "Setting more then a single document on a child offline cache update"); - - LOG(("Document %p added to update child %p", aDocument, this)); - - // Add document only if it was not loaded from an offline cache. - // If it were loaded from an offline cache then it has already - // been associated with it and must not be again cached as - // implicit (which are the reasons we collect documents here). - nsCOMPtr<nsIDocument> document = do_QueryInterface(aDocument); - if (!document) - return; - - nsIChannel* channel = document->GetChannel(); - nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel = - do_QueryInterface(channel); - if (!appCacheChannel) - return; - - bool loadedFromAppCache; - appCacheChannel->GetLoadedFromApplicationCache(&loadedFromAppCache); - if (loadedFromAppCache) - return; - - mDocument = aDocument; -} - -nsresult -OfflineCacheUpdateChild::AssociateDocument(nsIDOMDocument *aDocument, - nsIApplicationCache *aApplicationCache) -{ - // Check that the document that requested this update was - // previously associated with an application cache. If not, it - // should be associated with the new one. - nsCOMPtr<nsIApplicationCacheContainer> container = - do_QueryInterface(aDocument); - if (!container) - return NS_OK; - - nsCOMPtr<nsIApplicationCache> existingCache; - nsresult rv = container->GetApplicationCache(getter_AddRefs(existingCache)); - NS_ENSURE_SUCCESS(rv, rv); - - if (!existingCache) { - if (LOG_ENABLED()) { - nsAutoCString clientID; - if (aApplicationCache) { - aApplicationCache->GetClientID(clientID); - } - LOG(("Update %p: associating app cache %s to document %p", - this, clientID.get(), aDocument)); - } - - rv = container->SetApplicationCache(aApplicationCache); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// OfflineCacheUpdateChild::nsIOfflineCacheUpdate -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -OfflineCacheUpdateChild::Init(nsIURI *aManifestURI, - nsIURI *aDocumentURI, - nsIPrincipal *aLoadingPrincipal, - nsIDOMDocument *aDocument, - nsIFile *aCustomProfileDir) -{ - nsresult rv; - - // Make sure the service has been initialized - nsOfflineCacheUpdateService* service = - nsOfflineCacheUpdateService::EnsureService(); - if (!service) - return NS_ERROR_FAILURE; - - if (aCustomProfileDir) { - NS_ERROR("Custom Offline Cache Update not supported on child process"); - return NS_ERROR_NOT_IMPLEMENTED; - } - - LOG(("OfflineCacheUpdateChild::Init [%p]", this)); - - // Only http and https applications are supported. - bool match; - rv = aManifestURI->SchemeIs("http", &match); - NS_ENSURE_SUCCESS(rv, rv); - - if (!match) { - rv = aManifestURI->SchemeIs("https", &match); - NS_ENSURE_SUCCESS(rv, rv); - if (!match) - return NS_ERROR_ABORT; - } - - mManifestURI = aManifestURI; - - rv = mManifestURI->GetAsciiHost(mUpdateDomain); - NS_ENSURE_SUCCESS(rv, rv); - - mDocumentURI = aDocumentURI; - mLoadingPrincipal = aLoadingPrincipal; - - mState = STATE_INITIALIZED; - - if (aDocument) - SetDocument(aDocument); - - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::InitPartial(nsIURI *aManifestURI, - const nsACString& clientID, - nsIURI *aDocumentURI, - nsIPrincipal *aLoadingPrincipal) -{ - NS_NOTREACHED("Not expected to do partial offline cache updates" - " on the child process"); - // For now leaving this method, we may discover we need it. - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::InitForUpdateCheck(nsIURI *aManifestURI, - nsIPrincipal* aLoadingPrincipal, - nsIObserver *aObserver) -{ - NS_NOTREACHED("Not expected to do only update checks" - " from the child process"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::GetUpdateDomain(nsACString &aUpdateDomain) -{ - NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED); - - aUpdateDomain = mUpdateDomain; - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::GetStatus(uint16_t *aStatus) -{ - switch (mState) { - case STATE_CHECKING : - *aStatus = nsIDOMOfflineResourceList::CHECKING; - return NS_OK; - case STATE_DOWNLOADING : - *aStatus = nsIDOMOfflineResourceList::DOWNLOADING; - return NS_OK; - default : - *aStatus = nsIDOMOfflineResourceList::IDLE; - return NS_OK; - } - - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::GetPartial(bool *aPartial) -{ - *aPartial = false; - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::GetManifestURI(nsIURI **aManifestURI) -{ - NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED); - - NS_IF_ADDREF(*aManifestURI = mManifestURI); - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::GetSucceeded(bool *aSucceeded) -{ - NS_ENSURE_TRUE(mState == STATE_FINISHED, NS_ERROR_NOT_AVAILABLE); - - *aSucceeded = mSucceeded; - - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::GetIsUpgrade(bool *aIsUpgrade) -{ - NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED); - - *aIsUpgrade = mIsUpgrade; - - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::AddDynamicURI(nsIURI *aURI) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::Cancel() -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::AddObserver(nsIOfflineCacheUpdateObserver *aObserver, - bool aHoldWeak) -{ - LOG(("OfflineCacheUpdateChild::AddObserver [%p]", this)); - - NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED); - - if (aHoldWeak) { - nsCOMPtr<nsIWeakReference> weakRef = do_GetWeakReference(aObserver); - mWeakObservers.AppendObject(weakRef); - } else { - mObservers.AppendObject(aObserver); - } - - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::RemoveObserver(nsIOfflineCacheUpdateObserver *aObserver) -{ - LOG(("OfflineCacheUpdateChild::RemoveObserver [%p]", this)); - - NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED); - - for (int32_t i = 0; i < mWeakObservers.Count(); i++) { - nsCOMPtr<nsIOfflineCacheUpdateObserver> observer = - do_QueryReferent(mWeakObservers[i]); - if (observer == aObserver) { - mWeakObservers.RemoveObjectAt(i); - return NS_OK; - } - } - - for (int32_t i = 0; i < mObservers.Count(); i++) { - if (mObservers[i] == aObserver) { - mObservers.RemoveObjectAt(i); - return NS_OK; - } - } - - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::GetByteProgress(uint64_t * _result) -{ - NS_ENSURE_ARG(_result); - - *_result = mByteProgress; - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateChild::Schedule() -{ - LOG(("OfflineCacheUpdateChild::Schedule [%p]", this)); - - NS_ASSERTION(mWindow, "Window must be provided to the offline cache update child"); - - nsCOMPtr<nsPIDOMWindowInner> window = mWindow.forget(); - nsCOMPtr<nsIDocShell >docshell = window->GetDocShell(); - if (!docshell) { - NS_WARNING("doc shell tree item is null"); - return NS_ERROR_FAILURE; - } - - nsCOMPtr<nsITabChild> tabchild = docshell->GetTabChild(); - // because owner implements nsITabChild, we can assume that it is - // the one and only TabChild. - TabChild* child = tabchild ? static_cast<TabChild*>(tabchild.get()) : nullptr; - - if (MissingRequiredTabChild(child, "offlinecacheupdate")) { - return NS_ERROR_FAILURE; - } - - URIParams manifestURI, documentURI; - SerializeURI(mManifestURI, manifestURI); - SerializeURI(mDocumentURI, documentURI); - - nsresult rv = NS_OK; - PrincipalInfo loadingPrincipalInfo; - rv = PrincipalToPrincipalInfo(mLoadingPrincipal, - &loadingPrincipalInfo); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIObserverService> observerService = - mozilla::services::GetObserverService(); - if (observerService) { - LOG(("Calling offline-cache-update-added")); - observerService->NotifyObservers(static_cast<nsIOfflineCacheUpdate*>(this), - "offline-cache-update-added", - nullptr); - LOG(("Done offline-cache-update-added")); - } - - // mDocument is non-null if both: - // 1. this update was initiated by a document that referred a manifest - // 2. the document has not already been loaded from the application cache - // This tells the update to cache this document even in case the manifest - // has not been changed since the last fetch. - // See also nsOfflineCacheUpdate::ScheduleImplicit. - bool stickDocument = mDocument != nullptr; - - // Need to addref ourself here, because the IPC stack doesn't hold - // a reference to us. Will be released in RecvFinish() that identifies - // the work has been done. - ContentChild::GetSingleton()->SendPOfflineCacheUpdateConstructor( - this, manifestURI, documentURI, loadingPrincipalInfo, - stickDocument); - - // ContentChild::DeallocPOfflineCacheUpdate will release this. - NS_ADDREF_THIS(); - - return NS_OK; -} - -bool -OfflineCacheUpdateChild::RecvAssociateDocuments(const nsCString &cacheGroupId, - const nsCString &cacheClientId) -{ - LOG(("OfflineCacheUpdateChild::RecvAssociateDocuments [%p, cache=%s]", this, cacheClientId.get())); - - nsresult rv; - - nsCOMPtr<nsIApplicationCache> cache = - do_CreateInstance(NS_APPLICATIONCACHE_CONTRACTID, &rv); - if (NS_FAILED(rv)) - return true; - - cache->InitAsHandle(cacheGroupId, cacheClientId); - - if (mDocument) { - AssociateDocument(mDocument, cache); - } - - nsCOMArray<nsIOfflineCacheUpdateObserver> observers; - GatherObservers(observers); - - for (int32_t i = 0; i < observers.Count(); i++) - observers[i]->ApplicationCacheAvailable(cache); - - return true; -} - -bool -OfflineCacheUpdateChild::RecvNotifyStateEvent(const uint32_t &event, - const uint64_t &byteProgress) -{ - LOG(("OfflineCacheUpdateChild::RecvNotifyStateEvent [%p]", this)); - - mByteProgress = byteProgress; - - // Convert the public observer state to our internal state - switch (event) { - case nsIOfflineCacheUpdateObserver::STATE_CHECKING: - mState = STATE_CHECKING; - break; - - case nsIOfflineCacheUpdateObserver::STATE_DOWNLOADING: - mState = STATE_DOWNLOADING; - break; - - default: - break; - } - - nsCOMArray<nsIOfflineCacheUpdateObserver> observers; - GatherObservers(observers); - - for (int32_t i = 0; i < observers.Count(); i++) - observers[i]->UpdateStateChanged(this, event); - - return true; -} - -bool -OfflineCacheUpdateChild::RecvFinish(const bool &succeeded, - const bool &isUpgrade) -{ - LOG(("OfflineCacheUpdateChild::RecvFinish [%p]", this)); - - RefPtr<OfflineCacheUpdateChild> kungFuDeathGrip(this); - - mState = STATE_FINISHED; - mSucceeded = succeeded; - mIsUpgrade = isUpgrade; - - nsCOMPtr<nsIObserverService> observerService = - mozilla::services::GetObserverService(); - if (observerService) { - LOG(("Calling offline-cache-update-completed")); - observerService->NotifyObservers(static_cast<nsIOfflineCacheUpdate*>(this), - "offline-cache-update-completed", - nullptr); - LOG(("Done offline-cache-update-completed")); - } - - // This is by contract the last notification from the parent, release - // us now. This is corresponding to AddRef in Schedule(). - // TabChild::DeallocPOfflineCacheUpdate will call Release. - OfflineCacheUpdateChild::Send__delete__(this); - - return true; -} - -} // namespace docshell -} // namespace mozilla diff --git a/system/docshell/prefetch/OfflineCacheUpdateChild.h b/system/docshell/prefetch/OfflineCacheUpdateChild.h deleted file mode 100644 index 89d1e6f1f..000000000 --- a/system/docshell/prefetch/OfflineCacheUpdateChild.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsOfflineCacheUpdateChild_h -#define nsOfflineCacheUpdateChild_h - -#include "mozilla/docshell/POfflineCacheUpdateChild.h" -#include "nsIOfflineCacheUpdate.h" - -#include "nsCOMArray.h" -#include "nsCOMPtr.h" -#include "nsIDOMDocument.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsIURI.h" -#include "nsString.h" -#include "nsWeakReference.h" - -class nsPIDOMWindowInner; - -namespace mozilla { -namespace docshell { - -class OfflineCacheUpdateChild : public nsIOfflineCacheUpdate - , public POfflineCacheUpdateChild -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOFFLINECACHEUPDATE - - virtual bool - RecvNotifyStateEvent(const uint32_t& stateEvent, - const uint64_t& byteProgress) override; - - virtual bool - RecvAssociateDocuments( - const nsCString& cacheGroupId, - const nsCString& cacheClientId) override; - - virtual bool - RecvFinish(const bool& succeeded, - const bool& isUpgrade) override; - - explicit OfflineCacheUpdateChild(nsPIDOMWindowInner* aWindow); - - void SetDocument(nsIDOMDocument *aDocument); - -private: - ~OfflineCacheUpdateChild(); - - nsresult AssociateDocument(nsIDOMDocument *aDocument, - nsIApplicationCache *aApplicationCache); - void GatherObservers(nsCOMArray<nsIOfflineCacheUpdateObserver> &aObservers); - nsresult Finish(); - - enum { - STATE_UNINITIALIZED, - STATE_INITIALIZED, - STATE_CHECKING, - STATE_DOWNLOADING, - STATE_CANCELLED, - STATE_FINISHED - } mState; - - bool mIsUpgrade; - bool mSucceeded; - - nsCString mUpdateDomain; - nsCOMPtr<nsIURI> mManifestURI; - nsCOMPtr<nsIURI> mDocumentURI; - nsCOMPtr<nsIPrincipal> mLoadingPrincipal; - - nsCOMPtr<nsIObserverService> mObserverService; - - /* Clients watching this update for changes */ - nsCOMArray<nsIWeakReference> mWeakObservers; - nsCOMArray<nsIOfflineCacheUpdateObserver> mObservers; - - /* Document that requested this update */ - nsCOMPtr<nsIDOMDocument> mDocument; - - /* Keep reference to the window that owns this update to call the - parent offline cache update construcor */ - nsCOMPtr<nsPIDOMWindowInner> mWindow; - - uint64_t mByteProgress; -}; - -} // namespace docshell -} // namespace mozilla - -#endif diff --git a/system/docshell/prefetch/OfflineCacheUpdateGlue.cpp b/system/docshell/prefetch/OfflineCacheUpdateGlue.cpp deleted file mode 100644 index 71ca986ff..000000000 --- a/system/docshell/prefetch/OfflineCacheUpdateGlue.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "OfflineCacheUpdateGlue.h" -#include "nsOfflineCacheUpdate.h" -#include "mozilla/Services.h" - -#include "nsIApplicationCache.h" -#include "nsIApplicationCacheChannel.h" -#include "nsIApplicationCacheContainer.h" -#include "nsIChannel.h" -#include "nsIDocument.h" -#include "mozilla/Logging.h" - -// -// To enable logging (see mozilla/Logging.h for full details): -// -// set MOZ_LOG=nsOfflineCacheUpdate:5 -// set MOZ_LOG_FILE=offlineupdate.log -// -// this enables LogLevel::Info level information and places all output in -// the file offlineupdate.log -// -extern mozilla::LazyLogModule gOfflineCacheUpdateLog; - -#undef LOG -#define LOG(args) MOZ_LOG(gOfflineCacheUpdateLog, mozilla::LogLevel::Debug, args) - -#undef LOG_ENABLED -#define LOG_ENABLED() MOZ_LOG_TEST(gOfflineCacheUpdateLog, mozilla::LogLevel::Debug) - -namespace mozilla { -namespace docshell { - -//----------------------------------------------------------------------------- -// OfflineCacheUpdateGlue::nsISupports -//----------------------------------------------------------------------------- - -NS_IMPL_ISUPPORTS(OfflineCacheUpdateGlue, - nsIOfflineCacheUpdate, - nsIOfflineCacheUpdateObserver, - nsISupportsWeakReference) - -//----------------------------------------------------------------------------- -// OfflineCacheUpdateGlue <public> -//----------------------------------------------------------------------------- - -OfflineCacheUpdateGlue::OfflineCacheUpdateGlue() -: mCoalesced(false) -{ - LOG(("OfflineCacheUpdateGlue::OfflineCacheUpdateGlue [%p]", this)); -} - -OfflineCacheUpdateGlue::~OfflineCacheUpdateGlue() -{ - LOG(("OfflineCacheUpdateGlue::~OfflineCacheUpdateGlue [%p]", this)); -} - -nsIOfflineCacheUpdate* -OfflineCacheUpdateGlue::EnsureUpdate() -{ - if (!mUpdate) { - mUpdate = new nsOfflineCacheUpdate(); - LOG(("OfflineCacheUpdateGlue [%p] is using update [%p]", this, mUpdate.get())); - } - - return mUpdate; -} - -NS_IMETHODIMP -OfflineCacheUpdateGlue::Schedule() -{ - nsCOMPtr<nsIObserverService> observerService = - mozilla::services::GetObserverService(); - if (observerService) { - LOG(("Calling offline-cache-update-added")); - observerService->NotifyObservers(static_cast<nsIOfflineCacheUpdate*>(this), - "offline-cache-update-added", - nullptr); - LOG(("Done offline-cache-update-added")); - } - - if (!EnsureUpdate()) - return NS_ERROR_NULL_POINTER; - - // Do not use weak reference, we must survive! - mUpdate->AddObserver(this, false); - - if (mCoalesced) // already scheduled - return NS_OK; - - return mUpdate->Schedule(); -} - -NS_IMETHODIMP -OfflineCacheUpdateGlue::Init(nsIURI *aManifestURI, - nsIURI *aDocumentURI, - nsIPrincipal* aLoadingPrincipal, - nsIDOMDocument *aDocument, - nsIFile *aCustomProfileDir) -{ - nsresult rv; - - nsAutoCString originSuffix; - rv = aLoadingPrincipal->GetOriginSuffix(originSuffix); - NS_ENSURE_SUCCESS(rv, rv); - - nsOfflineCacheUpdateService* service = - nsOfflineCacheUpdateService::EnsureService(); - if (service) { - service->FindUpdate(aManifestURI, originSuffix, aCustomProfileDir, - getter_AddRefs(mUpdate)); - mCoalesced = !!mUpdate; - } - - if (!EnsureUpdate()) - return NS_ERROR_NULL_POINTER; - - mDocumentURI = aDocumentURI; - mLoadingPrincipal = aLoadingPrincipal; - - if (aDocument) - SetDocument(aDocument); - - if (mCoalesced) { // already initialized - LOG(("OfflineCacheUpdateGlue %p coalesced with update %p", this, mUpdate.get())); - return NS_OK; - } - - return mUpdate->Init(aManifestURI, aDocumentURI, aLoadingPrincipal, nullptr, - aCustomProfileDir); -} - -void -OfflineCacheUpdateGlue::SetDocument(nsIDOMDocument *aDocument) -{ - // The design is one document for one cache update on the content process. - NS_ASSERTION(!mDocument, - "Setting more then a single document on an instance of OfflineCacheUpdateGlue"); - - LOG(("Document %p added to update glue %p", aDocument, this)); - - // Add document only if it was not loaded from an offline cache. - // If it were loaded from an offline cache then it has already - // been associated with it and must not be again cached as - // implicit (which are the reasons we collect documents here). - nsCOMPtr<nsIDocument> document = do_QueryInterface(aDocument); - if (!document) - return; - - nsIChannel* channel = document->GetChannel(); - nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel = - do_QueryInterface(channel); - if (!appCacheChannel) - return; - - bool loadedFromAppCache; - appCacheChannel->GetLoadedFromApplicationCache(&loadedFromAppCache); - if (loadedFromAppCache) - return; - - if (EnsureUpdate()) { - mUpdate->StickDocument(mDocumentURI); - } - - mDocument = aDocument; -} - -NS_IMETHODIMP -OfflineCacheUpdateGlue::UpdateStateChanged(nsIOfflineCacheUpdate *aUpdate, uint32_t state) -{ - if (state == nsIOfflineCacheUpdateObserver::STATE_FINISHED) { - LOG(("OfflineCacheUpdateGlue got STATE_FINISHED [%p]", this)); - - nsCOMPtr<nsIObserverService> observerService = - mozilla::services::GetObserverService(); - if (observerService) { - LOG(("Calling offline-cache-update-completed")); - observerService->NotifyObservers(static_cast<nsIOfflineCacheUpdate*>(this), - "offline-cache-update-completed", - nullptr); - LOG(("Done offline-cache-update-completed")); - } - - aUpdate->RemoveObserver(this); - } - - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateGlue::ApplicationCacheAvailable(nsIApplicationCache *aApplicationCache) -{ - NS_ENSURE_ARG(aApplicationCache); - - // Check that the document that requested this update was - // previously associated with an application cache. If not, it - // should be associated with the new one. - nsCOMPtr<nsIApplicationCacheContainer> container = - do_QueryInterface(mDocument); - if (!container) - return NS_OK; - - nsCOMPtr<nsIApplicationCache> existingCache; - nsresult rv = container->GetApplicationCache(getter_AddRefs(existingCache)); - NS_ENSURE_SUCCESS(rv, rv); - - if (!existingCache) { - if (LOG_ENABLED()) { - nsAutoCString clientID; - if (aApplicationCache) { - aApplicationCache->GetClientID(clientID); - } - LOG(("Update %p: associating app cache %s to document %p", - this, clientID.get(), mDocument.get())); - } - - rv = container->SetApplicationCache(aApplicationCache); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; -} - -} // namespace docshell -} // namespace mozilla diff --git a/system/docshell/prefetch/OfflineCacheUpdateGlue.h b/system/docshell/prefetch/OfflineCacheUpdateGlue.h deleted file mode 100644 index 92201ec82..000000000 --- a/system/docshell/prefetch/OfflineCacheUpdateGlue.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsOfflineCacheUpdateGlue_h -#define nsOfflineCacheUpdateGlue_h - -#include "nsIOfflineCacheUpdate.h" - -#include "nsCOMPtr.h" -#include "nsAutoPtr.h" -#include "nsString.h" -#include "nsWeakReference.h" -#include "mozilla/Attributes.h" - -class nsOfflineCacheUpdate; - -namespace mozilla { -namespace docshell { - -// Like FORWARD_SAFE except methods: -// Schedule -// Init -#define NS_ADJUSTED_FORWARD_NSIOFFLINECACHEUPDATE(_to) \ - NS_IMETHOD GetStatus(uint16_t *aStatus) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetStatus(aStatus); } \ - NS_IMETHOD GetPartial(bool *aPartial) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetPartial(aPartial); } \ - NS_IMETHOD GetIsUpgrade(bool *aIsUpgrade) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetIsUpgrade(aIsUpgrade); } \ - NS_IMETHOD GetUpdateDomain(nsACString & aUpdateDomain) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetUpdateDomain(aUpdateDomain); } \ - NS_IMETHOD GetManifestURI(nsIURI **aManifestURI) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetManifestURI(aManifestURI); } \ - NS_IMETHOD GetSucceeded(bool *aSucceeded) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetSucceeded(aSucceeded); } \ - NS_IMETHOD InitPartial(nsIURI *aManifestURI, const nsACString & aClientID, nsIURI *aDocumentURI, nsIPrincipal *aLoadingPrincipal) override { return !_to ? NS_ERROR_NULL_POINTER : _to->InitPartial(aManifestURI, aClientID, aDocumentURI, aLoadingPrincipal); } \ - NS_IMETHOD InitForUpdateCheck(nsIURI *aManifestURI, nsIPrincipal* aLoadingPrincipal, nsIObserver *aObserver) override { return !_to ? NS_ERROR_NULL_POINTER : _to->InitForUpdateCheck(aManifestURI, aLoadingPrincipal, aObserver); } \ - NS_IMETHOD AddDynamicURI(nsIURI *aURI) override { return !_to ? NS_ERROR_NULL_POINTER : _to->AddDynamicURI(aURI); } \ - NS_IMETHOD AddObserver(nsIOfflineCacheUpdateObserver *aObserver, bool aHoldWeak) override { return !_to ? NS_ERROR_NULL_POINTER : _to->AddObserver(aObserver, aHoldWeak); } \ - NS_IMETHOD RemoveObserver(nsIOfflineCacheUpdateObserver *aObserver) override { return !_to ? NS_ERROR_NULL_POINTER : _to->RemoveObserver(aObserver); } \ - NS_IMETHOD GetByteProgress(uint64_t * _result) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetByteProgress(_result); } \ - NS_IMETHOD Cancel() override { return !_to ? NS_ERROR_NULL_POINTER : _to->Cancel(); } - -class OfflineCacheUpdateGlue final : public nsSupportsWeakReference - , public nsIOfflineCacheUpdate - , public nsIOfflineCacheUpdateObserver -{ -public: - NS_DECL_ISUPPORTS - -private: - nsIOfflineCacheUpdate* EnsureUpdate(); - -public: - NS_ADJUSTED_FORWARD_NSIOFFLINECACHEUPDATE(EnsureUpdate()) - NS_IMETHOD Schedule(void) override; - NS_IMETHOD Init(nsIURI *aManifestURI, - nsIURI *aDocumentURI, - nsIPrincipal* aLoadingPrincipal, - nsIDOMDocument *aDocument, - nsIFile *aCustomProfileDir) override; - - NS_DECL_NSIOFFLINECACHEUPDATEOBSERVER - - OfflineCacheUpdateGlue(); - - void SetDocument(nsIDOMDocument *aDocument); - -private: - ~OfflineCacheUpdateGlue(); - - RefPtr<nsOfflineCacheUpdate> mUpdate; - bool mCoalesced; - - /* Document that requested this update */ - nsCOMPtr<nsIDOMDocument> mDocument; - nsCOMPtr<nsIURI> mDocumentURI; - nsCOMPtr<nsIPrincipal> mLoadingPrincipal; -}; - -} // namespace docshell -} // namespace mozilla - -#endif diff --git a/system/docshell/prefetch/OfflineCacheUpdateParent.cpp b/system/docshell/prefetch/OfflineCacheUpdateParent.cpp deleted file mode 100644 index 0381ec3f6..000000000 --- a/system/docshell/prefetch/OfflineCacheUpdateParent.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "OfflineCacheUpdateParent.h" - -#include "BackgroundUtils.h" -#include "mozilla/BasePrincipal.h" -#include "mozilla/dom/TabParent.h" -#include "mozilla/ipc/URIUtils.h" -#include "mozilla/Unused.h" -#include "nsContentUtils.h" -#include "nsOfflineCacheUpdate.h" -#include "nsIApplicationCache.h" -#include "nsIScriptSecurityManager.h" -#include "nsNetUtil.h" - -using namespace mozilla::ipc; -using mozilla::BasePrincipal; -using mozilla::DocShellOriginAttributes; -using mozilla::PrincipalOriginAttributes; -using mozilla::dom::TabParent; - -// -// To enable logging (see mozilla/Logging.h for full details): -// -// set MOZ_LOG=nsOfflineCacheUpdate:5 -// set MOZ_LOG_FILE=offlineupdate.log -// -// this enables LogLevel::Debug level information and places all output in -// the file offlineupdate.log -// -extern mozilla::LazyLogModule gOfflineCacheUpdateLog; - -#undef LOG -#define LOG(args) MOZ_LOG(gOfflineCacheUpdateLog, mozilla::LogLevel::Debug, args) - -#undef LOG_ENABLED -#define LOG_ENABLED() MOZ_LOG_TEST(gOfflineCacheUpdateLog, mozilla::LogLevel::Debug) - -namespace mozilla { -namespace docshell { - -//----------------------------------------------------------------------------- -// OfflineCacheUpdateParent::nsISupports -//----------------------------------------------------------------------------- - -NS_IMPL_ISUPPORTS(OfflineCacheUpdateParent, - nsIOfflineCacheUpdateObserver, - nsILoadContext) - -//----------------------------------------------------------------------------- -// OfflineCacheUpdateParent <public> -//----------------------------------------------------------------------------- - - -OfflineCacheUpdateParent::OfflineCacheUpdateParent() - : mIPCClosed(false) -{ - // Make sure the service has been initialized - nsOfflineCacheUpdateService::EnsureService(); - - LOG(("OfflineCacheUpdateParent::OfflineCacheUpdateParent [%p]", this)); -} - -OfflineCacheUpdateParent::~OfflineCacheUpdateParent() -{ - LOG(("OfflineCacheUpdateParent::~OfflineCacheUpdateParent [%p]", this)); -} - -void -OfflineCacheUpdateParent::ActorDestroy(ActorDestroyReason why) -{ - mIPCClosed = true; -} - -nsresult -OfflineCacheUpdateParent::Schedule(const URIParams& aManifestURI, - const URIParams& aDocumentURI, - const PrincipalInfo& aLoadingPrincipalInfo, - const bool& stickDocument) -{ - LOG(("OfflineCacheUpdateParent::RecvSchedule [%p]", this)); - - nsresult rv; - - RefPtr<nsOfflineCacheUpdate> update; - nsCOMPtr<nsIURI> manifestURI = DeserializeURI(aManifestURI); - if (!manifestURI) - return NS_ERROR_FAILURE; - - mLoadingPrincipal = PrincipalInfoToPrincipal(aLoadingPrincipalInfo, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsOfflineCacheUpdateService* service = - nsOfflineCacheUpdateService::EnsureService(); - if (!service) - return NS_ERROR_FAILURE; - - bool offlinePermissionAllowed = false; - - rv = service->OfflineAppAllowed( - mLoadingPrincipal, nullptr, &offlinePermissionAllowed); - NS_ENSURE_SUCCESS(rv, rv); - - if (!offlinePermissionAllowed) - return NS_ERROR_DOM_SECURITY_ERR; - - nsCOMPtr<nsIURI> documentURI = DeserializeURI(aDocumentURI); - if (!documentURI) - return NS_ERROR_FAILURE; - - if (!NS_SecurityCompareURIs(manifestURI, documentURI, false)) - return NS_ERROR_DOM_SECURITY_ERR; - - nsAutoCString originSuffix; - rv = mLoadingPrincipal->GetOriginSuffix(originSuffix); - NS_ENSURE_SUCCESS(rv, rv); - - service->FindUpdate(manifestURI, - originSuffix, - nullptr, - getter_AddRefs(update)); - if (!update) { - update = new nsOfflineCacheUpdate(); - - // Leave aDocument argument null. Only glues and children keep - // document instances. - rv = update->Init(manifestURI, documentURI, mLoadingPrincipal, nullptr, nullptr); - NS_ENSURE_SUCCESS(rv, rv); - - // Must add before Schedule() call otherwise we would miss - // oncheck event notification. - update->AddObserver(this, false); - - rv = update->Schedule(); - NS_ENSURE_SUCCESS(rv, rv); - } else { - update->AddObserver(this, false); - } - - if (stickDocument) { - nsCOMPtr<nsIURI> stickURI; - documentURI->Clone(getter_AddRefs(stickURI)); - update->StickDocument(stickURI); - } - - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::UpdateStateChanged(nsIOfflineCacheUpdate *aUpdate, uint32_t state) -{ - if (mIPCClosed) - return NS_ERROR_UNEXPECTED; - - LOG(("OfflineCacheUpdateParent::StateEvent [%p]", this)); - - uint64_t byteProgress; - aUpdate->GetByteProgress(&byteProgress); - Unused << SendNotifyStateEvent(state, byteProgress); - - if (state == nsIOfflineCacheUpdateObserver::STATE_FINISHED) { - // Tell the child the particulars after the update has finished. - // Sending the Finish event will release the child side of the protocol - // and notify "offline-cache-update-completed" on the child process. - bool isUpgrade; - aUpdate->GetIsUpgrade(&isUpgrade); - bool succeeded; - aUpdate->GetSucceeded(&succeeded); - - Unused << SendFinish(succeeded, isUpgrade); - } - - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::ApplicationCacheAvailable(nsIApplicationCache *aApplicationCache) -{ - if (mIPCClosed) - return NS_ERROR_UNEXPECTED; - - NS_ENSURE_ARG(aApplicationCache); - - nsCString cacheClientId; - aApplicationCache->GetClientID(cacheClientId); - nsCString cacheGroupId; - aApplicationCache->GetGroupID(cacheGroupId); - - Unused << SendAssociateDocuments(cacheGroupId, cacheClientId); - return NS_OK; -} - -//----------------------------------------------------------------------------- -// OfflineCacheUpdateParent::nsILoadContext -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -OfflineCacheUpdateParent::GetAssociatedWindow(mozIDOMWindowProxy** aAssociatedWindow) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::GetTopWindow(mozIDOMWindowProxy** aTopWindow) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::GetTopFrameElement(nsIDOMElement** aElement) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::GetNestedFrameId(uint64_t* aId) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::GetIsContent(bool *aIsContent) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::GetUsePrivateBrowsing(bool *aUsePrivateBrowsing) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} -NS_IMETHODIMP -OfflineCacheUpdateParent::SetUsePrivateBrowsing(bool aUsePrivateBrowsing) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::SetPrivateBrowsing(bool aUsePrivateBrowsing) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::GetUseRemoteTabs(bool *aUseRemoteTabs) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::SetRemoteTabs(bool aUseRemoteTabs) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::GetIsInIsolatedMozBrowserElement(bool *aIsInIsolatedMozBrowserElement) -{ - NS_ENSURE_TRUE(mLoadingPrincipal, NS_ERROR_UNEXPECTED); - return mLoadingPrincipal->GetIsInIsolatedMozBrowserElement(aIsInIsolatedMozBrowserElement); -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::GetAppId(uint32_t *aAppId) -{ - NS_ENSURE_TRUE(mLoadingPrincipal, NS_ERROR_UNEXPECTED); - return mLoadingPrincipal->GetAppId(aAppId); -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::GetOriginAttributes(JS::MutableHandleValue aAttrs) -{ - NS_ENSURE_TRUE(mLoadingPrincipal, NS_ERROR_UNEXPECTED); - - JSContext* cx = nsContentUtils::GetCurrentJSContext(); - MOZ_ASSERT(cx); - - nsresult rv = mLoadingPrincipal->GetOriginAttributes(cx, aAttrs); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -NS_IMETHODIMP -OfflineCacheUpdateParent::IsTrackingProtectionOn(bool* aIsTrackingProtectionOn) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -} // namespace docshell -} // namespace mozilla diff --git a/system/docshell/prefetch/OfflineCacheUpdateParent.h b/system/docshell/prefetch/OfflineCacheUpdateParent.h deleted file mode 100644 index f6dbc1cb2..000000000 --- a/system/docshell/prefetch/OfflineCacheUpdateParent.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsOfflineCacheUpdateParent_h -#define nsOfflineCacheUpdateParent_h - -#include "mozilla/docshell/POfflineCacheUpdateParent.h" -#include "mozilla/BasePrincipal.h" -#include "nsIOfflineCacheUpdate.h" - -#include "nsCOMPtr.h" -#include "nsString.h" -#include "nsILoadContext.h" - -class nsIPrincipal; - -namespace mozilla { - -namespace ipc { -class URIParams; -} // namespace ipc - -namespace docshell { - -class OfflineCacheUpdateParent : public POfflineCacheUpdateParent - , public nsIOfflineCacheUpdateObserver - , public nsILoadContext -{ - typedef mozilla::ipc::URIParams URIParams; - typedef mozilla::ipc::PrincipalInfo PrincipalInfo; - -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOFFLINECACHEUPDATEOBSERVER - NS_DECL_NSILOADCONTEXT - - nsresult - Schedule(const URIParams& manifestURI, - const URIParams& documentURI, - const PrincipalInfo& loadingPrincipalInfo, - const bool& stickDocument); - - void - StopSendingMessagesToChild() - { - mIPCClosed = true; - } - - explicit OfflineCacheUpdateParent(); - - virtual void ActorDestroy(ActorDestroyReason aWhy) override; -private: - ~OfflineCacheUpdateParent(); - - bool mIPCClosed; - - nsCOMPtr<nsIPrincipal> mLoadingPrincipal; -}; - -} // namespace docshell -} // namespace mozilla - -#endif diff --git a/system/docshell/prefetch/POfflineCacheUpdate.ipdl b/system/docshell/prefetch/POfflineCacheUpdate.ipdl deleted file mode 100644 index 7f1614d81..000000000 --- a/system/docshell/prefetch/POfflineCacheUpdate.ipdl +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -include protocol PContent; - -namespace mozilla { -namespace docshell { - -//------------------------------------------------------------------- -protocol POfflineCacheUpdate -{ - manager PContent; - -parent: - async __delete__(); - -child: - async NotifyStateEvent(uint32_t stateEvent, uint64_t byteProgress); - async AssociateDocuments(nsCString cacheGroupId, nsCString cacheClientId); - async Finish(bool succeeded, bool isUpgrade); -}; - -} -} diff --git a/system/docshell/prefetch/moz.build b/system/docshell/prefetch/moz.build deleted file mode 100644 index d60197953..000000000 --- a/system/docshell/prefetch/moz.build +++ /dev/null @@ -1,44 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -XPIDL_SOURCES += [ - 'nsIOfflineCacheUpdate.idl', - 'nsIPrefetchService.idl', -] - -XPIDL_MODULE = 'prefetch' - -EXPORTS += [ - 'nsCPrefetchService.h', -] - -EXPORTS.mozilla.docshell += [ - 'OfflineCacheUpdateChild.h', - 'OfflineCacheUpdateParent.h', -] - -UNIFIED_SOURCES += [ - 'nsOfflineCacheUpdate.cpp', - 'nsOfflineCacheUpdateService.cpp', - 'nsPrefetchService.cpp', - 'OfflineCacheUpdateChild.cpp', - 'OfflineCacheUpdateGlue.cpp', - 'OfflineCacheUpdateParent.cpp', -] - -IPDL_SOURCES += [ - 'POfflineCacheUpdate.ipdl', -] - -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' - -LOCAL_INCLUDES += [ - '/dom/base', -] - -if CONFIG['GNU_CXX']: - CXXFLAGS += ['-Wno-error=shadow'] diff --git a/system/docshell/prefetch/nsCPrefetchService.h b/system/docshell/prefetch/nsCPrefetchService.h deleted file mode 100644 index d74d89fe7..000000000 --- a/system/docshell/prefetch/nsCPrefetchService.h +++ /dev/null @@ -1,52 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsCPrefetchService_h__ -#define nsCPrefetchService_h__ - -#include "nsIPrefetchService.h" - -/** - * nsPrefetchService : nsIPrefetchService - */ -#define NS_PREFETCHSERVICE_CONTRACTID \ - "@mozilla.org/prefetch-service;1" -#define NS_PREFETCHSERVICE_CID \ -{ /* 6b8bdffc-3394-417d-be83-a81b7c0f63bf */ \ - 0x6b8bdffc, \ - 0x3394, \ - 0x417d, \ - {0xbe, 0x83, 0xa8, 0x1b, 0x7c, 0x0f, 0x63, 0xbf} \ -} - -/** - * nsOfflineCacheUpdateService : nsIOfflineCacheUpdateService - */ - -#define NS_OFFLINECACHEUPDATESERVICE_CONTRACTID \ - "@mozilla.org/offlinecacheupdate-service;1" -#define NS_OFFLINECACHEUPDATESERVICE_CID \ -{ /* ec06f3fc-70db-4ecd-94e0-a6e91ca44d8a */ \ - 0xec06f3fc, \ - 0x70db, \ - 0x4ecd , \ - {0x94, 0xe0, 0xa6, 0xe9, 0x1c, 0xa4, 0x4d, 0x8a} \ -} - -/** - * nsOfflineCacheUpdate : nsIOfflineCacheUpdate - */ - -#define NS_OFFLINECACHEUPDATE_CONTRACTID \ - "@mozilla.org/offlinecacheupdate;1" -#define NS_OFFLINECACHEUPDATE_CID \ -{ /* e56f5e01-c7cc-4675-a9d7-b8f1e4127295 */ \ - 0xe56f5e01, \ - 0xc7cc, \ - 0x4675, \ - {0xa9, 0xd7, 0xb8, 0xf1, 0xe4, 0x12, 0x72, 0x95} \ -} - - -#endif // !nsCPrefetchService_h__ diff --git a/system/docshell/prefetch/nsIOfflineCacheUpdate.idl b/system/docshell/prefetch/nsIOfflineCacheUpdate.idl deleted file mode 100644 index 1308a8de2..000000000 --- a/system/docshell/prefetch/nsIOfflineCacheUpdate.idl +++ /dev/null @@ -1,292 +0,0 @@ -/* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface mozIDOMWindow; -interface nsIURI; -interface nsIDOMNode; -interface nsIDOMDocument; -interface nsIOfflineCacheUpdate; -interface nsIPrincipal; -interface nsIPrefBranch; -interface nsIApplicationCache; -interface nsIFile; -interface nsIObserver; - -[scriptable, uuid(47360d57-8ef4-4a5d-8865-1a27a739ad1a)] -interface nsIOfflineCacheUpdateObserver : nsISupports { - const unsigned long STATE_ERROR = 1; - const unsigned long STATE_CHECKING = 2; - const unsigned long STATE_NOUPDATE = 3; - const unsigned long STATE_OBSOLETE = 4; - const unsigned long STATE_DOWNLOADING = 5; - const unsigned long STATE_ITEMSTARTED = 6; - const unsigned long STATE_ITEMCOMPLETED = 7; - const unsigned long STATE_ITEMPROGRESS = 8; - const unsigned long STATE_FINISHED = 10; - - /** - * aUpdate has changed its state. - * - * @param aUpdate - * The nsIOfflineCacheUpdate being processed. - * @param event - * See enumeration above - */ - void updateStateChanged(in nsIOfflineCacheUpdate aUpdate, in uint32_t state); - - /** - * Informs the observer about an application being available to associate. - * - * @param applicationCache - * The application cache instance that has been created or found by the - * update to associate with - */ - void applicationCacheAvailable(in nsIApplicationCache applicationCache); -}; - -/** - * An nsIOfflineCacheUpdate is used to update an application's offline - * resources. - * - * It can be used to perform partial or complete updates. - * - * One update object will be updating at a time. The active object will - * load its items one by one, sending itemCompleted() to any registered - * observers. - */ -[scriptable, uuid(6e3e26ea-45b2-4db7-9e4a-93b965679298)] -interface nsIOfflineCacheUpdate : nsISupports { - /** - * Fetch the status of the running update. This will return a value - * defined in nsIDOMOfflineResourceList. - */ - readonly attribute unsigned short status; - - /** - * TRUE if the update is being used to add specific resources. - * FALSE if the complete cache update process is happening. - */ - readonly attribute boolean partial; - - /** - * TRUE if this is an upgrade attempt, FALSE if it is a new cache - * attempt. - */ - readonly attribute boolean isUpgrade; - - /** - * The domain being updated, and the domain that will own any URIs added - * with this update. - */ - readonly attribute ACString updateDomain; - - /** - * The manifest for the offline application being updated. - */ - readonly attribute nsIURI manifestURI; - - /** - * TRUE if the cache update completed successfully. - */ - readonly attribute boolean succeeded; - - /** - * Initialize the update. - * - * @param aManifestURI - * The manifest URI to be checked. - * @param aDocumentURI - * The page that is requesting the update. - * @param aLoadingPrincipal - * The principal of the page that is requesting the update. - */ - void init(in nsIURI aManifestURI, - in nsIURI aDocumentURI, - in nsIPrincipal aLoadingPrincipal, - in nsIDOMDocument aDocument, - [optional] in nsIFile aCustomProfileDir); - - /** - * Initialize the update for partial processing. - * - * @param aManifestURI - * The manifest URI of the related cache. - * @param aClientID - * Client ID of the cache to store resource to. This ClientID - * must be ID of cache in the cache group identified by - * the manifest URI passed in the first parameter. - * @param aDocumentURI - * The page that is requesting the update. May be null - * when this information is unknown. - */ - void initPartial(in nsIURI aManifestURI, in ACString aClientID, - in nsIURI aDocumentURI, in nsIPrincipal aPrincipal); - - /** - * Initialize the update to only check whether there is an update - * to the manifest available (if it has actually changed on the server). - * - * @param aManifestURI - * The manifest URI of the related cache. - * @param aObserver - * nsIObserver implementation that receives the result. - * When aTopic == "offline-cache-update-available" there is an update to - * to download. Update of the app cache will lead to a new version - * download. - * When aTopic == "offline-cache-update-unavailable" then there is no - * update available (the manifest has not changed on the server). - */ - void initForUpdateCheck(in nsIURI aManifestURI, - in nsIPrincipal aLoadingPrincipal, - in nsIObserver aObserver); - - /** - * Add a dynamic URI to the offline cache as part of the update. - * - * @param aURI - * The URI to add. - */ - void addDynamicURI(in nsIURI aURI); - - /** - * Add the update to the offline update queue. An offline-cache-update-added - * event will be sent to the observer service. - */ - void schedule(); - - /** - * Observe loads that are added to the update. - * - * @param aObserver - * object that notifications will be sent to. - * @param aHoldWeak - * TRUE if you want the update to hold a weak reference to the - * observer, FALSE for a strong reference. - */ - void addObserver(in nsIOfflineCacheUpdateObserver aObserver, - in boolean aHoldWeak); - - /** - * Remove an observer from the update. - * - * @param aObserver - * the observer to remove. - */ - void removeObserver(in nsIOfflineCacheUpdateObserver aObserver); - - /** - * Cancel the update when still in progress. This stops all running resource - * downloads and discards the downloaded cache version. Throws when update - * has already finished and made the new cache version active. - */ - void cancel(); - - /** - * Return the number of bytes downloaded so far - */ - readonly attribute uint64_t byteProgress; -}; - -[scriptable, uuid(44971e74-37e4-4140-8677-a4cf213a3f4b)] -interface nsIOfflineCacheUpdateService : nsISupports { - /** - * Constants for the offline-app permission. - * - * XXX: This isn't a great place for this, but it's really the only - * private offline-app-related interface - */ - - /** - * Allow the domain to use offline APIs, and don't warn about excessive - * usage. - */ - const unsigned long ALLOW_NO_WARN = 3; - - /** - * Access to the list of cache updates that have been scheduled. - */ - readonly attribute unsigned long numUpdates; - nsIOfflineCacheUpdate getUpdate(in unsigned long index); - - /** - * Schedule a cache update for a given offline manifest. If an - * existing update is scheduled or running, that update will be returned. - * Otherwise a new update will be scheduled. - */ - nsIOfflineCacheUpdate scheduleUpdate(in nsIURI aManifestURI, - in nsIURI aDocumentURI, - in nsIPrincipal aLoadingPrincipal, - in mozIDOMWindow aWindow); - - /** - * Schedule a cache update for a given offline manifest using app cache - * bound to the given appID+inIsolatedMozBrowser flag. If an existing update - * is scheduled or running, that update will be returned. Otherwise a new - * update will be scheduled. - */ - nsIOfflineCacheUpdate scheduleAppUpdate(in nsIURI aManifestURI, - in nsIURI aDocumentURI, - in nsIPrincipal aLoadingPrincipal, - in nsIFile aProfileDir); - - /** - * Schedule a cache update for a manifest when the document finishes - * loading. - */ - void scheduleOnDocumentStop(in nsIURI aManifestURI, - in nsIURI aDocumentURI, - in nsIPrincipal aLoadingPrincipal, - in nsIDOMDocument aDocument); - - /** - * Schedule a check to see if an update is available. - * - * This will not update or make any changes to the appcache. - * It only notifies the observer to indicate whether the manifest has - * changed on the server (or not): a changed manifest means that an - * update is available. - * - * For arguments see nsIOfflineCacheUpdate.initForUpdateCheck() method - * description. - */ - void checkForUpdate(in nsIURI aManifestURI, - in nsIPrincipal aLoadingPrincipal, - in nsIObserver aObserver); - - /** - * Checks whether a principal should have access to the offline - * cache. - * @param aPrincipal - * The principal to check. - * @param aPrefBranch - * The pref branch to use to check the - * offline-apps.allow_by_default pref. If not specified, - * the pref service will be used. - */ - boolean offlineAppAllowed(in nsIPrincipal aPrincipal, - in nsIPrefBranch aPrefBranch); - - /** - * Checks whether a document at the given URI should have access - * to the offline cache. - * @param aURI - * The URI to check - * @param aPrefBranch - * The pref branch to use to check the - * offline-apps.allow_by_default pref. If not specified, - * the pref service will be used. - */ - boolean offlineAppAllowedForURI(in nsIURI aURI, - in nsIPrefBranch aPrefBranch); - - /** - * Sets the "offline-app" permission for the principal. - * In the single process model calls directly on permission manager. - * In the multi process model dispatches to the parent process. - */ - void allowOfflineApp(in nsIPrincipal aPrincipal); -}; diff --git a/system/docshell/prefetch/nsIPrefetchService.idl b/system/docshell/prefetch/nsIPrefetchService.idl deleted file mode 100644 index 198320dd2..000000000 --- a/system/docshell/prefetch/nsIPrefetchService.idl +++ /dev/null @@ -1,37 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsIURI; -interface nsIDOMNode; -interface nsISimpleEnumerator; - -[scriptable, uuid(422a1807-4e7f-463d-b8d7-ca2ceb9b5d53)] -interface nsIPrefetchService : nsISupports -{ - /** - * Enqueue a request to prefetch the specified URI. - * - * @param aURI the URI of the document to prefetch - * @param aReferrerURI the URI of the referring page - * @param aSource the DOM node (such as a <link> tag) that requested this - * fetch, or null if the prefetch was not requested by a DOM node. - * @param aExplicit the link element has an explicit prefetch link type - */ - void prefetchURI(in nsIURI aURI, - in nsIURI aReferrerURI, - in nsIDOMNode aSource, - in boolean aExplicit); - - /** - * Find out if there are any prefetches running or queued - */ - boolean hasMoreElements(); - - /** - * Cancel prefetch - */ - void cancelPrefetchURI(in nsIURI aURI, in nsIDOMNode aSource); -}; diff --git a/system/docshell/prefetch/nsOfflineCacheUpdate.cpp b/system/docshell/prefetch/nsOfflineCacheUpdate.cpp deleted file mode 100644 index 8a4183429..000000000 --- a/system/docshell/prefetch/nsOfflineCacheUpdate.cpp +++ /dev/null @@ -1,2479 +0,0 @@ -/* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsOfflineCacheUpdate.h" - -#include "nsCPrefetchService.h" -#include "nsCURILoader.h" -#include "nsIApplicationCacheContainer.h" -#include "nsIApplicationCacheChannel.h" -#include "nsIApplicationCacheService.h" -#include "nsICachingChannel.h" -#include "nsIContent.h" -#include "mozilla/dom/Element.h" -#include "nsIDocumentLoader.h" -#include "nsIDOMElement.h" -#include "nsIDOMWindow.h" -#include "nsIDOMOfflineResourceList.h" -#include "nsIDocument.h" -#include "nsIObserverService.h" -#include "nsIURL.h" -#include "nsIWebProgress.h" -#include "nsICryptoHash.h" -#include "nsICacheEntry.h" -#include "nsIPermissionManager.h" -#include "nsIPrincipal.h" -#include "nsNetCID.h" -#include "nsNetUtil.h" -#include "nsServiceManagerUtils.h" -#include "nsStreamUtils.h" -#include "nsThreadUtils.h" -#include "nsProxyRelease.h" -#include "nsIConsoleService.h" -#include "mozilla/Logging.h" -#include "nsIAsyncVerifyRedirectCallback.h" -#include "mozilla/Preferences.h" -#include "mozilla/Attributes.h" -#include "nsContentUtils.h" -#include "nsIPrincipal.h" - -#include "nsXULAppAPI.h" - -using namespace mozilla; - -static const uint32_t kRescheduleLimit = 3; -// Max number of retries for every entry of pinned app. -static const uint32_t kPinnedEntryRetriesLimit = 3; -// Maximum number of parallel items loads -static const uint32_t kParallelLoadLimit = 15; - -// Quota for offline apps when preloading -static const int32_t kCustomProfileQuota = 512000; - -// -// To enable logging (see mozilla/Logging.h for full details): -// -// set MOZ_LOG=nsOfflineCacheUpdate:5 -// set MOZ_LOG_FILE=offlineupdate.log -// -// this enables LogLevel::Debug level information and places all output in -// the file offlineupdate.log -// -extern LazyLogModule gOfflineCacheUpdateLog; - -#undef LOG -#define LOG(args) MOZ_LOG(gOfflineCacheUpdateLog, mozilla::LogLevel::Debug, args) - -#undef LOG_ENABLED -#define LOG_ENABLED() MOZ_LOG_TEST(gOfflineCacheUpdateLog, mozilla::LogLevel::Debug) - -class AutoFreeArray { -public: - AutoFreeArray(uint32_t count, char **values) - : mCount(count), mValues(values) {}; - ~AutoFreeArray() { NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mCount, mValues); } -private: - uint32_t mCount; - char **mValues; -}; - -namespace { - -nsresult -DropReferenceFromURL(nsIURI * aURI) -{ - // XXXdholbert If this SetRef fails, callers of this method probably - // want to call aURI->CloneIgnoringRef() and use the result of that. - return aURI->SetRef(EmptyCString()); -} - -void -LogToConsole(const char * message, nsOfflineCacheUpdateItem * item = nullptr) -{ - nsCOMPtr<nsIConsoleService> consoleService = - do_GetService(NS_CONSOLESERVICE_CONTRACTID); - if (consoleService) - { - nsAutoString messageUTF16 = NS_ConvertUTF8toUTF16(message); - if (item && item->mURI) { - messageUTF16.AppendLiteral(", URL="); - messageUTF16.Append( - NS_ConvertUTF8toUTF16(item->mURI->GetSpecOrDefault())); - } - consoleService->LogStringMessage(messageUTF16.get()); - } -} - -} // namespace - -//----------------------------------------------------------------------------- -// nsManifestCheck -//----------------------------------------------------------------------------- - -class nsManifestCheck final : public nsIStreamListener - , public nsIChannelEventSink - , public nsIInterfaceRequestor -{ -public: - nsManifestCheck(nsOfflineCacheUpdate *aUpdate, - nsIURI *aURI, - nsIURI *aReferrerURI, - nsIPrincipal* aLoadingPrincipal) - : mUpdate(aUpdate) - , mURI(aURI) - , mReferrerURI(aReferrerURI) - , mLoadingPrincipal(aLoadingPrincipal) - {} - - NS_DECL_ISUPPORTS - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSICHANNELEVENTSINK - NS_DECL_NSIINTERFACEREQUESTOR - - nsresult Begin(); - -private: - - ~nsManifestCheck() {} - - static nsresult ReadManifest(nsIInputStream *aInputStream, - void *aClosure, - const char *aFromSegment, - uint32_t aOffset, - uint32_t aCount, - uint32_t *aBytesConsumed); - - RefPtr<nsOfflineCacheUpdate> mUpdate; - nsCOMPtr<nsIURI> mURI; - nsCOMPtr<nsIURI> mReferrerURI; - nsCOMPtr<nsIPrincipal> mLoadingPrincipal; - nsCOMPtr<nsICryptoHash> mManifestHash; - nsCOMPtr<nsIChannel> mChannel; -}; - -//----------------------------------------------------------------------------- -// nsManifestCheck::nsISupports -//----------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS(nsManifestCheck, - nsIRequestObserver, - nsIStreamListener, - nsIChannelEventSink, - nsIInterfaceRequestor) - -//----------------------------------------------------------------------------- -// nsManifestCheck <public> -//----------------------------------------------------------------------------- - -nsresult -nsManifestCheck::Begin() -{ - nsresult rv; - mManifestHash = do_CreateInstance("@mozilla.org/security/hash;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mManifestHash->Init(nsICryptoHash::MD5); - NS_ENSURE_SUCCESS(rv, rv); - rv = NS_NewChannel(getter_AddRefs(mChannel), - mURI, - mLoadingPrincipal, - nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED, - nsIContentPolicy::TYPE_OTHER, - nullptr, // loadGroup - nullptr, // aCallbacks - nsIRequest::LOAD_BYPASS_CACHE); - - NS_ENSURE_SUCCESS(rv, rv); - - // configure HTTP specific stuff - nsCOMPtr<nsIHttpChannel> httpChannel = - do_QueryInterface(mChannel); - if (httpChannel) { - httpChannel->SetReferrer(mReferrerURI); - httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"), - NS_LITERAL_CSTRING("offline-resource"), - false); - } - - return mChannel->AsyncOpen2(this); -} - -//----------------------------------------------------------------------------- -// nsManifestCheck <public> -//----------------------------------------------------------------------------- - -/* static */ nsresult -nsManifestCheck::ReadManifest(nsIInputStream *aInputStream, - void *aClosure, - const char *aFromSegment, - uint32_t aOffset, - uint32_t aCount, - uint32_t *aBytesConsumed) -{ - nsManifestCheck *manifestCheck = - static_cast<nsManifestCheck*>(aClosure); - - nsresult rv; - *aBytesConsumed = aCount; - - rv = manifestCheck->mManifestHash->Update( - reinterpret_cast<const uint8_t *>(aFromSegment), aCount); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsManifestCheck::nsIStreamListener -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsManifestCheck::OnStartRequest(nsIRequest *aRequest, - nsISupports *aContext) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsManifestCheck::OnDataAvailable(nsIRequest *aRequest, - nsISupports *aContext, - nsIInputStream *aStream, - uint64_t aOffset, - uint32_t aCount) -{ - uint32_t bytesRead; - aStream->ReadSegments(ReadManifest, this, aCount, &bytesRead); - return NS_OK; -} - -NS_IMETHODIMP -nsManifestCheck::OnStopRequest(nsIRequest *aRequest, - nsISupports *aContext, - nsresult aStatus) -{ - nsAutoCString manifestHash; - if (NS_SUCCEEDED(aStatus)) { - mManifestHash->Finish(true, manifestHash); - } - - mUpdate->ManifestCheckCompleted(aStatus, manifestHash); - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsManifestCheck::nsIInterfaceRequestor -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsManifestCheck::GetInterface(const nsIID &aIID, void **aResult) -{ - if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) { - NS_ADDREF_THIS(); - *aResult = static_cast<nsIChannelEventSink *>(this); - return NS_OK; - } - - return NS_ERROR_NO_INTERFACE; -} - -//----------------------------------------------------------------------------- -// nsManifestCheck::nsIChannelEventSink -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsManifestCheck::AsyncOnChannelRedirect(nsIChannel *aOldChannel, - nsIChannel *aNewChannel, - uint32_t aFlags, - nsIAsyncVerifyRedirectCallback *callback) -{ - // Redirects should cause the load (and therefore the update) to fail. - if (aFlags & nsIChannelEventSink::REDIRECT_INTERNAL) { - callback->OnRedirectVerifyCallback(NS_OK); - return NS_OK; - } - - LogToConsole("Manifest check failed because its response is a redirect"); - - aOldChannel->Cancel(NS_ERROR_ABORT); - return NS_ERROR_ABORT; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateItem::nsISupports -//----------------------------------------------------------------------------- - -NS_IMPL_ISUPPORTS(nsOfflineCacheUpdateItem, - nsIRequestObserver, - nsIStreamListener, - nsIRunnable, - nsIInterfaceRequestor, - nsIChannelEventSink) - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateItem <public> -//----------------------------------------------------------------------------- - -nsOfflineCacheUpdateItem::nsOfflineCacheUpdateItem(nsIURI *aURI, - nsIURI *aReferrerURI, - nsIPrincipal* aLoadingPrincipal, - nsIApplicationCache *aApplicationCache, - nsIApplicationCache *aPreviousApplicationCache, - uint32_t type, - uint32_t loadFlags) - : mURI(aURI) - , mReferrerURI(aReferrerURI) - , mLoadingPrincipal(aLoadingPrincipal) - , mApplicationCache(aApplicationCache) - , mPreviousApplicationCache(aPreviousApplicationCache) - , mItemType(type) - , mLoadFlags(loadFlags) - , mChannel(nullptr) - , mState(LoadStatus::UNINITIALIZED) - , mBytesRead(0) -{ -} - -nsOfflineCacheUpdateItem::~nsOfflineCacheUpdateItem() -{ -} - -nsresult -nsOfflineCacheUpdateItem::OpenChannel(nsOfflineCacheUpdate *aUpdate) -{ - if (LOG_ENABLED()) { - LOG(("%p: Opening channel for %s", this, - mURI->GetSpecOrDefault().get())); - } - - if (mUpdate) { - // Holding a reference to the update means this item is already - // in progress (has a channel, or is just in between OnStopRequest() - // and its Run() call. We must never open channel on this item again. - LOG((" %p is already running! ignoring", this)); - return NS_ERROR_ALREADY_OPENED; - } - - nsresult rv = nsOfflineCacheUpdate::GetCacheKey(mURI, mCacheKey); - NS_ENSURE_SUCCESS(rv, rv); - - uint32_t flags = nsIRequest::LOAD_BACKGROUND | - nsICachingChannel::LOAD_ONLY_IF_MODIFIED; - - if (mApplicationCache == mPreviousApplicationCache) { - // Same app cache to read from and to write to is used during - // an only-update-check procedure. Here we protect the existing - // cache from being modified. - flags |= nsIRequest::INHIBIT_CACHING; - } - - flags |= mLoadFlags; - - rv = NS_NewChannel(getter_AddRefs(mChannel), - mURI, - mLoadingPrincipal, - nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, - nsIContentPolicy::TYPE_OTHER, - nullptr, // aLoadGroup - this, // aCallbacks - flags); - - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel = - do_QueryInterface(mChannel, &rv); - - // Support for nsIApplicationCacheChannel is required. - NS_ENSURE_SUCCESS(rv, rv); - - // Use the existing application cache as the cache to check. - rv = appCacheChannel->SetApplicationCache(mPreviousApplicationCache); - NS_ENSURE_SUCCESS(rv, rv); - - // Set the new application cache as the target for write. - rv = appCacheChannel->SetApplicationCacheForWrite(mApplicationCache); - NS_ENSURE_SUCCESS(rv, rv); - - // configure HTTP specific stuff - nsCOMPtr<nsIHttpChannel> httpChannel = - do_QueryInterface(mChannel); - if (httpChannel) { - httpChannel->SetReferrer(mReferrerURI); - httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"), - NS_LITERAL_CSTRING("offline-resource"), - false); - } - - rv = mChannel->AsyncOpen2(this); - NS_ENSURE_SUCCESS(rv, rv); - - mUpdate = aUpdate; - - mState = LoadStatus::REQUESTED; - - return NS_OK; -} - -nsresult -nsOfflineCacheUpdateItem::Cancel() -{ - if (mChannel) { - mChannel->Cancel(NS_ERROR_ABORT); - mChannel = nullptr; - } - - mState = LoadStatus::UNINITIALIZED; - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateItem::nsIStreamListener -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsOfflineCacheUpdateItem::OnStartRequest(nsIRequest *aRequest, - nsISupports *aContext) -{ - mState = LoadStatus::RECEIVING; - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdateItem::OnDataAvailable(nsIRequest *aRequest, - nsISupports *aContext, - nsIInputStream *aStream, - uint64_t aOffset, - uint32_t aCount) -{ - uint32_t bytesRead = 0; - aStream->ReadSegments(NS_DiscardSegment, nullptr, aCount, &bytesRead); - mBytesRead += bytesRead; - LOG(("loaded %u bytes into offline cache [offset=%llu]\n", - bytesRead, aOffset)); - - mUpdate->OnByteProgress(bytesRead); - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdateItem::OnStopRequest(nsIRequest *aRequest, - nsISupports *aContext, - nsresult aStatus) -{ - if (LOG_ENABLED()) { - LOG(("%p: Done fetching offline item %s [status=%x]\n", - this, mURI->GetSpecOrDefault().get(), aStatus)); - } - - if (mBytesRead == 0 && aStatus == NS_OK) { - // we didn't need to read (because LOAD_ONLY_IF_MODIFIED was - // specified), but the object should report loadedSize as if it - // did. - mChannel->GetContentLength(&mBytesRead); - mUpdate->OnByteProgress(mBytesRead); - } - - if (NS_FAILED(aStatus)) { - nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel); - if (httpChannel) { - bool isNoStore; - if (NS_SUCCEEDED(httpChannel->IsNoStoreResponse(&isNoStore)) - && isNoStore) { - LogToConsole("Offline cache manifest item has Cache-control: no-store header", - this); - } - } - } - - // We need to notify the update that the load is complete, but we - // want to give the channel a chance to close the cache entries. - NS_DispatchToCurrentThread(this); - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateItem::nsIRunnable -//----------------------------------------------------------------------------- -NS_IMETHODIMP -nsOfflineCacheUpdateItem::Run() -{ - // Set mState to LOADED here rather than in OnStopRequest to prevent - // race condition when checking state of all mItems in ProcessNextURI(). - // If state would have been set in OnStopRequest we could mistakenly - // take this item as already finished and finish the update process too - // early when ProcessNextURI() would get called between OnStopRequest() - // and Run() of this item. Finish() would then have been called twice. - mState = LoadStatus::LOADED; - - RefPtr<nsOfflineCacheUpdate> update; - update.swap(mUpdate); - update->LoadCompleted(this); - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateItem::nsIInterfaceRequestor -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsOfflineCacheUpdateItem::GetInterface(const nsIID &aIID, void **aResult) -{ - if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) { - NS_ADDREF_THIS(); - *aResult = static_cast<nsIChannelEventSink *>(this); - return NS_OK; - } - - return NS_ERROR_NO_INTERFACE; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateItem::nsIChannelEventSink -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsOfflineCacheUpdateItem::AsyncOnChannelRedirect(nsIChannel *aOldChannel, - nsIChannel *aNewChannel, - uint32_t aFlags, - nsIAsyncVerifyRedirectCallback *cb) -{ - if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) { - // Don't allow redirect in case of non-internal redirect and cancel - // the channel to clean the cache entry. - LogToConsole("Offline cache manifest failed because an item redirects", this); - - aOldChannel->Cancel(NS_ERROR_ABORT); - return NS_ERROR_ABORT; - } - - nsCOMPtr<nsIURI> newURI; - nsresult rv = aNewChannel->GetURI(getter_AddRefs(newURI)); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel = - do_QueryInterface(aNewChannel); - if (appCacheChannel) { - rv = appCacheChannel->SetApplicationCacheForWrite(mApplicationCache); - NS_ENSURE_SUCCESS(rv, rv); - } - - nsAutoCString oldScheme; - mURI->GetScheme(oldScheme); - - bool match; - if (NS_FAILED(newURI->SchemeIs(oldScheme.get(), &match)) || !match) { - LOG(("rejected: redirected to a different scheme\n")); - return NS_ERROR_ABORT; - } - - // HTTP request headers are not automatically forwarded to the new channel. - nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aNewChannel); - NS_ENSURE_STATE(httpChannel); - - httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"), - NS_LITERAL_CSTRING("offline-resource"), - false); - - mChannel = aNewChannel; - - cb->OnRedirectVerifyCallback(NS_OK); - return NS_OK; -} - -nsresult -nsOfflineCacheUpdateItem::GetRequestSucceeded(bool * succeeded) -{ - *succeeded = false; - - if (!mChannel) - return NS_OK; - - nsresult rv; - nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - bool reqSucceeded; - rv = httpChannel->GetRequestSucceeded(&reqSucceeded); - if (NS_ERROR_NOT_AVAILABLE == rv) - return NS_OK; - NS_ENSURE_SUCCESS(rv, rv); - - if (!reqSucceeded) { - LOG(("Request failed")); - return NS_OK; - } - - nsresult channelStatus; - rv = httpChannel->GetStatus(&channelStatus); - NS_ENSURE_SUCCESS(rv, rv); - - if (NS_FAILED(channelStatus)) { - LOG(("Channel status=0x%08x", channelStatus)); - return NS_OK; - } - - *succeeded = true; - return NS_OK; -} - -bool -nsOfflineCacheUpdateItem::IsScheduled() -{ - return mState == LoadStatus::UNINITIALIZED; -} - -bool -nsOfflineCacheUpdateItem::IsInProgress() -{ - return mState == LoadStatus::REQUESTED || - mState == LoadStatus::RECEIVING; -} - -bool -nsOfflineCacheUpdateItem::IsCompleted() -{ - return mState == LoadStatus::LOADED; -} - -nsresult -nsOfflineCacheUpdateItem::GetStatus(uint16_t *aStatus) -{ - if (!mChannel) { - *aStatus = 0; - return NS_OK; - } - - nsresult rv; - nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - uint32_t httpStatus; - rv = httpChannel->GetResponseStatus(&httpStatus); - if (rv == NS_ERROR_NOT_AVAILABLE) { - *aStatus = 0; - return NS_OK; - } - - NS_ENSURE_SUCCESS(rv, rv); - *aStatus = uint16_t(httpStatus); - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsOfflineManifestItem -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// nsOfflineManifestItem <public> -//----------------------------------------------------------------------------- - -nsOfflineManifestItem::nsOfflineManifestItem(nsIURI *aURI, - nsIURI *aReferrerURI, - nsIPrincipal* aLoadingPrincipal, - nsIApplicationCache *aApplicationCache, - nsIApplicationCache *aPreviousApplicationCache) - : nsOfflineCacheUpdateItem(aURI, aReferrerURI, aLoadingPrincipal, - aApplicationCache, aPreviousApplicationCache, - nsIApplicationCache::ITEM_MANIFEST, 0) - , mParserState(PARSE_INIT) - , mNeedsUpdate(true) - , mStrictFileOriginPolicy(false) - , mManifestHashInitialized(false) -{ - ReadStrictFileOriginPolicyPref(); -} - -nsOfflineManifestItem::~nsOfflineManifestItem() -{ -} - -//----------------------------------------------------------------------------- -// nsOfflineManifestItem <private> -//----------------------------------------------------------------------------- - -/* static */ -nsresult -nsOfflineManifestItem::ReadManifest(nsIInputStream *aInputStream, - void *aClosure, - const char *aFromSegment, - uint32_t aOffset, - uint32_t aCount, - uint32_t *aBytesConsumed) -{ - nsOfflineManifestItem *manifest = - static_cast<nsOfflineManifestItem*>(aClosure); - - nsresult rv; - - *aBytesConsumed = aCount; - - if (manifest->mParserState == PARSE_ERROR) { - // parse already failed, ignore this - return NS_OK; - } - - if (!manifest->mManifestHashInitialized) { - // Avoid re-creation of crypto hash when it fails from some reason the first time - manifest->mManifestHashInitialized = true; - - manifest->mManifestHash = do_CreateInstance("@mozilla.org/security/hash;1", &rv); - if (NS_SUCCEEDED(rv)) { - rv = manifest->mManifestHash->Init(nsICryptoHash::MD5); - if (NS_FAILED(rv)) { - manifest->mManifestHash = nullptr; - LOG(("Could not initialize manifest hash for byte-to-byte check, rv=%08x", rv)); - } - } - } - - if (manifest->mManifestHash) { - rv = manifest->mManifestHash->Update(reinterpret_cast<const uint8_t *>(aFromSegment), aCount); - if (NS_FAILED(rv)) { - manifest->mManifestHash = nullptr; - LOG(("Could not update manifest hash, rv=%08x", rv)); - } - } - - manifest->mReadBuf.Append(aFromSegment, aCount); - - nsCString::const_iterator begin, iter, end; - manifest->mReadBuf.BeginReading(begin); - manifest->mReadBuf.EndReading(end); - - for (iter = begin; iter != end; iter++) { - if (*iter == '\r' || *iter == '\n') { - rv = manifest->HandleManifestLine(begin, iter); - - if (NS_FAILED(rv)) { - LOG(("HandleManifestLine failed with 0x%08x", rv)); - *aBytesConsumed = 0; // Avoid assertion failure in stream tee - return NS_ERROR_ABORT; - } - - begin = iter; - begin++; - } - } - - // any leftovers are saved for next time - manifest->mReadBuf = Substring(begin, end); - - return NS_OK; -} - -nsresult -nsOfflineManifestItem::AddNamespace(uint32_t namespaceType, - const nsCString &namespaceSpec, - const nsCString &data) - -{ - nsresult rv; - if (!mNamespaces) { - mNamespaces = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - } - - nsCOMPtr<nsIApplicationCacheNamespace> ns = - do_CreateInstance(NS_APPLICATIONCACHENAMESPACE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = ns->Init(namespaceType, namespaceSpec, data); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mNamespaces->AppendElement(ns, false); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -nsresult -nsOfflineManifestItem::HandleManifestLine(const nsCString::const_iterator &aBegin, - const nsCString::const_iterator &aEnd) -{ - nsCString::const_iterator begin = aBegin; - nsCString::const_iterator end = aEnd; - - // all lines ignore trailing spaces and tabs - nsCString::const_iterator last = end; - --last; - while (end != begin && (*last == ' ' || *last == '\t')) { - --end; - --last; - } - - if (mParserState == PARSE_INIT) { - // Allow a UTF-8 BOM - if (begin != end && static_cast<unsigned char>(*begin) == 0xef) { - if (++begin == end || static_cast<unsigned char>(*begin) != 0xbb || - ++begin == end || static_cast<unsigned char>(*begin) != 0xbf) { - mParserState = PARSE_ERROR; - LogToConsole("Offline cache manifest BOM error", this); - return NS_OK; - } - ++begin; - } - - const nsCSubstring &magic = Substring(begin, end); - - if (!magic.EqualsLiteral("CACHE MANIFEST")) { - mParserState = PARSE_ERROR; - LogToConsole("Offline cache manifest magic incorrect", this); - return NS_OK; - } - - mParserState = PARSE_CACHE_ENTRIES; - return NS_OK; - } - - // lines other than the first ignore leading spaces and tabs - while (begin != end && (*begin == ' ' || *begin == '\t')) - begin++; - - // ignore blank lines and comments - if (begin == end || *begin == '#') - return NS_OK; - - const nsCSubstring &line = Substring(begin, end); - - if (line.EqualsLiteral("CACHE:")) { - mParserState = PARSE_CACHE_ENTRIES; - return NS_OK; - } - - if (line.EqualsLiteral("FALLBACK:")) { - mParserState = PARSE_FALLBACK_ENTRIES; - return NS_OK; - } - - if (line.EqualsLiteral("NETWORK:")) { - mParserState = PARSE_BYPASS_ENTRIES; - return NS_OK; - } - - // Every other section type we don't know must be silently ignored. - nsCString::const_iterator lastChar = end; - if (*(--lastChar) == ':') { - mParserState = PARSE_UNKNOWN_SECTION; - return NS_OK; - } - - nsresult rv; - - switch(mParserState) { - case PARSE_INIT: - case PARSE_ERROR: { - // this should have been dealt with earlier - return NS_ERROR_FAILURE; - } - - case PARSE_UNKNOWN_SECTION: { - // just jump over - return NS_OK; - } - - case PARSE_CACHE_ENTRIES: { - nsCOMPtr<nsIURI> uri; - rv = NS_NewURI(getter_AddRefs(uri), line, nullptr, mURI); - if (NS_FAILED(rv)) - break; - if (NS_FAILED(DropReferenceFromURL(uri))) - break; - - nsAutoCString scheme; - uri->GetScheme(scheme); - - // Manifest URIs must have the same scheme as the manifest. - bool match; - if (NS_FAILED(mURI->SchemeIs(scheme.get(), &match)) || !match) - break; - - mExplicitURIs.AppendObject(uri); - - if (!NS_SecurityCompareURIs(mURI, uri, - mStrictFileOriginPolicy)) { - mAnonymousURIs.AppendObject(uri); - } - - break; - } - - case PARSE_FALLBACK_ENTRIES: { - int32_t separator = line.FindChar(' '); - if (separator == kNotFound) { - separator = line.FindChar('\t'); - if (separator == kNotFound) - break; - } - - nsCString namespaceSpec(Substring(line, 0, separator)); - nsCString fallbackSpec(Substring(line, separator + 1)); - namespaceSpec.CompressWhitespace(); - fallbackSpec.CompressWhitespace(); - - nsCOMPtr<nsIURI> namespaceURI; - rv = NS_NewURI(getter_AddRefs(namespaceURI), namespaceSpec, nullptr, mURI); - if (NS_FAILED(rv)) - break; - if (NS_FAILED(DropReferenceFromURL(namespaceURI))) - break; - rv = namespaceURI->GetAsciiSpec(namespaceSpec); - if (NS_FAILED(rv)) - break; - - nsCOMPtr<nsIURI> fallbackURI; - rv = NS_NewURI(getter_AddRefs(fallbackURI), fallbackSpec, nullptr, mURI); - if (NS_FAILED(rv)) - break; - if (NS_FAILED(DropReferenceFromURL(fallbackURI))) - break; - rv = fallbackURI->GetAsciiSpec(fallbackSpec); - if (NS_FAILED(rv)) - break; - - // Manifest and namespace must be same origin - if (!NS_SecurityCompareURIs(mURI, namespaceURI, - mStrictFileOriginPolicy)) - break; - - // Fallback and namespace must be same origin - if (!NS_SecurityCompareURIs(namespaceURI, fallbackURI, - mStrictFileOriginPolicy)) - break; - - // Check fallback path for disallowed encoded path separators
- nsAutoCString path;
- fallbackURI->GetFilePath(path);
- if (path.Find("%2f") != kNotFound || path.Find("%2F") != kNotFound) {
- LogToConsole("Offline cache manifest bad fallback path", this);
- break;
- }
- - mFallbackURIs.AppendObject(fallbackURI); - - AddNamespace(nsIApplicationCacheNamespace::NAMESPACE_FALLBACK, - namespaceSpec, fallbackSpec); - break; - } - - case PARSE_BYPASS_ENTRIES: { - if (line[0] == '*' && (line.Length() == 1 || line[1] == ' ' || line[1] == '\t')) - { - // '*' indicates to make the online whitelist wildcard flag open, - // i.e. do allow load of resources not present in the offline cache - // or not conforming any namespace. - // We achive that simply by adding an 'empty' - i.e. universal - // namespace of BYPASS type into the cache. - AddNamespace(nsIApplicationCacheNamespace::NAMESPACE_BYPASS, - EmptyCString(), EmptyCString()); - break; - } - - nsCOMPtr<nsIURI> bypassURI; - rv = NS_NewURI(getter_AddRefs(bypassURI), line, nullptr, mURI); - if (NS_FAILED(rv)) - break; - - nsAutoCString scheme; - bypassURI->GetScheme(scheme); - bool equals; - if (NS_FAILED(mURI->SchemeIs(scheme.get(), &equals)) || !equals) - break; - if (NS_FAILED(DropReferenceFromURL(bypassURI))) - break; - nsCString spec; - if (NS_FAILED(bypassURI->GetAsciiSpec(spec))) - break; - - AddNamespace(nsIApplicationCacheNamespace::NAMESPACE_BYPASS, - spec, EmptyCString()); - break; - } - } - - return NS_OK; -} - -nsresult -nsOfflineManifestItem::GetOldManifestContentHash(nsIRequest *aRequest) -{ - nsresult rv; - - nsCOMPtr<nsICachingChannel> cachingChannel = do_QueryInterface(aRequest, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - // load the main cache token that is actually the old offline cache token and - // read previous manifest content hash value - nsCOMPtr<nsISupports> cacheToken; - cachingChannel->GetCacheToken(getter_AddRefs(cacheToken)); - if (cacheToken) { - nsCOMPtr<nsICacheEntry> cacheDescriptor(do_QueryInterface(cacheToken, &rv)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = cacheDescriptor->GetMetaDataElement("offline-manifest-hash", getter_Copies(mOldManifestHashValue)); - if (NS_FAILED(rv)) - mOldManifestHashValue.Truncate(); - } - - return NS_OK; -} - -nsresult -nsOfflineManifestItem::CheckNewManifestContentHash(nsIRequest *aRequest) -{ - nsresult rv; - - if (!mManifestHash) { - // Nothing to compare against... - return NS_OK; - } - - nsCString newManifestHashValue; - rv = mManifestHash->Finish(true, mManifestHashValue); - mManifestHash = nullptr; - - if (NS_FAILED(rv)) { - LOG(("Could not finish manifest hash, rv=%08x", rv)); - // This is not critical error - return NS_OK; - } - - if (!ParseSucceeded()) { - // Parsing failed, the hash is not valid - return NS_OK; - } - - if (mOldManifestHashValue == mManifestHashValue) { - LOG(("Update not needed, downloaded manifest content is byte-for-byte identical")); - mNeedsUpdate = false; - } - - // Store the manifest content hash value to the new - // offline cache token - nsCOMPtr<nsICachingChannel> cachingChannel = do_QueryInterface(aRequest, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsISupports> cacheToken; - cachingChannel->GetOfflineCacheToken(getter_AddRefs(cacheToken)); - if (cacheToken) { - nsCOMPtr<nsICacheEntry> cacheDescriptor(do_QueryInterface(cacheToken, &rv)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = cacheDescriptor->SetMetaDataElement("offline-manifest-hash", mManifestHashValue.get()); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; -} - -void -nsOfflineManifestItem::ReadStrictFileOriginPolicyPref() -{ - mStrictFileOriginPolicy = - Preferences::GetBool("security.fileuri.strict_origin_policy", true); -} - -NS_IMETHODIMP -nsOfflineManifestItem::OnStartRequest(nsIRequest *aRequest, - nsISupports *aContext) -{ - nsresult rv; - - nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aRequest, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - bool succeeded; - rv = channel->GetRequestSucceeded(&succeeded); - NS_ENSURE_SUCCESS(rv, rv); - - if (!succeeded) { - LOG(("HTTP request failed")); - LogToConsole("Offline cache manifest HTTP request failed", this); - mParserState = PARSE_ERROR; - return NS_ERROR_ABORT; - } - - rv = GetOldManifestContentHash(aRequest); - NS_ENSURE_SUCCESS(rv, rv); - - return nsOfflineCacheUpdateItem::OnStartRequest(aRequest, aContext); -} - -NS_IMETHODIMP -nsOfflineManifestItem::OnDataAvailable(nsIRequest *aRequest, - nsISupports *aContext, - nsIInputStream *aStream, - uint64_t aOffset, - uint32_t aCount) -{ - uint32_t bytesRead = 0; - aStream->ReadSegments(ReadManifest, this, aCount, &bytesRead); - mBytesRead += bytesRead; - - if (mParserState == PARSE_ERROR) { - LOG(("OnDataAvailable is canceling the request due a parse error\n")); - return NS_ERROR_ABORT; - } - - LOG(("loaded %u bytes into offline cache [offset=%u]\n", - bytesRead, aOffset)); - - // All the parent method does is read and discard, don't bother - // chaining up. - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineManifestItem::OnStopRequest(nsIRequest *aRequest, - nsISupports *aContext, - nsresult aStatus) -{ - if (mBytesRead == 0) { - // We didn't need to read (because LOAD_ONLY_IF_MODIFIED was - // specified). - mNeedsUpdate = false; - } else { - // Handle any leftover manifest data. - nsCString::const_iterator begin, end; - mReadBuf.BeginReading(begin); - mReadBuf.EndReading(end); - nsresult rv = HandleManifestLine(begin, end); - NS_ENSURE_SUCCESS(rv, rv); - - rv = CheckNewManifestContentHash(aRequest); - NS_ENSURE_SUCCESS(rv, rv); - } - - return nsOfflineCacheUpdateItem::OnStopRequest(aRequest, aContext, aStatus); -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdate::nsISupports -//----------------------------------------------------------------------------- - -NS_IMPL_ISUPPORTS(nsOfflineCacheUpdate, - nsIOfflineCacheUpdateObserver, - nsIOfflineCacheUpdate, - nsIRunnable) - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdate <public> -//----------------------------------------------------------------------------- - -nsOfflineCacheUpdate::nsOfflineCacheUpdate() - : mState(STATE_UNINITIALIZED) - , mAddedItems(false) - , mPartialUpdate(false) - , mOnlyCheckUpdate(false) - , mSucceeded(true) - , mObsolete(false) - , mItemsInProgress(0) - , mRescheduleCount(0) - , mPinnedEntryRetriesCount(0) - , mPinned(false) - , mByteProgress(0) -{ -} - -nsOfflineCacheUpdate::~nsOfflineCacheUpdate() -{ - LOG(("nsOfflineCacheUpdate::~nsOfflineCacheUpdate [%p]", this)); -} - -/* static */ -nsresult -nsOfflineCacheUpdate::GetCacheKey(nsIURI *aURI, nsACString &aKey) -{ - aKey.Truncate(); - - nsCOMPtr<nsIURI> newURI; - nsresult rv = aURI->CloneIgnoringRef(getter_AddRefs(newURI)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = newURI->GetAsciiSpec(aKey); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -nsresult -nsOfflineCacheUpdate::InitInternal(nsIURI *aManifestURI, - nsIPrincipal* aLoadingPrincipal) -{ - nsresult rv; - - // Only http and https applications are supported. - bool match; - rv = aManifestURI->SchemeIs("http", &match); - NS_ENSURE_SUCCESS(rv, rv); - - if (!match) { - rv = aManifestURI->SchemeIs("https", &match); - NS_ENSURE_SUCCESS(rv, rv); - if (!match) - return NS_ERROR_ABORT; - } - - mManifestURI = aManifestURI; - mLoadingPrincipal = aLoadingPrincipal; - - rv = mManifestURI->GetAsciiHost(mUpdateDomain); - NS_ENSURE_SUCCESS(rv, rv); - - mPartialUpdate = false; - - return NS_OK; -} - -nsresult -nsOfflineCacheUpdate::Init(nsIURI *aManifestURI, - nsIURI *aDocumentURI, - nsIPrincipal* aLoadingPrincipal, - nsIDOMDocument *aDocument, - nsIFile *aCustomProfileDir) -{ - nsresult rv; - - // Make sure the service has been initialized - nsOfflineCacheUpdateService* service = - nsOfflineCacheUpdateService::EnsureService(); - if (!service) - return NS_ERROR_FAILURE; - - LOG(("nsOfflineCacheUpdate::Init [%p]", this)); - - rv = InitInternal(aManifestURI, aLoadingPrincipal); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIApplicationCacheService> cacheService = - do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoCString originSuffix; - rv = aLoadingPrincipal->GetOriginSuffix(originSuffix); - NS_ENSURE_SUCCESS(rv, rv); - - mDocumentURI = aDocumentURI; - - if (aCustomProfileDir) { - rv = cacheService->BuildGroupIDForSuffix(aManifestURI, originSuffix, mGroupID); - NS_ENSURE_SUCCESS(rv, rv); - - // Create only a new offline application cache in the custom profile - // This is a preload of a new cache. - - // XXX Custom updates don't support "updating" of an existing cache - // in the custom profile at the moment. This support can be, though, - // simply added as well when needed. - mPreviousApplicationCache = nullptr; - - rv = cacheService->CreateCustomApplicationCache(mGroupID, - aCustomProfileDir, - kCustomProfileQuota, - getter_AddRefs(mApplicationCache)); - NS_ENSURE_SUCCESS(rv, rv); - - mCustomProfileDir = aCustomProfileDir; - } - else { - rv = cacheService->BuildGroupIDForSuffix(aManifestURI, originSuffix, mGroupID); - NS_ENSURE_SUCCESS(rv, rv); - - rv = cacheService->GetActiveCache(mGroupID, - getter_AddRefs(mPreviousApplicationCache)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = cacheService->CreateApplicationCache(mGroupID, - getter_AddRefs(mApplicationCache)); - NS_ENSURE_SUCCESS(rv, rv); - } - - rv = nsOfflineCacheUpdateService::OfflineAppPinnedForURI(aDocumentURI, - nullptr, - &mPinned); - NS_ENSURE_SUCCESS(rv, rv); - - mState = STATE_INITIALIZED; - return NS_OK; -} - -nsresult -nsOfflineCacheUpdate::InitForUpdateCheck(nsIURI *aManifestURI, - nsIPrincipal* aLoadingPrincipal, - nsIObserver *aObserver) -{ - nsresult rv; - - // Make sure the service has been initialized - nsOfflineCacheUpdateService* service = - nsOfflineCacheUpdateService::EnsureService(); - if (!service) - return NS_ERROR_FAILURE; - - LOG(("nsOfflineCacheUpdate::InitForUpdateCheck [%p]", this)); - - rv = InitInternal(aManifestURI, aLoadingPrincipal); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIApplicationCacheService> cacheService = - do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoCString originSuffix; - rv = aLoadingPrincipal->GetOriginSuffix(originSuffix); - NS_ENSURE_SUCCESS(rv, rv); - - rv = cacheService->BuildGroupIDForSuffix(aManifestURI, originSuffix, mGroupID); - NS_ENSURE_SUCCESS(rv, rv); - - rv = cacheService->GetActiveCache(mGroupID, - getter_AddRefs(mPreviousApplicationCache)); - NS_ENSURE_SUCCESS(rv, rv); - - // To load the manifest properly using current app cache to satisfy and - // also to compare the cached content hash value we have to set 'some' - // app cache to write to on the channel. Otherwise the cached version will - // be used and no actual network request will be made. We use the same - // app cache here. OpenChannel prevents caching in this case using - // INHIBIT_CACHING load flag. - mApplicationCache = mPreviousApplicationCache; - - rv = nsOfflineCacheUpdateService::OfflineAppPinnedForURI(aManifestURI, - nullptr, - &mPinned); - NS_ENSURE_SUCCESS(rv, rv); - - mUpdateAvailableObserver = aObserver; - mOnlyCheckUpdate = true; - - mState = STATE_INITIALIZED; - return NS_OK; -} - -nsresult -nsOfflineCacheUpdate::InitPartial(nsIURI *aManifestURI, - const nsACString& clientID, - nsIURI *aDocumentURI, - nsIPrincipal *aLoadingPrincipal) -{ - nsresult rv; - - // Make sure the service has been initialized - nsOfflineCacheUpdateService* service = - nsOfflineCacheUpdateService::EnsureService(); - if (!service) - return NS_ERROR_FAILURE; - - LOG(("nsOfflineCacheUpdate::InitPartial [%p]", this)); - - mPartialUpdate = true; - mDocumentURI = aDocumentURI; - mLoadingPrincipal = aLoadingPrincipal; - - mManifestURI = aManifestURI; - rv = mManifestURI->GetAsciiHost(mUpdateDomain); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIApplicationCacheService> cacheService = - do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = cacheService->GetApplicationCache(clientID, - getter_AddRefs(mApplicationCache)); - NS_ENSURE_SUCCESS(rv, rv); - - if (!mApplicationCache) { - nsAutoCString manifestSpec; - rv = GetCacheKey(mManifestURI, manifestSpec); - NS_ENSURE_SUCCESS(rv, rv); - - rv = cacheService->CreateApplicationCache - (manifestSpec, getter_AddRefs(mApplicationCache)); - NS_ENSURE_SUCCESS(rv, rv); - } - - rv = mApplicationCache->GetManifestURI(getter_AddRefs(mManifestURI)); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoCString groupID; - rv = mApplicationCache->GetGroupID(groupID); - NS_ENSURE_SUCCESS(rv, rv); - - rv = nsOfflineCacheUpdateService::OfflineAppPinnedForURI(aDocumentURI, - nullptr, - &mPinned); - NS_ENSURE_SUCCESS(rv, rv); - - mState = STATE_INITIALIZED; - return NS_OK; -} - -nsresult -nsOfflineCacheUpdate::HandleManifest(bool *aDoUpdate) -{ - // Be pessimistic - *aDoUpdate = false; - - bool succeeded; - nsresult rv = mManifestItem->GetRequestSucceeded(&succeeded); - NS_ENSURE_SUCCESS(rv, rv); - - if (!succeeded || !mManifestItem->ParseSucceeded()) { - return NS_ERROR_FAILURE; - } - - if (!mManifestItem->NeedsUpdate()) { - return NS_OK; - } - - // Add items requested by the manifest. - const nsCOMArray<nsIURI> &manifestURIs = mManifestItem->GetExplicitURIs(); - for (int32_t i = 0; i < manifestURIs.Count(); i++) { - rv = AddURI(manifestURIs[i], nsIApplicationCache::ITEM_EXPLICIT); - NS_ENSURE_SUCCESS(rv, rv); - } - - const nsCOMArray<nsIURI> &anonURIs = mManifestItem->GetAnonymousURIs(); - for (int32_t i = 0; i < anonURIs.Count(); i++) { - rv = AddURI(anonURIs[i], nsIApplicationCache::ITEM_EXPLICIT, - nsIRequest::LOAD_ANONYMOUS); - NS_ENSURE_SUCCESS(rv, rv); - } - - const nsCOMArray<nsIURI> &fallbackURIs = mManifestItem->GetFallbackURIs(); - for (int32_t i = 0; i < fallbackURIs.Count(); i++) { - rv = AddURI(fallbackURIs[i], nsIApplicationCache::ITEM_FALLBACK); - NS_ENSURE_SUCCESS(rv, rv); - } - - // The document that requested the manifest is implicitly included - // as part of that manifest update. - rv = AddURI(mDocumentURI, nsIApplicationCache::ITEM_IMPLICIT); - NS_ENSURE_SUCCESS(rv, rv); - - // Add items previously cached implicitly - rv = AddExistingItems(nsIApplicationCache::ITEM_IMPLICIT); - NS_ENSURE_SUCCESS(rv, rv); - - // Add items requested by the script API - rv = AddExistingItems(nsIApplicationCache::ITEM_DYNAMIC); - NS_ENSURE_SUCCESS(rv, rv); - - // Add opportunistically cached items conforming current opportunistic - // namespace list - rv = AddExistingItems(nsIApplicationCache::ITEM_OPPORTUNISTIC, - &mManifestItem->GetOpportunisticNamespaces()); - NS_ENSURE_SUCCESS(rv, rv); - - *aDoUpdate = true; - - return NS_OK; -} - -bool -nsOfflineCacheUpdate::CheckUpdateAvailability() -{ - nsresult rv; - - bool succeeded; - rv = mManifestItem->GetRequestSucceeded(&succeeded); - NS_ENSURE_SUCCESS(rv, false); - - if (!succeeded || !mManifestItem->ParseSucceeded()) { - return false; - } - - if (!mPinned) { - uint16_t status; - rv = mManifestItem->GetStatus(&status); - NS_ENSURE_SUCCESS(rv, false); - - // Treat these as there would be an update available, - // since this is indication of demand to remove this - // offline cache. - if (status == 404 || status == 410) { - return true; - } - } - - return mManifestItem->NeedsUpdate(); -} - -void -nsOfflineCacheUpdate::LoadCompleted(nsOfflineCacheUpdateItem *aItem) -{ - nsresult rv; - - LOG(("nsOfflineCacheUpdate::LoadCompleted [%p]", this)); - - if (mState == STATE_FINISHED) { - LOG((" after completion, ignoring")); - return; - } - - // Keep the object alive through a Finish() call. - nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this); - - if (mState == STATE_CANCELLED) { - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); - Finish(); - return; - } - - if (mState == STATE_CHECKING) { - // Manifest load finished. - - if (mOnlyCheckUpdate) { - Finish(); - NotifyUpdateAvailability(CheckUpdateAvailability()); - return; - } - - NS_ASSERTION(mManifestItem, - "Must have a manifest item in STATE_CHECKING."); - NS_ASSERTION(mManifestItem == aItem, - "Unexpected aItem in nsOfflineCacheUpdate::LoadCompleted"); - - // A 404 or 410 is interpreted as an intentional removal of - // the manifest file, rather than a transient server error. - // Obsolete this cache group if one of these is returned. - uint16_t status; - rv = mManifestItem->GetStatus(&status); - if (status == 404 || status == 410) { - LogToConsole("Offline cache manifest removed, cache cleared", mManifestItem); - mSucceeded = false; - if (mPreviousApplicationCache) { - if (mPinned) { - // Do not obsolete a pinned application. - NotifyState(nsIOfflineCacheUpdateObserver::STATE_NOUPDATE); - } else { - NotifyState(nsIOfflineCacheUpdateObserver::STATE_OBSOLETE); - mObsolete = true; - } - } else { - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); - mObsolete = true; - } - Finish(); - return; - } - - bool doUpdate; - if (NS_FAILED(HandleManifest(&doUpdate))) { - mSucceeded = false; - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); - Finish(); - return; - } - - if (!doUpdate) { - LogToConsole("Offline cache doesn't need to update", mManifestItem); - - mSucceeded = false; - - AssociateDocuments(mPreviousApplicationCache); - - ScheduleImplicit(); - - // If we didn't need an implicit update, we can - // send noupdate and end the update now. - if (!mImplicitUpdate) { - NotifyState(nsIOfflineCacheUpdateObserver::STATE_NOUPDATE); - Finish(); - } - return; - } - - rv = mApplicationCache->MarkEntry(mManifestItem->mCacheKey, - mManifestItem->mItemType); - if (NS_FAILED(rv)) { - mSucceeded = false; - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); - Finish(); - return; - } - - mState = STATE_DOWNLOADING; - NotifyState(nsIOfflineCacheUpdateObserver::STATE_DOWNLOADING); - - // Start fetching resources. - ProcessNextURI(); - - return; - } - - // Normal load finished. - if (mItemsInProgress) // Just to be safe here! - --mItemsInProgress; - - bool succeeded; - rv = aItem->GetRequestSucceeded(&succeeded); - - if (mPinned && NS_SUCCEEDED(rv) && succeeded) { - uint32_t dummy_cache_type; - rv = mApplicationCache->GetTypes(aItem->mCacheKey, &dummy_cache_type); - bool item_doomed = NS_FAILED(rv); // can not find it? -> doomed - - if (item_doomed && - mPinnedEntryRetriesCount < kPinnedEntryRetriesLimit && - (aItem->mItemType & (nsIApplicationCache::ITEM_EXPLICIT | - nsIApplicationCache::ITEM_FALLBACK))) { - rv = EvictOneNonPinned(); - if (NS_FAILED(rv)) { - mSucceeded = false; - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); - Finish(); - return; - } - - // This reverts the item state to UNINITIALIZED that makes it to - // be scheduled for download again. - rv = aItem->Cancel(); - if (NS_FAILED(rv)) { - mSucceeded = false; - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); - Finish(); - return; - } - - mPinnedEntryRetriesCount++; - - LogToConsole("An unpinned offline cache deleted"); - - // Retry this item. - ProcessNextURI(); - return; - } - } - - // According to parallelism this may imply more pinned retries count, - // but that is not critical, since at one moment the algoritm will - // stop anyway. Also, this code may soon be completely removed - // after we have a separate storage for pinned apps. - mPinnedEntryRetriesCount = 0; - - // Check for failures. 3XX, 4XX and 5XX errors on items explicitly - // listed in the manifest will cause the update to fail. - if (NS_FAILED(rv) || !succeeded) { - if (aItem->mItemType & - (nsIApplicationCache::ITEM_EXPLICIT | - nsIApplicationCache::ITEM_FALLBACK)) { - LogToConsole("Offline cache manifest item failed to load", aItem); - mSucceeded = false; - } - } else { - rv = mApplicationCache->MarkEntry(aItem->mCacheKey, aItem->mItemType); - if (NS_FAILED(rv)) { - mSucceeded = false; - } - } - - if (!mSucceeded) { - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); - Finish(); - return; - } - - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ITEMCOMPLETED); - - ProcessNextURI(); -} - -void -nsOfflineCacheUpdate::ManifestCheckCompleted(nsresult aStatus, - const nsCString &aManifestHash) -{ - // Keep the object alive through a Finish() call. - nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this); - - if (NS_SUCCEEDED(aStatus)) { - nsAutoCString firstManifestHash; - mManifestItem->GetManifestHash(firstManifestHash); - if (aManifestHash != firstManifestHash) { - LOG(("Manifest has changed during cache items download [%p]", this)); - LogToConsole("Offline cache manifest changed during update", mManifestItem); - aStatus = NS_ERROR_FAILURE; - } - } - - if (NS_FAILED(aStatus)) { - mSucceeded = false; - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); - } - - if (NS_FAILED(aStatus) && mRescheduleCount < kRescheduleLimit) { - // Do the final stuff but prevent notification of STATE_FINISHED. - // That would disconnect listeners that are responsible for document - // association after a successful update. Forwarding notifications - // from a new update through this dead update to them is absolutely - // correct. - FinishNoNotify(); - - RefPtr<nsOfflineCacheUpdate> newUpdate = - new nsOfflineCacheUpdate(); - // Leave aDocument argument null. Only glues and children keep - // document instances. - newUpdate->Init(mManifestURI, mDocumentURI, mLoadingPrincipal, nullptr, - mCustomProfileDir); - - // In a rare case the manifest will not be modified on the next refetch - // transfer all master document URIs to the new update to ensure that - // all documents refering it will be properly cached. - for (int32_t i = 0; i < mDocumentURIs.Count(); i++) { - newUpdate->StickDocument(mDocumentURIs[i]); - } - - newUpdate->mRescheduleCount = mRescheduleCount + 1; - newUpdate->AddObserver(this, false); - newUpdate->Schedule(); - } - else { - LogToConsole("Offline cache update done", mManifestItem); - Finish(); - } -} - -nsresult -nsOfflineCacheUpdate::Begin() -{ - LOG(("nsOfflineCacheUpdate::Begin [%p]", this)); - - // Keep the object alive through a ProcessNextURI()/Finish() call. - nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this); - - mItemsInProgress = 0; - - if (mState == STATE_CANCELLED) { - nsresult rv = NS_DispatchToMainThread(NewRunnableMethod(this, - &nsOfflineCacheUpdate::AsyncFinishWithError)); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; - } - - if (mPartialUpdate) { - mState = STATE_DOWNLOADING; - NotifyState(nsIOfflineCacheUpdateObserver::STATE_DOWNLOADING); - ProcessNextURI(); - return NS_OK; - } - - // Start checking the manifest. - mManifestItem = new nsOfflineManifestItem(mManifestURI, - mDocumentURI, - mLoadingPrincipal, - mApplicationCache, - mPreviousApplicationCache); - if (!mManifestItem) { - return NS_ERROR_OUT_OF_MEMORY; - } - - mState = STATE_CHECKING; - mByteProgress = 0; - NotifyState(nsIOfflineCacheUpdateObserver::STATE_CHECKING); - - nsresult rv = mManifestItem->OpenChannel(this); - if (NS_FAILED(rv)) { - LoadCompleted(mManifestItem); - } - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdate <private> -//----------------------------------------------------------------------------- - -nsresult -nsOfflineCacheUpdate::AddExistingItems(uint32_t aType, - nsTArray<nsCString>* namespaceFilter) -{ - if (!mPreviousApplicationCache) { - return NS_OK; - } - - if (namespaceFilter && namespaceFilter->Length() == 0) { - // Don't bother to walk entries when there are no namespaces - // defined. - return NS_OK; - } - - uint32_t count = 0; - char **keys = nullptr; - nsresult rv = mPreviousApplicationCache->GatherEntries(aType, - &count, &keys); - NS_ENSURE_SUCCESS(rv, rv); - - AutoFreeArray autoFree(count, keys); - - for (uint32_t i = 0; i < count; i++) { - if (namespaceFilter) { - bool found = false; - for (uint32_t j = 0; j < namespaceFilter->Length() && !found; j++) { - found = StringBeginsWith(nsDependentCString(keys[i]), - namespaceFilter->ElementAt(j)); - } - - if (!found) - continue; - } - - nsCOMPtr<nsIURI> uri; - if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), keys[i]))) { - rv = AddURI(uri, aType); - NS_ENSURE_SUCCESS(rv, rv); - } - } - - return NS_OK; -} - -nsresult -nsOfflineCacheUpdate::ProcessNextURI() -{ - // Keep the object alive through a Finish() call. - nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this); - - LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p, inprogress=%d, numItems=%d]", - this, mItemsInProgress, mItems.Length())); - - if (mState != STATE_DOWNLOADING) { - LOG((" should only be called from the DOWNLOADING state, ignoring")); - return NS_ERROR_UNEXPECTED; - } - - nsOfflineCacheUpdateItem * runItem = nullptr; - uint32_t completedItems = 0; - for (uint32_t i = 0; i < mItems.Length(); ++i) { - nsOfflineCacheUpdateItem * item = mItems[i]; - - if (item->IsScheduled()) { - runItem = item; - break; - } - - if (item->IsCompleted()) - ++completedItems; - } - - if (completedItems == mItems.Length()) { - LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p]: all items loaded", this)); - - if (mPartialUpdate) { - return Finish(); - } else { - // Verify that the manifest wasn't changed during the - // update, to prevent capturing a cache while the server - // is being updated. The check will call - // ManifestCheckCompleted() when it's done. - RefPtr<nsManifestCheck> manifestCheck = - new nsManifestCheck(this, mManifestURI, mDocumentURI, mLoadingPrincipal); - if (NS_FAILED(manifestCheck->Begin())) { - mSucceeded = false; - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); - return Finish(); - } - - return NS_OK; - } - } - - if (!runItem) { - LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p]:" - " No more items to include in parallel load", this)); - return NS_OK; - } - - if (LOG_ENABLED()) { - LOG(("%p: Opening channel for %s", this, - runItem->mURI->GetSpecOrDefault().get())); - } - - ++mItemsInProgress; - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ITEMSTARTED); - - nsresult rv = runItem->OpenChannel(this); - if (NS_FAILED(rv)) { - LoadCompleted(runItem); - return rv; - } - - if (mItemsInProgress >= kParallelLoadLimit) { - LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p]:" - " At parallel load limit", this)); - return NS_OK; - } - - // This calls this method again via a post triggering - // a parallel item load - return NS_DispatchToCurrentThread(this); -} - -void -nsOfflineCacheUpdate::GatherObservers(nsCOMArray<nsIOfflineCacheUpdateObserver> &aObservers) -{ - for (int32_t i = 0; i < mWeakObservers.Count(); i++) { - nsCOMPtr<nsIOfflineCacheUpdateObserver> observer = - do_QueryReferent(mWeakObservers[i]); - if (observer) - aObservers.AppendObject(observer); - else - mWeakObservers.RemoveObjectAt(i--); - } - - for (int32_t i = 0; i < mObservers.Count(); i++) { - aObservers.AppendObject(mObservers[i]); - } -} - -void -nsOfflineCacheUpdate::NotifyState(uint32_t state) -{ - LOG(("nsOfflineCacheUpdate::NotifyState [%p, %d]", this, state)); - - if (state == STATE_ERROR) { - LogToConsole("Offline cache update error", mManifestItem); - } - - nsCOMArray<nsIOfflineCacheUpdateObserver> observers; - GatherObservers(observers); - - for (int32_t i = 0; i < observers.Count(); i++) { - observers[i]->UpdateStateChanged(this, state); - } -} - -void -nsOfflineCacheUpdate::NotifyUpdateAvailability(bool updateAvailable) -{ - if (!mUpdateAvailableObserver) - return; - - LOG(("nsOfflineCacheUpdate::NotifyUpdateAvailability [this=%p, avail=%d]", - this, updateAvailable)); - - const char* topic = updateAvailable - ? "offline-cache-update-available" - : "offline-cache-update-unavailable"; - - nsCOMPtr<nsIObserver> observer; - observer.swap(mUpdateAvailableObserver); - observer->Observe(mManifestURI, topic, nullptr); -} - -void -nsOfflineCacheUpdate::AssociateDocuments(nsIApplicationCache* cache) -{ - if (!cache) { - LOG(("nsOfflineCacheUpdate::AssociateDocuments bypassed" - ", no cache provided [this=%p]", this)); - return; - } - - nsCOMArray<nsIOfflineCacheUpdateObserver> observers; - GatherObservers(observers); - - for (int32_t i = 0; i < observers.Count(); i++) { - observers[i]->ApplicationCacheAvailable(cache); - } -} - -void -nsOfflineCacheUpdate::StickDocument(nsIURI *aDocumentURI) -{ - if (!aDocumentURI) - return; - - mDocumentURIs.AppendObject(aDocumentURI); -} - -void -nsOfflineCacheUpdate::SetOwner(nsOfflineCacheUpdateOwner *aOwner) -{ - NS_ASSERTION(!mOwner, "Tried to set cache update owner twice."); - mOwner = aOwner; -} - -bool -nsOfflineCacheUpdate::IsForGroupID(const nsCSubstring &groupID) -{ - return mGroupID == groupID; -} - -bool -nsOfflineCacheUpdate::IsForProfile(nsIFile* aCustomProfileDir) -{ - if (!mCustomProfileDir && !aCustomProfileDir) - return true; - if (!mCustomProfileDir || !aCustomProfileDir) - return false; - - bool equals; - nsresult rv = mCustomProfileDir->Equals(aCustomProfileDir, &equals); - - return NS_SUCCEEDED(rv) && equals; -} - -nsresult -nsOfflineCacheUpdate::UpdateFinished(nsOfflineCacheUpdate *aUpdate) -{ - // Keep the object alive through a Finish() call. - nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this); - - mImplicitUpdate = nullptr; - - NotifyState(nsIOfflineCacheUpdateObserver::STATE_NOUPDATE); - Finish(); - - return NS_OK; -} - -void -nsOfflineCacheUpdate::OnByteProgress(uint64_t byteIncrement) -{ - mByteProgress += byteIncrement; - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ITEMPROGRESS); -} - -nsresult -nsOfflineCacheUpdate::ScheduleImplicit() -{ - if (mDocumentURIs.Count() == 0) - return NS_OK; - - nsresult rv; - - RefPtr<nsOfflineCacheUpdate> update = new nsOfflineCacheUpdate(); - NS_ENSURE_TRUE(update, NS_ERROR_OUT_OF_MEMORY); - - nsAutoCString clientID; - if (mPreviousApplicationCache) { - rv = mPreviousApplicationCache->GetClientID(clientID); - NS_ENSURE_SUCCESS(rv, rv); - } - else if (mApplicationCache) { - rv = mApplicationCache->GetClientID(clientID); - NS_ENSURE_SUCCESS(rv, rv); - } - else { - NS_ERROR("Offline cache update not having set mApplicationCache?"); - } - - rv = update->InitPartial(mManifestURI, clientID, mDocumentURI, mLoadingPrincipal); - NS_ENSURE_SUCCESS(rv, rv); - - for (int32_t i = 0; i < mDocumentURIs.Count(); i++) { - rv = update->AddURI(mDocumentURIs[i], - nsIApplicationCache::ITEM_IMPLICIT); - NS_ENSURE_SUCCESS(rv, rv); - } - - update->SetOwner(this); - rv = update->Begin(); - NS_ENSURE_SUCCESS(rv, rv); - - mImplicitUpdate = update; - - return NS_OK; -} - -nsresult -nsOfflineCacheUpdate::FinishNoNotify() -{ - LOG(("nsOfflineCacheUpdate::Finish [%p]", this)); - - mState = STATE_FINISHED; - - if (!mPartialUpdate && !mOnlyCheckUpdate) { - if (mSucceeded) { - nsIArray *namespaces = mManifestItem->GetNamespaces(); - nsresult rv = mApplicationCache->AddNamespaces(namespaces); - if (NS_FAILED(rv)) { - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); - mSucceeded = false; - } - - rv = mApplicationCache->Activate(); - if (NS_FAILED(rv)) { - NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); - mSucceeded = false; - } - - AssociateDocuments(mApplicationCache); - } - - if (mObsolete) { - nsCOMPtr<nsIApplicationCacheService> appCacheService = - do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID); - if (appCacheService) { - nsAutoCString groupID; - mApplicationCache->GetGroupID(groupID); - appCacheService->DeactivateGroup(groupID); - } - } - - if (!mSucceeded) { - // Update was not merged, mark all the loads as failures - for (uint32_t i = 0; i < mItems.Length(); i++) { - mItems[i]->Cancel(); - } - - mApplicationCache->Discard(); - } - } - - nsresult rv = NS_OK; - - if (mOwner) { - rv = mOwner->UpdateFinished(this); - // mozilla::WeakPtr is missing some key features, like setting it to - // null explicitly. - mOwner = mozilla::WeakPtr<nsOfflineCacheUpdateOwner>(); - } - - return rv; -} - -nsresult -nsOfflineCacheUpdate::Finish() -{ - nsresult rv = FinishNoNotify(); - - NotifyState(nsIOfflineCacheUpdateObserver::STATE_FINISHED); - - return rv; -} - -void -nsOfflineCacheUpdate::AsyncFinishWithError() -{ - NotifyState(nsOfflineCacheUpdate::STATE_ERROR); - Finish(); -} - -static nsresult -EvictOneOfCacheGroups(nsIApplicationCacheService *cacheService, - uint32_t count, const char * const *groups) -{ - nsresult rv; - unsigned int i; - - for (i = 0; i < count; i++) { - nsCOMPtr<nsIURI> uri; - rv = NS_NewURI(getter_AddRefs(uri), groups[i]); - NS_ENSURE_SUCCESS(rv, rv); - - nsDependentCString group_name(groups[i]); - nsCOMPtr<nsIApplicationCache> cache; - rv = cacheService->GetActiveCache(group_name, getter_AddRefs(cache)); - // Maybe someone in another thread or process have deleted it. - if (NS_FAILED(rv) || !cache) - continue; - - bool pinned; - rv = nsOfflineCacheUpdateService::OfflineAppPinnedForURI(uri, - nullptr, - &pinned); - NS_ENSURE_SUCCESS(rv, rv); - - if (!pinned) { - rv = cache->Discard(); - return NS_OK; - } - } - - return NS_ERROR_FILE_NOT_FOUND; -} - -nsresult -nsOfflineCacheUpdate::EvictOneNonPinned() -{ - nsresult rv; - - nsCOMPtr<nsIApplicationCacheService> cacheService = - do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - uint32_t count; - char **groups; - rv = cacheService->GetGroupsTimeOrdered(&count, &groups); - NS_ENSURE_SUCCESS(rv, rv); - - rv = EvictOneOfCacheGroups(cacheService, count, groups); - - NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, groups); - return rv; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdate::nsIOfflineCacheUpdate -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsOfflineCacheUpdate::GetUpdateDomain(nsACString &aUpdateDomain) -{ - NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED); - - aUpdateDomain = mUpdateDomain; - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::GetStatus(uint16_t *aStatus) -{ - switch (mState) { - case STATE_CHECKING : - *aStatus = nsIDOMOfflineResourceList::CHECKING; - return NS_OK; - case STATE_DOWNLOADING : - *aStatus = nsIDOMOfflineResourceList::DOWNLOADING; - return NS_OK; - default : - *aStatus = nsIDOMOfflineResourceList::IDLE; - return NS_OK; - } - - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::GetPartial(bool *aPartial) -{ - *aPartial = mPartialUpdate || mOnlyCheckUpdate; - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::GetManifestURI(nsIURI **aManifestURI) -{ - NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED); - - NS_IF_ADDREF(*aManifestURI = mManifestURI); - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::GetSucceeded(bool *aSucceeded) -{ - NS_ENSURE_TRUE(mState == STATE_FINISHED, NS_ERROR_NOT_AVAILABLE); - - *aSucceeded = mSucceeded; - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::GetIsUpgrade(bool *aIsUpgrade) -{ - NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED); - - *aIsUpgrade = (mPreviousApplicationCache != nullptr); - - return NS_OK; -} - -nsresult -nsOfflineCacheUpdate::AddURI(nsIURI *aURI, uint32_t aType, uint32_t aLoadFlags) -{ - NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED); - - if (mState >= STATE_DOWNLOADING) - return NS_ERROR_NOT_AVAILABLE; - - // Resource URIs must have the same scheme as the manifest. - nsAutoCString scheme; - aURI->GetScheme(scheme); - - bool match; - if (NS_FAILED(mManifestURI->SchemeIs(scheme.get(), &match)) || !match) - return NS_ERROR_FAILURE; - - // Don't fetch the same URI twice. - for (uint32_t i = 0; i < mItems.Length(); i++) { - bool equals; - if (NS_SUCCEEDED(mItems[i]->mURI->Equals(aURI, &equals)) && equals && - mItems[i]->mLoadFlags == aLoadFlags) { - // retain both types. - mItems[i]->mItemType |= aType; - return NS_OK; - } - } - - RefPtr<nsOfflineCacheUpdateItem> item = - new nsOfflineCacheUpdateItem(aURI, - mDocumentURI, - mLoadingPrincipal, - mApplicationCache, - mPreviousApplicationCache, - aType, - aLoadFlags); - if (!item) return NS_ERROR_OUT_OF_MEMORY; - - mItems.AppendElement(item); - mAddedItems = true; - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::AddDynamicURI(nsIURI *aURI) -{ - if (GeckoProcessType_Default != XRE_GetProcessType()) - return NS_ERROR_NOT_IMPLEMENTED; - - // If this is a partial update and the resource is already in the - // cache, we should only mark the entry, not fetch it again. - if (mPartialUpdate) { - nsAutoCString key; - GetCacheKey(aURI, key); - - uint32_t types; - nsresult rv = mApplicationCache->GetTypes(key, &types); - if (NS_SUCCEEDED(rv)) { - if (!(types & nsIApplicationCache::ITEM_DYNAMIC)) { - mApplicationCache->MarkEntry - (key, nsIApplicationCache::ITEM_DYNAMIC); - } - return NS_OK; - } - } - - return AddURI(aURI, nsIApplicationCache::ITEM_DYNAMIC); -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::Cancel() -{ - LOG(("nsOfflineCacheUpdate::Cancel [%p]", this)); - - if ((mState == STATE_FINISHED) || (mState == STATE_CANCELLED)) { - return NS_ERROR_NOT_AVAILABLE; - } - - mState = STATE_CANCELLED; - mSucceeded = false; - - // Cancel all running downloads - for (uint32_t i = 0; i < mItems.Length(); ++i) { - nsOfflineCacheUpdateItem * item = mItems[i]; - - if (item->IsInProgress()) - item->Cancel(); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::AddObserver(nsIOfflineCacheUpdateObserver *aObserver, - bool aHoldWeak) -{ - LOG(("nsOfflineCacheUpdate::AddObserver [%p] to update [%p]", aObserver, this)); - - NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED); - - if (aHoldWeak) { - nsCOMPtr<nsIWeakReference> weakRef = do_GetWeakReference(aObserver); - mWeakObservers.AppendObject(weakRef); - } else { - mObservers.AppendObject(aObserver); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::RemoveObserver(nsIOfflineCacheUpdateObserver *aObserver) -{ - LOG(("nsOfflineCacheUpdate::RemoveObserver [%p] from update [%p]", aObserver, this)); - - NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED); - - for (int32_t i = 0; i < mWeakObservers.Count(); i++) { - nsCOMPtr<nsIOfflineCacheUpdateObserver> observer = - do_QueryReferent(mWeakObservers[i]); - if (observer == aObserver) { - mWeakObservers.RemoveObjectAt(i); - return NS_OK; - } - } - - for (int32_t i = 0; i < mObservers.Count(); i++) { - if (mObservers[i] == aObserver) { - mObservers.RemoveObjectAt(i); - return NS_OK; - } - } - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::GetByteProgress(uint64_t * _result) -{ - NS_ENSURE_ARG(_result); - - *_result = mByteProgress; - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::Schedule() -{ - LOG(("nsOfflineCacheUpdate::Schedule [%p]", this)); - - nsOfflineCacheUpdateService* service = - nsOfflineCacheUpdateService::EnsureService(); - - if (!service) { - return NS_ERROR_FAILURE; - } - - return service->ScheduleUpdate(this); -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::UpdateStateChanged(nsIOfflineCacheUpdate *aUpdate, - uint32_t aState) -{ - if (aState == nsIOfflineCacheUpdateObserver::STATE_FINISHED) { - // Take the mSucceeded flag from the underlying update, we will be - // queried for it soon. mSucceeded of this update is false (manifest - // check failed) but the subsequent re-fetch update might succeed - bool succeeded; - aUpdate->GetSucceeded(&succeeded); - mSucceeded = succeeded; - } - - NotifyState(aState); - if (aState == nsIOfflineCacheUpdateObserver::STATE_FINISHED) - aUpdate->RemoveObserver(this); - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdate::ApplicationCacheAvailable(nsIApplicationCache *applicationCache) -{ - AssociateDocuments(applicationCache); - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdate::nsIRunable -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsOfflineCacheUpdate::Run() -{ - ProcessNextURI(); - return NS_OK; -} diff --git a/system/docshell/prefetch/nsOfflineCacheUpdate.h b/system/docshell/prefetch/nsOfflineCacheUpdate.h deleted file mode 100644 index 2e6d6d30c..000000000 --- a/system/docshell/prefetch/nsOfflineCacheUpdate.h +++ /dev/null @@ -1,380 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsOfflineCacheUpdate_h__ -#define nsOfflineCacheUpdate_h__ - -#include "nsIOfflineCacheUpdate.h" - -#include "nsAutoPtr.h" -#include "nsCOMArray.h" -#include "nsCOMPtr.h" -#include "nsIChannelEventSink.h" -#include "nsIDOMDocument.h" -#include "nsIDOMNode.h" -#include "nsIInterfaceRequestor.h" -#include "nsIMutableArray.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsIApplicationCache.h" -#include "nsIRequestObserver.h" -#include "nsIRunnable.h" -#include "nsIStreamListener.h" -#include "nsIURI.h" -#include "nsIWebProgressListener.h" -#include "nsClassHashtable.h" -#include "nsString.h" -#include "nsTArray.h" -#include "nsWeakReference.h" -#include "nsICryptoHash.h" -#include "mozilla/Attributes.h" -#include "mozilla/WeakPtr.h" -#include "nsTHashtable.h" -#include "nsHashKeys.h" - -class nsOfflineCacheUpdate; - -class nsOfflineCacheUpdateItem : public nsIStreamListener - , public nsIRunnable - , public nsIInterfaceRequestor - , public nsIChannelEventSink -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIRUNNABLE - NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSICHANNELEVENTSINK - - nsOfflineCacheUpdateItem(nsIURI *aURI, - nsIURI *aReferrerURI, - nsIPrincipal* aLoadingPrincipal, - nsIApplicationCache *aApplicationCache, - nsIApplicationCache *aPreviousApplicationCache, - uint32_t aType, - uint32_t aLoadFlags); - - nsCOMPtr<nsIURI> mURI; - nsCOMPtr<nsIURI> mReferrerURI; - nsCOMPtr<nsIPrincipal> mLoadingPrincipal; - nsCOMPtr<nsIApplicationCache> mApplicationCache; - nsCOMPtr<nsIApplicationCache> mPreviousApplicationCache; - nsCString mCacheKey; - uint32_t mItemType; - uint32_t mLoadFlags; - - nsresult OpenChannel(nsOfflineCacheUpdate *aUpdate); - nsresult Cancel(); - nsresult GetRequestSucceeded(bool * succeeded); - - bool IsInProgress(); - bool IsScheduled(); - bool IsCompleted(); - - nsresult GetStatus(uint16_t *aStatus); - -private: - enum LoadStatus : uint16_t { - UNINITIALIZED = 0U, - REQUESTED = 1U, - RECEIVING = 2U, - LOADED = 3U - }; - - RefPtr<nsOfflineCacheUpdate> mUpdate; - nsCOMPtr<nsIChannel> mChannel; - uint16_t mState; - -protected: - virtual ~nsOfflineCacheUpdateItem(); - - int64_t mBytesRead; -}; - - -class nsOfflineManifestItem : public nsOfflineCacheUpdateItem -{ -public: - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIREQUESTOBSERVER - - nsOfflineManifestItem(nsIURI *aURI, - nsIURI *aReferrerURI, - nsIPrincipal* aLoadingPrincipal, - nsIApplicationCache *aApplicationCache, - nsIApplicationCache *aPreviousApplicationCache); - virtual ~nsOfflineManifestItem(); - - nsCOMArray<nsIURI> &GetExplicitURIs() { return mExplicitURIs; } - nsCOMArray<nsIURI> &GetAnonymousURIs() { return mAnonymousURIs; } - nsCOMArray<nsIURI> &GetFallbackURIs() { return mFallbackURIs; } - - nsTArray<nsCString> &GetOpportunisticNamespaces() - { return mOpportunisticNamespaces; } - nsIArray *GetNamespaces() - { return mNamespaces.get(); } - - bool ParseSucceeded() - { return (mParserState != PARSE_INIT && mParserState != PARSE_ERROR); } - bool NeedsUpdate() { return mParserState != PARSE_INIT && mNeedsUpdate; } - - void GetManifestHash(nsCString &aManifestHash) - { aManifestHash = mManifestHashValue; } - -private: - static nsresult ReadManifest(nsIInputStream *aInputStream, - void *aClosure, - const char *aFromSegment, - uint32_t aOffset, - uint32_t aCount, - uint32_t *aBytesConsumed); - - nsresult AddNamespace(uint32_t namespaceType, - const nsCString &namespaceSpec, - const nsCString &data); - - nsresult HandleManifestLine(const nsCString::const_iterator &aBegin, - const nsCString::const_iterator &aEnd); - - /** - * Saves "offline-manifest-hash" meta data from the old offline cache - * token to mOldManifestHashValue member to be compared on - * successfull load. - */ - nsresult GetOldManifestContentHash(nsIRequest *aRequest); - /** - * This method setups the mNeedsUpdate to false when hash value - * of the just downloaded manifest file is the same as stored in cache's - * "offline-manifest-hash" meta data. Otherwise stores the new value - * to this meta data. - */ - nsresult CheckNewManifestContentHash(nsIRequest *aRequest); - - void ReadStrictFileOriginPolicyPref(); - - enum { - PARSE_INIT, - PARSE_CACHE_ENTRIES, - PARSE_FALLBACK_ENTRIES, - PARSE_BYPASS_ENTRIES, - PARSE_UNKNOWN_SECTION, - PARSE_ERROR - } mParserState; - - nsCString mReadBuf; - - nsCOMArray<nsIURI> mExplicitURIs; - nsCOMArray<nsIURI> mAnonymousURIs; - nsCOMArray<nsIURI> mFallbackURIs; - - // All opportunistic caching namespaces. Used to decide whether - // to include previously-opportunistically-cached entries. - nsTArray<nsCString> mOpportunisticNamespaces; - - // Array of nsIApplicationCacheNamespace objects specified by the - // manifest. - nsCOMPtr<nsIMutableArray> mNamespaces; - - bool mNeedsUpdate; - bool mStrictFileOriginPolicy; - - // manifest hash data - nsCOMPtr<nsICryptoHash> mManifestHash; - bool mManifestHashInitialized; - nsCString mManifestHashValue; - nsCString mOldManifestHashValue; -}; - -class nsOfflineCacheUpdateOwner - : public mozilla::SupportsWeakPtr<nsOfflineCacheUpdateOwner> -{ -public: - MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsOfflineCacheUpdateOwner) - virtual ~nsOfflineCacheUpdateOwner() {} - virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate) = 0; -}; - -class nsOfflineCacheUpdate final : public nsIOfflineCacheUpdate - , public nsIOfflineCacheUpdateObserver - , public nsIRunnable - , public nsOfflineCacheUpdateOwner -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOFFLINECACHEUPDATE - NS_DECL_NSIOFFLINECACHEUPDATEOBSERVER - NS_DECL_NSIRUNNABLE - - nsOfflineCacheUpdate(); - - static nsresult GetCacheKey(nsIURI *aURI, nsACString &aKey); - - nsresult Init(); - - nsresult Begin(); - - void LoadCompleted(nsOfflineCacheUpdateItem *aItem); - void ManifestCheckCompleted(nsresult aStatus, - const nsCString &aManifestHash); - void StickDocument(nsIURI *aDocumentURI); - - void SetOwner(nsOfflineCacheUpdateOwner *aOwner); - - bool IsForGroupID(const nsCSubstring &groupID); - bool IsForProfile(nsIFile* aCustomProfileDir); - - virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate) override; - -protected: - ~nsOfflineCacheUpdate(); - - friend class nsOfflineCacheUpdateItem; - void OnByteProgress(uint64_t byteIncrement); - -private: - nsresult InitInternal(nsIURI *aManifestURI, nsIPrincipal* aPrincipal); - nsresult HandleManifest(bool *aDoUpdate); - nsresult AddURI(nsIURI *aURI, uint32_t aItemType, uint32_t aLoadFlags = 0); - - nsresult ProcessNextURI(); - - // Adds items from the previous cache witha type matching aType. - // If namespaceFilter is non-null, only items matching the - // specified namespaces will be added. - nsresult AddExistingItems(uint32_t aType, - nsTArray<nsCString>* namespaceFilter = nullptr); - nsresult ScheduleImplicit(); - void AssociateDocuments(nsIApplicationCache* cache); - bool CheckUpdateAvailability(); - void NotifyUpdateAvailability(bool updateAvailable); - - void GatherObservers(nsCOMArray<nsIOfflineCacheUpdateObserver> &aObservers); - void NotifyState(uint32_t state); - nsresult Finish(); - nsresult FinishNoNotify(); - - void AsyncFinishWithError(); - - // Find one non-pinned cache group and evict it. - nsresult EvictOneNonPinned(); - - enum { - STATE_UNINITIALIZED, - STATE_INITIALIZED, - STATE_CHECKING, - STATE_DOWNLOADING, - STATE_CANCELLED, - STATE_FINISHED - } mState; - - mozilla::WeakPtr<nsOfflineCacheUpdateOwner> mOwner; - - bool mAddedItems; - bool mPartialUpdate; - bool mOnlyCheckUpdate; - bool mSucceeded; - bool mObsolete; - - nsCString mUpdateDomain; - nsCString mGroupID; - nsCOMPtr<nsIURI> mManifestURI; - nsCOMPtr<nsIURI> mDocumentURI; - nsCOMPtr<nsIPrincipal> mLoadingPrincipal; - nsCOMPtr<nsIFile> mCustomProfileDir; - - nsCOMPtr<nsIObserver> mUpdateAvailableObserver; - - nsCOMPtr<nsIApplicationCache> mApplicationCache; - nsCOMPtr<nsIApplicationCache> mPreviousApplicationCache; - - nsCOMPtr<nsIObserverService> mObserverService; - - RefPtr<nsOfflineManifestItem> mManifestItem; - - /* Items being updated */ - uint32_t mItemsInProgress; - nsTArray<RefPtr<nsOfflineCacheUpdateItem> > mItems; - - /* Clients watching this update for changes */ - nsCOMArray<nsIWeakReference> mWeakObservers; - nsCOMArray<nsIOfflineCacheUpdateObserver> mObservers; - - /* Documents that requested this update */ - nsCOMArray<nsIURI> mDocumentURIs; - - /* Reschedule count. When an update is rescheduled due to - * mismatched manifests, the reschedule count will be increased. */ - uint32_t mRescheduleCount; - - /* Whena an entry for a pinned app is retried, retries count is - * increaded. */ - uint32_t mPinnedEntryRetriesCount; - - RefPtr<nsOfflineCacheUpdate> mImplicitUpdate; - - bool mPinned; - - uint64_t mByteProgress; -}; - -class nsOfflineCacheUpdateService final : public nsIOfflineCacheUpdateService - , public nsIObserver - , public nsOfflineCacheUpdateOwner - , public nsSupportsWeakReference -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOFFLINECACHEUPDATESERVICE - NS_DECL_NSIOBSERVER - - nsOfflineCacheUpdateService(); - - nsresult Init(); - - nsresult ScheduleUpdate(nsOfflineCacheUpdate *aUpdate); - nsresult FindUpdate(nsIURI *aManifestURI, - nsACString const &aOriginSuffix, - nsIFile *aCustomProfileDir, - nsOfflineCacheUpdate **aUpdate); - - nsresult Schedule(nsIURI *aManifestURI, - nsIURI *aDocumentURI, - nsIPrincipal* aLoadingPrincipal, - nsIDOMDocument *aDocument, - nsPIDOMWindowInner* aWindow, - nsIFile* aCustomProfileDir, - nsIOfflineCacheUpdate **aUpdate); - - virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate) override; - - /** - * Returns the singleton nsOfflineCacheUpdateService without an addref, or - * nullptr if the service couldn't be created. - */ - static nsOfflineCacheUpdateService *EnsureService(); - - /** Addrefs and returns the singleton nsOfflineCacheUpdateService. */ - static nsOfflineCacheUpdateService *GetInstance(); - - static nsresult OfflineAppPinnedForURI(nsIURI *aDocumentURI, - nsIPrefBranch *aPrefBranch, - bool *aPinned); - - static nsTHashtable<nsCStringHashKey>* AllowedDomains(); - -private: - ~nsOfflineCacheUpdateService(); - - nsresult ProcessNextUpdate(); - - nsTArray<RefPtr<nsOfflineCacheUpdate> > mUpdates; - static nsTHashtable<nsCStringHashKey>* mAllowedDomains; - - bool mDisabled; - bool mUpdateRunning; -}; - -#endif diff --git a/system/docshell/prefetch/nsOfflineCacheUpdateService.cpp b/system/docshell/prefetch/nsOfflineCacheUpdateService.cpp deleted file mode 100644 index 6a67af013..000000000 --- a/system/docshell/prefetch/nsOfflineCacheUpdateService.cpp +++ /dev/null @@ -1,706 +0,0 @@ -/* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "OfflineCacheUpdateChild.h" -#include "OfflineCacheUpdateParent.h" -#include "nsXULAppAPI.h" -#include "OfflineCacheUpdateGlue.h" -#include "nsOfflineCacheUpdate.h" - -#include "nsCPrefetchService.h" -#include "nsCURILoader.h" -#include "nsIApplicationCacheContainer.h" -#include "nsIApplicationCacheChannel.h" -#include "nsIApplicationCacheService.h" -#include "nsICachingChannel.h" -#include "nsIContent.h" -#include "nsIDocShell.h" -#include "nsIDocumentLoader.h" -#include "nsIDOMElement.h" -#include "nsIDOMWindow.h" -#include "nsIDOMOfflineResourceList.h" -#include "nsIDocument.h" -#include "nsIObserverService.h" -#include "nsIURL.h" -#include "nsIWebProgress.h" -#include "nsIWebNavigation.h" -#include "nsICryptoHash.h" -#include "nsIPermissionManager.h" -#include "nsIPrincipal.h" -#include "nsNetCID.h" -#include "nsServiceManagerUtils.h" -#include "nsStreamUtils.h" -#include "nsThreadUtils.h" -#include "nsProxyRelease.h" -#include "mozilla/Logging.h" -#include "nsIAsyncVerifyRedirectCallback.h" -#include "mozilla/Preferences.h" -#include "mozilla/Attributes.h" -#include "mozilla/Unused.h" -#include "nsIDocShell.h" -#include "nsIDocShellTreeItem.h" -#include "nsIDocShellTreeOwner.h" -#include "mozilla/dom/ContentChild.h" -#include "mozilla/dom/PermissionMessageUtils.h" -#include "nsContentUtils.h" -#include "mozilla/Unused.h" - -using namespace mozilla; -using namespace mozilla::dom; - -static nsOfflineCacheUpdateService *gOfflineCacheUpdateService = nullptr; -static bool sAllowOfflineCache = true; - -nsTHashtable<nsCStringHashKey>* nsOfflineCacheUpdateService::mAllowedDomains = nullptr; - -nsTHashtable<nsCStringHashKey>* nsOfflineCacheUpdateService::AllowedDomains() -{ - if (!mAllowedDomains) - mAllowedDomains = new nsTHashtable<nsCStringHashKey>(); - - return mAllowedDomains; -} - - -typedef mozilla::docshell::OfflineCacheUpdateParent OfflineCacheUpdateParent; -typedef mozilla::docshell::OfflineCacheUpdateChild OfflineCacheUpdateChild; -typedef mozilla::docshell::OfflineCacheUpdateGlue OfflineCacheUpdateGlue; - -// -// To enable logging (see mozilla/Logging.h for full details): -// -// set MOZ_LOG=nsOfflineCacheUpdate:5 -// set MOZ_LOG_FILE=offlineupdate.log -// -// this enables LogLevel::Debug level information and places all output in -// the file offlineupdate.log -// -LazyLogModule gOfflineCacheUpdateLog("nsOfflineCacheUpdate"); - -#undef LOG -#define LOG(args) MOZ_LOG(gOfflineCacheUpdateLog, mozilla::LogLevel::Debug, args) - -#undef LOG_ENABLED -#define LOG_ENABLED() MOZ_LOG_TEST(gOfflineCacheUpdateLog, mozilla::LogLevel::Debug) - -//----------------------------------------------------------------------------- -// nsOfflineCachePendingUpdate -//----------------------------------------------------------------------------- - -class nsOfflineCachePendingUpdate final : public nsIWebProgressListener - , public nsSupportsWeakReference -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIWEBPROGRESSLISTENER - - nsOfflineCachePendingUpdate(nsOfflineCacheUpdateService *aService, - nsIURI *aManifestURI, - nsIURI *aDocumentURI, - nsIPrincipal* aLoadingPrincipal, - nsIDOMDocument *aDocument) - : mService(aService) - , mManifestURI(aManifestURI) - , mDocumentURI(aDocumentURI) - , mLoadingPrincipal(aLoadingPrincipal) - , mDidReleaseThis(false) - { - mDocument = do_GetWeakReference(aDocument); - } - -private: - ~nsOfflineCachePendingUpdate() {} - - RefPtr<nsOfflineCacheUpdateService> mService; - nsCOMPtr<nsIURI> mManifestURI; - nsCOMPtr<nsIURI> mDocumentURI; - nsCOMPtr<nsIPrincipal> mLoadingPrincipal; - nsCOMPtr<nsIWeakReference> mDocument; - bool mDidReleaseThis; -}; - -NS_IMPL_ISUPPORTS(nsOfflineCachePendingUpdate, - nsIWebProgressListener, - nsISupportsWeakReference) - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateService::nsIWebProgressListener -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsOfflineCachePendingUpdate::OnProgressChange(nsIWebProgress *aProgress, - nsIRequest *aRequest, - int32_t curSelfProgress, - int32_t maxSelfProgress, - int32_t curTotalProgress, - int32_t maxTotalProgress) -{ - NS_NOTREACHED("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCachePendingUpdate::OnStateChange(nsIWebProgress* aWebProgress, - nsIRequest *aRequest, - uint32_t progressStateFlags, - nsresult aStatus) -{ - if (mDidReleaseThis) { - return NS_OK; - } - nsCOMPtr<nsIDOMDocument> updateDoc = do_QueryReferent(mDocument); - if (!updateDoc) { - // The document that scheduled this update has gone away, - // we don't need to listen anymore. - aWebProgress->RemoveProgressListener(this); - MOZ_ASSERT(!mDidReleaseThis); - mDidReleaseThis = true; - NS_RELEASE_THIS(); - return NS_OK; - } - - if (!(progressStateFlags & STATE_STOP)) { - return NS_OK; - } - - nsCOMPtr<mozIDOMWindowProxy> windowProxy; - aWebProgress->GetDOMWindow(getter_AddRefs(windowProxy)); - if (!windowProxy) return NS_OK; - - auto* outerWindow = nsPIDOMWindowOuter::From(windowProxy); - nsPIDOMWindowInner* innerWindow = outerWindow->GetCurrentInnerWindow(); - - nsCOMPtr<nsIDocument> progressDoc = outerWindow->GetDoc(); - if (!progressDoc) return NS_OK; - - if (!SameCOMIdentity(progressDoc, updateDoc)) { - return NS_OK; - } - - LOG(("nsOfflineCachePendingUpdate::OnStateChange [%p, doc=%p]", - this, progressDoc.get())); - - // Only schedule the update if the document loaded successfully - if (NS_SUCCEEDED(aStatus)) { - nsCOMPtr<nsIOfflineCacheUpdate> update; - mService->Schedule(mManifestURI, mDocumentURI, mLoadingPrincipal, updateDoc, innerWindow, - nullptr, getter_AddRefs(update)); - if (mDidReleaseThis) { - return NS_OK; - } - } - - aWebProgress->RemoveProgressListener(this); - MOZ_ASSERT(!mDidReleaseThis); - mDidReleaseThis = true; - NS_RELEASE_THIS(); - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCachePendingUpdate::OnLocationChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - nsIURI *location, - uint32_t aFlags) -{ - NS_NOTREACHED("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCachePendingUpdate::OnStatusChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - nsresult aStatus, - const char16_t* aMessage) -{ - NS_NOTREACHED("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCachePendingUpdate::OnSecurityChange(nsIWebProgress *aWebProgress, - nsIRequest *aRequest, - uint32_t state) -{ - NS_NOTREACHED("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateService::nsISupports -//----------------------------------------------------------------------------- - -NS_IMPL_ISUPPORTS(nsOfflineCacheUpdateService, - nsIOfflineCacheUpdateService, - nsIObserver, - nsISupportsWeakReference) - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateService <public> -//----------------------------------------------------------------------------- - -nsOfflineCacheUpdateService::nsOfflineCacheUpdateService() - : mDisabled(false) - , mUpdateRunning(false) -{ - MOZ_ASSERT(NS_IsMainThread()); - Preferences::AddBoolVarCache(&sAllowOfflineCache, - "browser.cache.offline.enable", - true); -} - -nsOfflineCacheUpdateService::~nsOfflineCacheUpdateService() -{ - gOfflineCacheUpdateService = nullptr; -} - -nsresult -nsOfflineCacheUpdateService::Init() -{ - // Observe xpcom-shutdown event - nsCOMPtr<nsIObserverService> observerService = - mozilla::services::GetObserverService(); - if (!observerService) - return NS_ERROR_FAILURE; - - nsresult rv = observerService->AddObserver(this, - NS_XPCOM_SHUTDOWN_OBSERVER_ID, - true); - NS_ENSURE_SUCCESS(rv, rv); - - gOfflineCacheUpdateService = this; - - return NS_OK; -} - -/* static */ -nsOfflineCacheUpdateService * -nsOfflineCacheUpdateService::GetInstance() -{ - if (!gOfflineCacheUpdateService) { - gOfflineCacheUpdateService = new nsOfflineCacheUpdateService(); - if (!gOfflineCacheUpdateService) - return nullptr; - NS_ADDREF(gOfflineCacheUpdateService); - nsresult rv = gOfflineCacheUpdateService->Init(); - if (NS_FAILED(rv)) { - NS_RELEASE(gOfflineCacheUpdateService); - return nullptr; - } - return gOfflineCacheUpdateService; - } - - NS_ADDREF(gOfflineCacheUpdateService); - - return gOfflineCacheUpdateService; -} - -/* static */ -nsOfflineCacheUpdateService * -nsOfflineCacheUpdateService::EnsureService() -{ - if (!gOfflineCacheUpdateService) { - // Make the service manager hold a long-lived reference to the service - nsCOMPtr<nsIOfflineCacheUpdateService> service = - do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID); - } - - return gOfflineCacheUpdateService; -} - -nsresult -nsOfflineCacheUpdateService::ScheduleUpdate(nsOfflineCacheUpdate *aUpdate) -{ - LOG(("nsOfflineCacheUpdateService::Schedule [%p, update=%p]", - this, aUpdate)); - - aUpdate->SetOwner(this); - - mUpdates.AppendElement(aUpdate); - ProcessNextUpdate(); - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdateService::ScheduleOnDocumentStop(nsIURI *aManifestURI, - nsIURI *aDocumentURI, - nsIPrincipal* aLoadingPrincipal, - nsIDOMDocument *aDocument) -{ - LOG(("nsOfflineCacheUpdateService::ScheduleOnDocumentStop [%p, manifestURI=%p, documentURI=%p doc=%p]", - this, aManifestURI, aDocumentURI, aDocument)); - - nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDocument); - nsCOMPtr<nsIWebProgress> progress = do_QueryInterface(doc->GetContainer()); - NS_ENSURE_TRUE(progress, NS_ERROR_INVALID_ARG); - - // Proceed with cache update - RefPtr<nsOfflineCachePendingUpdate> update = - new nsOfflineCachePendingUpdate(this, aManifestURI, aDocumentURI, - aLoadingPrincipal, aDocument); - NS_ENSURE_TRUE(update, NS_ERROR_OUT_OF_MEMORY); - - nsresult rv = progress->AddProgressListener - (update, nsIWebProgress::NOTIFY_STATE_DOCUMENT); - NS_ENSURE_SUCCESS(rv, rv); - - // The update will release when it has scheduled itself. - Unused << update.forget(); - - return NS_OK; -} - -nsresult -nsOfflineCacheUpdateService::UpdateFinished(nsOfflineCacheUpdate *aUpdate) -{ - LOG(("nsOfflineCacheUpdateService::UpdateFinished [%p, update=%p]", - this, aUpdate)); - - NS_ASSERTION(mUpdates.Length() > 0 && - mUpdates[0] == aUpdate, "Unknown update completed"); - - // keep this item alive until we're done notifying observers - RefPtr<nsOfflineCacheUpdate> update = mUpdates[0]; - Unused << update; - mUpdates.RemoveElementAt(0); - mUpdateRunning = false; - - ProcessNextUpdate(); - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateService <private> -//----------------------------------------------------------------------------- - -nsresult -nsOfflineCacheUpdateService::ProcessNextUpdate() -{ - LOG(("nsOfflineCacheUpdateService::ProcessNextUpdate [%p, num=%d]", - this, mUpdates.Length())); - - if (mDisabled) - return NS_ERROR_ABORT; - - if (mUpdateRunning) - return NS_OK; - - if (mUpdates.Length() > 0) { - mUpdateRunning = true; - - return mUpdates[0]->Begin(); - } - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateService::nsIOfflineCacheUpdateService -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsOfflineCacheUpdateService::GetNumUpdates(uint32_t *aNumUpdates) -{ - LOG(("nsOfflineCacheUpdateService::GetNumUpdates [%p]", this)); - - *aNumUpdates = mUpdates.Length(); - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdateService::GetUpdate(uint32_t aIndex, - nsIOfflineCacheUpdate **aUpdate) -{ - LOG(("nsOfflineCacheUpdateService::GetUpdate [%p, %d]", this, aIndex)); - - if (aIndex < mUpdates.Length()) { - NS_ADDREF(*aUpdate = mUpdates[aIndex]); - } else { - *aUpdate = nullptr; - } - - return NS_OK; -} - -nsresult -nsOfflineCacheUpdateService::FindUpdate(nsIURI *aManifestURI, - nsACString const &aOriginSuffix, - nsIFile *aCustomProfileDir, - nsOfflineCacheUpdate **aUpdate) -{ - nsresult rv; - - nsCOMPtr<nsIApplicationCacheService> cacheService = - do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoCString groupID; - rv = cacheService->BuildGroupIDForSuffix(aManifestURI, aOriginSuffix, groupID); - NS_ENSURE_SUCCESS(rv, rv); - - RefPtr<nsOfflineCacheUpdate> update; - for (uint32_t i = 0; i < mUpdates.Length(); i++) { - update = mUpdates[i]; - - bool partial; - rv = update->GetPartial(&partial); - NS_ENSURE_SUCCESS(rv, rv); - - if (partial) { - // Partial updates aren't considered - continue; - } - - if (update->IsForGroupID(groupID) && update->IsForProfile(aCustomProfileDir)) { - update.swap(*aUpdate); - return NS_OK; - } - } - - return NS_ERROR_NOT_AVAILABLE; -} - -nsresult -nsOfflineCacheUpdateService::Schedule(nsIURI *aManifestURI, - nsIURI *aDocumentURI, - nsIPrincipal* aLoadingPrincipal, - nsIDOMDocument *aDocument, - nsPIDOMWindowInner* aWindow, - nsIFile* aCustomProfileDir, - nsIOfflineCacheUpdate **aUpdate) -{ - nsCOMPtr<nsIOfflineCacheUpdate> update; - if (GeckoProcessType_Default != XRE_GetProcessType()) { - update = new OfflineCacheUpdateChild(aWindow); - } - else { - update = new OfflineCacheUpdateGlue(); - } - - nsresult rv; - - if (aWindow) { - // Ensure there is window.applicationCache object that is - // responsible for association of the new applicationCache - // with the corresponding document. Just ignore the result. - nsCOMPtr<nsIDOMOfflineResourceList> appCacheWindowObject = - aWindow->GetApplicationCache(); - } - - rv = update->Init(aManifestURI, aDocumentURI, aLoadingPrincipal, aDocument, - aCustomProfileDir); - NS_ENSURE_SUCCESS(rv, rv); - - rv = update->Schedule(); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ADDREF(*aUpdate = update); - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdateService::ScheduleUpdate(nsIURI *aManifestURI, - nsIURI *aDocumentURI, - nsIPrincipal* aLoadingPrincipal, - mozIDOMWindow* aWindow, - nsIOfflineCacheUpdate **aUpdate) -{ - return Schedule(aManifestURI, aDocumentURI, aLoadingPrincipal, nullptr, - nsPIDOMWindowInner::From(aWindow), nullptr, aUpdate); -} - -NS_IMETHODIMP -nsOfflineCacheUpdateService::ScheduleAppUpdate(nsIURI *aManifestURI, - nsIURI *aDocumentURI, - nsIPrincipal* aLoadingPrincipal, - nsIFile *aProfileDir, - nsIOfflineCacheUpdate **aUpdate) -{ - return Schedule(aManifestURI, aDocumentURI, aLoadingPrincipal, nullptr, nullptr, - aProfileDir, aUpdate); -} - -NS_IMETHODIMP nsOfflineCacheUpdateService::CheckForUpdate(nsIURI *aManifestURI, - nsIPrincipal* aLoadingPrincipal, - nsIObserver *aObserver) -{ - if (GeckoProcessType_Default != XRE_GetProcessType()) { - // Not intended to support this on child processes - return NS_ERROR_NOT_IMPLEMENTED; - } - - nsCOMPtr<nsIOfflineCacheUpdate> update = new OfflineCacheUpdateGlue(); - - nsresult rv; - - rv = update->InitForUpdateCheck(aManifestURI, aLoadingPrincipal, aObserver); - NS_ENSURE_SUCCESS(rv, rv); - - rv = update->Schedule(); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateService::nsIObserver -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsOfflineCacheUpdateService::Observe(nsISupports *aSubject, - const char *aTopic, - const char16_t *aData) -{ - if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { - if (mUpdates.Length() > 0) - mUpdates[0]->Cancel(); - mDisabled = true; - } - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsOfflineCacheUpdateService::nsIOfflineCacheUpdateService -//----------------------------------------------------------------------------- - -static nsresult -OfflineAppPermForPrincipal(nsIPrincipal *aPrincipal, - nsIPrefBranch *aPrefBranch, - bool pinned, - bool *aAllowed) -{ - *aAllowed = false; - - if (!sAllowOfflineCache) { - return NS_OK; - } - - if (!aPrincipal) - return NS_ERROR_INVALID_ARG; - - nsCOMPtr<nsIURI> uri; - aPrincipal->GetURI(getter_AddRefs(uri)); - - if (!uri) - return NS_OK; - - nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(uri); - if (!innerURI) - return NS_OK; - - // only http and https applications can use offline APIs. - bool match; - nsresult rv = innerURI->SchemeIs("http", &match); - NS_ENSURE_SUCCESS(rv, rv); - - if (!match) { - rv = innerURI->SchemeIs("https", &match); - NS_ENSURE_SUCCESS(rv, rv); - if (!match) { - return NS_OK; - } - } - - nsAutoCString domain; - rv = innerURI->GetAsciiHost(domain); - NS_ENSURE_SUCCESS(rv, rv); - - if (nsOfflineCacheUpdateService::AllowedDomains()->Contains(domain)) { - *aAllowed = true; - return NS_OK; - } - - nsCOMPtr<nsIPermissionManager> permissionManager = - services::GetPermissionManager(); - if (!permissionManager) { - return NS_OK; - } - - uint32_t perm; - const char *permName = pinned ? "pin-app" : "offline-app"; - permissionManager->TestExactPermissionFromPrincipal(aPrincipal, permName, &perm); - - if (perm == nsIPermissionManager::ALLOW_ACTION || - perm == nsIOfflineCacheUpdateService::ALLOW_NO_WARN) { - *aAllowed = true; - } - - // offline-apps.allow_by_default is now effective at the cache selection - // algorithm code (nsContentSink). - - return NS_OK; -} - -NS_IMETHODIMP -nsOfflineCacheUpdateService::OfflineAppAllowed(nsIPrincipal *aPrincipal, - nsIPrefBranch *aPrefBranch, - bool *aAllowed) -{ - return OfflineAppPermForPrincipal(aPrincipal, aPrefBranch, false, aAllowed); -} - -NS_IMETHODIMP -nsOfflineCacheUpdateService::OfflineAppAllowedForURI(nsIURI *aURI, - nsIPrefBranch *aPrefBranch, - bool *aAllowed) -{ - PrincipalOriginAttributes attrs; - nsCOMPtr<nsIPrincipal> principal = - BasePrincipal::CreateCodebasePrincipal(aURI, attrs); - return OfflineAppPermForPrincipal(principal, aPrefBranch, false, aAllowed); -} - -nsresult -nsOfflineCacheUpdateService::OfflineAppPinnedForURI(nsIURI *aDocumentURI, - nsIPrefBranch *aPrefBranch, - bool *aPinned) -{ - PrincipalOriginAttributes attrs; - nsCOMPtr<nsIPrincipal> principal = - BasePrincipal::CreateCodebasePrincipal(aDocumentURI, attrs); - return OfflineAppPermForPrincipal(principal, aPrefBranch, true, aPinned); -} - -NS_IMETHODIMP -nsOfflineCacheUpdateService::AllowOfflineApp(nsIPrincipal *aPrincipal) -{ - nsresult rv; - - if (!sAllowOfflineCache) { - return NS_ERROR_NOT_AVAILABLE; - } - - if (GeckoProcessType_Default != XRE_GetProcessType()) { - ContentChild* child = ContentChild::GetSingleton(); - - if (!child->SendSetOfflinePermission(IPC::Principal(aPrincipal))) { - return NS_ERROR_FAILURE; - } - - nsAutoCString domain; - rv = aPrincipal->GetBaseDomain(domain); - NS_ENSURE_SUCCESS(rv, rv); - - nsOfflineCacheUpdateService::AllowedDomains()->PutEntry(domain); - } - else { - nsCOMPtr<nsIPermissionManager> permissionManager = - services::GetPermissionManager(); - if (!permissionManager) - return NS_ERROR_NOT_AVAILABLE; - - rv = permissionManager->AddFromPrincipal( - aPrincipal, "offline-app", nsIPermissionManager::ALLOW_ACTION, - nsIPermissionManager::EXPIRE_NEVER, 0); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; -} diff --git a/system/docshell/prefetch/nsPrefetchService.cpp b/system/docshell/prefetch/nsPrefetchService.cpp deleted file mode 100644 index bd2b10d30..000000000 --- a/system/docshell/prefetch/nsPrefetchService.cpp +++ /dev/null @@ -1,931 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsPrefetchService.h" -#include "nsICacheEntry.h" -#include "nsIServiceManager.h" -#include "nsICategoryManager.h" -#include "nsIObserverService.h" -#include "nsIWebProgress.h" -#include "nsCURILoader.h" -#include "nsICacheInfoChannel.h" -#include "nsIHttpChannel.h" -#include "nsIURL.h" -#include "nsISimpleEnumerator.h" -#include "nsNetUtil.h" -#include "nsString.h" -#include "nsXPIDLString.h" -#include "nsReadableUtils.h" -#include "nsStreamUtils.h" -#include "nsAutoPtr.h" -#include "prtime.h" -#include "mozilla/Logging.h" -#include "plstr.h" -#include "nsIAsyncVerifyRedirectCallback.h" -#include "mozilla/Preferences.h" -#include "mozilla/Attributes.h" -#include "mozilla/CORSMode.h" -#include "mozilla/dom/HTMLLinkElement.h" -#include "nsIDOMNode.h" -#include "nsINode.h" -#include "nsIDocument.h" -#include "nsContentUtils.h" - -using namespace mozilla; - -// -// To enable logging (see mozilla/Logging.h for full details): -// -// set MOZ_LOG=nsPrefetch:5 -// set MOZ_LOG_FILE=prefetch.log -// -// this enables LogLevel::Debug level information and places all output in -// the file prefetch.log -// -static LazyLogModule gPrefetchLog("nsPrefetch"); - -#undef LOG -#define LOG(args) MOZ_LOG(gPrefetchLog, mozilla::LogLevel::Debug, args) - -#undef LOG_ENABLED -#define LOG_ENABLED() MOZ_LOG_TEST(gPrefetchLog, mozilla::LogLevel::Debug) - -#define PREFETCH_PREF "network.prefetch-next" -#define PARALLELISM_PREF "network.prefetch-next.parallelism" -#define AGGRESSIVE_PREF "network.prefetch-next.aggressive" - -//----------------------------------------------------------------------------- -// helpers -//----------------------------------------------------------------------------- - -static inline uint32_t -PRTimeToSeconds(PRTime t_usec) -{ - PRTime usec_per_sec = PR_USEC_PER_SEC; - return uint32_t(t_usec /= usec_per_sec); -} - -#define NowInSeconds() PRTimeToSeconds(PR_Now()) - -//----------------------------------------------------------------------------- -// nsPrefetchNode <public> -//----------------------------------------------------------------------------- - -nsPrefetchNode::nsPrefetchNode(nsPrefetchService *aService, - nsIURI *aURI, - nsIURI *aReferrerURI, - nsIDOMNode *aSource) - : mURI(aURI) - , mReferrerURI(aReferrerURI) - , mService(aService) - , mChannel(nullptr) - , mBytesRead(0) - , mShouldFireLoadEvent(false) -{ - nsCOMPtr<nsIWeakReference> source = do_GetWeakReference(aSource); - mSources.AppendElement(source); -} - -nsresult -nsPrefetchNode::OpenChannel() -{ - if (mSources.IsEmpty()) { - // Don't attempt to prefetch if we don't have a source node - // (which should never happen). - return NS_ERROR_FAILURE; - } - nsCOMPtr<nsINode> source; - while (!mSources.IsEmpty() && !(source = do_QueryReferent(mSources.ElementAt(0)))) { - // If source is null remove it. - // (which should never happen). - mSources.RemoveElementAt(0); - } - - if (!source) { - // Don't attempt to prefetch if we don't have a source node - // (which should never happen). - - return NS_ERROR_FAILURE; - } - nsCOMPtr<nsILoadGroup> loadGroup = source->OwnerDoc()->GetDocumentLoadGroup(); - CORSMode corsMode = CORS_NONE; - net::ReferrerPolicy referrerPolicy = net::RP_Unset; - if (source->IsHTMLElement(nsGkAtoms::link)) { - dom::HTMLLinkElement* link = static_cast<dom::HTMLLinkElement*>(source.get()); - corsMode = link->GetCORSMode(); - referrerPolicy = link->GetLinkReferrerPolicy(); - } - - if (referrerPolicy == net::RP_Unset) { - referrerPolicy = source->OwnerDoc()->GetReferrerPolicy(); - } - - uint32_t securityFlags; - if (corsMode == CORS_NONE) { - securityFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS; - } else { - securityFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS; - if (corsMode == CORS_USE_CREDENTIALS) { - securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE; - } - } - nsresult rv = NS_NewChannelInternal(getter_AddRefs(mChannel), - mURI, - source, - source->NodePrincipal(), - nullptr, //aTriggeringPrincipal - securityFlags, - nsIContentPolicy::TYPE_OTHER, - loadGroup, // aLoadGroup - this, // aCallbacks - nsIRequest::LOAD_BACKGROUND | - nsICachingChannel::LOAD_ONLY_IF_MODIFIED); - - NS_ENSURE_SUCCESS(rv, rv); - - // configure HTTP specific stuff - nsCOMPtr<nsIHttpChannel> httpChannel = - do_QueryInterface(mChannel); - if (httpChannel) { - httpChannel->SetReferrerWithPolicy(mReferrerURI, referrerPolicy); - httpChannel->SetRequestHeader( - NS_LITERAL_CSTRING("X-Moz"), - NS_LITERAL_CSTRING("prefetch"), - false); - } - - rv = mChannel->AsyncOpen2(this); - if (NS_WARN_IF(NS_FAILED(rv))) { - // Drop the ref to the channel, because we don't want to end up with - // cycles through it. - mChannel = nullptr; - } - return rv; -} - -nsresult -nsPrefetchNode::CancelChannel(nsresult error) -{ - mChannel->Cancel(error); - mChannel = nullptr; - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsPrefetchNode::nsISupports -//----------------------------------------------------------------------------- - -NS_IMPL_ISUPPORTS(nsPrefetchNode, - nsIRequestObserver, - nsIStreamListener, - nsIInterfaceRequestor, - nsIChannelEventSink, - nsIRedirectResultListener) - -//----------------------------------------------------------------------------- -// nsPrefetchNode::nsIStreamListener -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsPrefetchNode::OnStartRequest(nsIRequest *aRequest, - nsISupports *aContext) -{ - nsresult rv; - - nsCOMPtr<nsIHttpChannel> httpChannel = - do_QueryInterface(aRequest, &rv); - if (NS_FAILED(rv)) return rv; - - // if the load is cross origin without CORS, or the CORS access is rejected, - // always fire load event to avoid leaking site information. - nsCOMPtr<nsILoadInfo> loadInfo = httpChannel->GetLoadInfo(); - mShouldFireLoadEvent = loadInfo->GetTainting() == LoadTainting::Opaque || - (loadInfo->GetTainting() == LoadTainting::CORS && - (NS_FAILED(httpChannel->GetStatus(&rv)) || - NS_FAILED(rv))); - - // no need to prefetch http error page - bool requestSucceeded; - if (NS_FAILED(httpChannel->GetRequestSucceeded(&requestSucceeded)) || - !requestSucceeded) { - return NS_BINDING_ABORTED; - } - - nsCOMPtr<nsICacheInfoChannel> cacheInfoChannel = - do_QueryInterface(aRequest, &rv); - if (NS_FAILED(rv)) return rv; - - // no need to prefetch a document that is already in the cache - bool fromCache; - if (NS_SUCCEEDED(cacheInfoChannel->IsFromCache(&fromCache)) && - fromCache) { - LOG(("document is already in the cache; canceling prefetch\n")); - // although it's canceled we still want to fire load event - mShouldFireLoadEvent = true; - return NS_BINDING_ABORTED; - } - - // - // no need to prefetch a document that must be requested fresh each - // and every time. - // - uint32_t expTime; - if (NS_SUCCEEDED(cacheInfoChannel->GetCacheTokenExpirationTime(&expTime))) { - if (NowInSeconds() >= expTime) { - LOG(("document cannot be reused from cache; " - "canceling prefetch\n")); - return NS_BINDING_ABORTED; - } - } - - return NS_OK; -} - -NS_IMETHODIMP -nsPrefetchNode::OnDataAvailable(nsIRequest *aRequest, - nsISupports *aContext, - nsIInputStream *aStream, - uint64_t aOffset, - uint32_t aCount) -{ - uint32_t bytesRead = 0; - aStream->ReadSegments(NS_DiscardSegment, nullptr, aCount, &bytesRead); - mBytesRead += bytesRead; - LOG(("prefetched %u bytes [offset=%llu]\n", bytesRead, aOffset)); - return NS_OK; -} - - -NS_IMETHODIMP -nsPrefetchNode::OnStopRequest(nsIRequest *aRequest, - nsISupports *aContext, - nsresult aStatus) -{ - LOG(("done prefetching [status=%x]\n", aStatus)); - - if (mBytesRead == 0 && aStatus == NS_OK && mChannel) { - // we didn't need to read (because LOAD_ONLY_IF_MODIFIED was - // specified), but the object should report loadedSize as if it - // did. - mChannel->GetContentLength(&mBytesRead); - } - - mService->NotifyLoadCompleted(this); - mService->DispatchEvent(this, mShouldFireLoadEvent || NS_SUCCEEDED(aStatus)); - mService->ProcessNextURI(this); - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsPrefetchNode::nsIInterfaceRequestor -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsPrefetchNode::GetInterface(const nsIID &aIID, void **aResult) -{ - if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) { - NS_ADDREF_THIS(); - *aResult = static_cast<nsIChannelEventSink *>(this); - return NS_OK; - } - - if (aIID.Equals(NS_GET_IID(nsIRedirectResultListener))) { - NS_ADDREF_THIS(); - *aResult = static_cast<nsIRedirectResultListener *>(this); - return NS_OK; - } - - return NS_ERROR_NO_INTERFACE; -} - -//----------------------------------------------------------------------------- -// nsPrefetchNode::nsIChannelEventSink -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsPrefetchNode::AsyncOnChannelRedirect(nsIChannel *aOldChannel, - nsIChannel *aNewChannel, - uint32_t aFlags, - nsIAsyncVerifyRedirectCallback *callback) -{ - nsCOMPtr<nsIURI> newURI; - nsresult rv = aNewChannel->GetURI(getter_AddRefs(newURI)); - if (NS_FAILED(rv)) - return rv; - - bool match; - rv = newURI->SchemeIs("http", &match); - if (NS_FAILED(rv) || !match) { - rv = newURI->SchemeIs("https", &match); - if (NS_FAILED(rv) || !match) { - LOG(("rejected: URL is not of type http/https\n")); - return NS_ERROR_ABORT; - } - } - - // HTTP request headers are not automatically forwarded to the new channel. - nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aNewChannel); - NS_ENSURE_STATE(httpChannel); - - httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"), - NS_LITERAL_CSTRING("prefetch"), - false); - - // Assign to mChannel after we get notification about success of the - // redirect in OnRedirectResult. - mRedirectChannel = aNewChannel; - - callback->OnRedirectVerifyCallback(NS_OK); - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsPrefetchNode::nsIRedirectResultListener -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsPrefetchNode::OnRedirectResult(bool proceeding) -{ - if (proceeding && mRedirectChannel) - mChannel = mRedirectChannel; - - mRedirectChannel = nullptr; - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsPrefetchService <public> -//----------------------------------------------------------------------------- - -nsPrefetchService::nsPrefetchService() - : mMaxParallelism(6) - , mStopCount(0) - , mHaveProcessed(false) - , mDisabled(true) - , mAggressive(false) -{ -} - -nsPrefetchService::~nsPrefetchService() -{ - Preferences::RemoveObserver(this, PREFETCH_PREF); - Preferences::RemoveObserver(this, PARALLELISM_PREF); - Preferences::RemoveObserver(this, AGGRESSIVE_PREF); - // cannot reach destructor if prefetch in progress (listener owns reference - // to this service) - EmptyQueue(); -} - -nsresult -nsPrefetchService::Init() -{ - nsresult rv; - - // read prefs and hook up pref observer - mDisabled = !Preferences::GetBool(PREFETCH_PREF, !mDisabled); - Preferences::AddWeakObserver(this, PREFETCH_PREF); - - mMaxParallelism = Preferences::GetInt(PARALLELISM_PREF, mMaxParallelism); - if (mMaxParallelism < 1) { - mMaxParallelism = 1; - } - Preferences::AddWeakObserver(this, PARALLELISM_PREF); - - mAggressive = Preferences::GetBool(AGGRESSIVE_PREF, false); - Preferences::AddWeakObserver(this, AGGRESSIVE_PREF); - - // Observe xpcom-shutdown event - nsCOMPtr<nsIObserverService> observerService = - mozilla::services::GetObserverService(); - if (!observerService) - return NS_ERROR_FAILURE; - - rv = observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true); - NS_ENSURE_SUCCESS(rv, rv); - - if (!mDisabled) - AddProgressListener(); - - return NS_OK; -} - -void -nsPrefetchService::ProcessNextURI(nsPrefetchNode *aFinished) -{ - nsresult rv; - - if (aFinished) { - mCurrentNodes.RemoveElement(aFinished); - } - - if (mCurrentNodes.Length() >= static_cast<uint32_t>(mMaxParallelism)) { - // We already have enough prefetches going on, so hold off - // for now. - return; - } - - do { - if (mQueue.empty()) { - break; - } - RefPtr<nsPrefetchNode> node = mQueue.front().forget(); - mQueue.pop_front(); - - if (LOG_ENABLED()) { - LOG(("ProcessNextURI [%s]\n", - node->mURI->GetSpecOrDefault().get())); } - - // - // if opening the channel fails (e.g. security check returns an error), - // send an error event and then just skip to the next uri - // - rv = node->OpenChannel(); - if (NS_SUCCEEDED(rv)) { - mCurrentNodes.AppendElement(node); - } else { - DispatchEvent(node, false); - } - } - while (NS_FAILED(rv)); -} - -void -nsPrefetchService::NotifyLoadRequested(nsPrefetchNode *node) -{ - nsCOMPtr<nsIObserverService> observerService = - mozilla::services::GetObserverService(); - if (!observerService) - return; - - observerService->NotifyObservers(static_cast<nsIStreamListener*>(node), - "prefetch-load-requested", nullptr); -} - -void -nsPrefetchService::NotifyLoadCompleted(nsPrefetchNode *node) -{ - nsCOMPtr<nsIObserverService> observerService = - mozilla::services::GetObserverService(); - if (!observerService) - return; - - observerService->NotifyObservers(static_cast<nsIStreamListener*>(node), - "prefetch-load-completed", nullptr); -} - -void -nsPrefetchService::DispatchEvent(nsPrefetchNode *node, bool aSuccess) -{ - for (uint32_t i = 0; i < node->mSources.Length(); i++) { - nsCOMPtr<nsINode> domNode = do_QueryReferent(node->mSources.ElementAt(i)); - if (domNode && domNode->IsInComposedDoc()) { - nsContentUtils::DispatchTrustedEvent(domNode->OwnerDoc(), - domNode, - aSuccess ? - NS_LITERAL_STRING("load") : - NS_LITERAL_STRING("error"), - /* aCanBubble = */ false, - /* aCancelable = */ false); - } - } -} - -//----------------------------------------------------------------------------- -// nsPrefetchService <private> -//----------------------------------------------------------------------------- - -void -nsPrefetchService::AddProgressListener() -{ - // Register as an observer for the document loader - nsCOMPtr<nsIWebProgress> progress = - do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID); - if (progress) - progress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT); -} - -void -nsPrefetchService::RemoveProgressListener() -{ - // Register as an observer for the document loader - nsCOMPtr<nsIWebProgress> progress = - do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID); - if (progress) - progress->RemoveProgressListener(this); -} - -nsresult -nsPrefetchService::EnqueueURI(nsIURI *aURI, - nsIURI *aReferrerURI, - nsIDOMNode *aSource, - nsPrefetchNode **aNode) -{ - RefPtr<nsPrefetchNode> node = new nsPrefetchNode(this, aURI, aReferrerURI, - aSource); - mQueue.push_back(node); - node.forget(aNode); - return NS_OK; -} - -void -nsPrefetchService::EmptyQueue() -{ - while (!mQueue.empty()) { - mQueue.pop_back(); - } -} - -void -nsPrefetchService::StartPrefetching() -{ - // - // at initialization time we might miss the first DOCUMENT START - // notification, so we have to be careful to avoid letting our - // stop count go negative. - // - if (mStopCount > 0) - mStopCount--; - - LOG(("StartPrefetching [stopcount=%d]\n", mStopCount)); - - // only start prefetching after we've received enough DOCUMENT - // STOP notifications. we do this inorder to defer prefetching - // until after all sub-frames have finished loading. - if (!mStopCount) { - mHaveProcessed = true; - while (!mQueue.empty() && mCurrentNodes.Length() < static_cast<uint32_t>(mMaxParallelism)) { - ProcessNextURI(nullptr); - } - } -} - -void -nsPrefetchService::StopPrefetching() -{ - mStopCount++; - - LOG(("StopPrefetching [stopcount=%d]\n", mStopCount)); - - // only kill the prefetch queue if we are actively prefetching right now - if (mCurrentNodes.IsEmpty()) { - return; - } - - for (uint32_t i = 0; i < mCurrentNodes.Length(); ++i) { - mCurrentNodes[i]->CancelChannel(NS_BINDING_ABORTED); - } - mCurrentNodes.Clear(); - EmptyQueue(); -} - -//----------------------------------------------------------------------------- -// nsPrefetchService::nsISupports -//----------------------------------------------------------------------------- - -NS_IMPL_ISUPPORTS(nsPrefetchService, - nsIPrefetchService, - nsIWebProgressListener, - nsIObserver, - nsISupportsWeakReference) - -//----------------------------------------------------------------------------- -// nsPrefetchService::nsIPrefetchService -//----------------------------------------------------------------------------- - -nsresult -nsPrefetchService::Prefetch(nsIURI *aURI, - nsIURI *aReferrerURI, - nsIDOMNode *aSource, - bool aExplicit) -{ - nsresult rv; - - NS_ENSURE_ARG_POINTER(aURI); - NS_ENSURE_ARG_POINTER(aReferrerURI); - - if (LOG_ENABLED()) { - LOG(("PrefetchURI [%s]\n", aURI->GetSpecOrDefault().get())); - } - - if (mDisabled) { - LOG(("rejected: prefetch service is disabled\n")); - return NS_ERROR_ABORT; - } - - // - // XXX we should really be asking the protocol handler if it supports - // caching, so we can determine if there is any value to prefetching. - // for now, we'll only prefetch http links since we know that's the - // most common case. ignore https links since https content only goes - // into the memory cache. - // - // XXX we might want to either leverage nsIProtocolHandler::protocolFlags - // or possibly nsIRequest::loadFlags to determine if this URI should be - // prefetched. - // - bool match; - rv = aURI->SchemeIs("http", &match); - if (NS_FAILED(rv) || !match) { - rv = aURI->SchemeIs("https", &match); - if (NS_FAILED(rv) || !match) { - LOG(("rejected: URL is not of type http/https\n")); - return NS_ERROR_ABORT; - } - } - - // - // the referrer URI must be http: - // - rv = aReferrerURI->SchemeIs("http", &match); - if (NS_FAILED(rv) || !match) { - rv = aReferrerURI->SchemeIs("https", &match); - if (NS_FAILED(rv) || !match) { - LOG(("rejected: referrer URL is neither http nor https\n")); - return NS_ERROR_ABORT; - } - } - - // skip URLs that contain query strings, except URLs for which prefetching - // has been explicitly requested. - if (!aExplicit) { - nsCOMPtr<nsIURL> url(do_QueryInterface(aURI, &rv)); - if (NS_FAILED(rv)) return rv; - nsAutoCString query; - rv = url->GetQuery(query); - if (NS_FAILED(rv) || !query.IsEmpty()) { - LOG(("rejected: URL has a query string\n")); - return NS_ERROR_ABORT; - } - } - - // - // Check whether it is being prefetched. - // - for (uint32_t i = 0; i < mCurrentNodes.Length(); ++i) { - bool equals; - if (NS_SUCCEEDED(mCurrentNodes[i]->mURI->Equals(aURI, &equals)) && - equals) { - nsCOMPtr<nsIWeakReference> source = do_GetWeakReference(aSource); - if (mCurrentNodes[i]->mSources.IndexOf(source) == - mCurrentNodes[i]->mSources.NoIndex) { - LOG(("URL is already being prefetched, add a new reference " - "document\n")); - mCurrentNodes[i]->mSources.AppendElement(source); - return NS_OK; - } else { - LOG(("URL is already being prefetched by this document")); - return NS_ERROR_ABORT; - } - } - } - - // - // Check whether it is on the prefetch queue. - // - for (std::deque<RefPtr<nsPrefetchNode>>::iterator nodeIt = mQueue.begin(); - nodeIt != mQueue.end(); nodeIt++) { - bool equals; - RefPtr<nsPrefetchNode> node = nodeIt->get(); - if (NS_SUCCEEDED(node->mURI->Equals(aURI, &equals)) && equals) { - nsCOMPtr<nsIWeakReference> source = do_GetWeakReference(aSource); - if (node->mSources.IndexOf(source) == - node->mSources.NoIndex) { - LOG(("URL is already being prefetched, add a new reference " - "document\n")); - node->mSources.AppendElement(do_GetWeakReference(aSource)); - return NS_OK; - } else { - LOG(("URL is already being prefetched by this document")); - return NS_ERROR_ABORT; - } - - } - } - - RefPtr<nsPrefetchNode> enqueuedNode; - rv = EnqueueURI(aURI, aReferrerURI, aSource, - getter_AddRefs(enqueuedNode)); - NS_ENSURE_SUCCESS(rv, rv); - - NotifyLoadRequested(enqueuedNode); - - // if there are no pages loading, kick off the request immediately - if (mStopCount == 0 && mHaveProcessed) { - ProcessNextURI(nullptr); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsPrefetchService::CancelPrefetchURI(nsIURI* aURI, - nsIDOMNode* aSource) -{ - NS_ENSURE_ARG_POINTER(aURI); - - if (LOG_ENABLED()) { - LOG(("CancelPrefetchURI [%s]\n", aURI->GetSpecOrDefault().get())); - } - - // - // look in current prefetches - // - for (uint32_t i = 0; i < mCurrentNodes.Length(); ++i) { - bool equals; - if (NS_SUCCEEDED(mCurrentNodes[i]->mURI->Equals(aURI, &equals)) && - equals) { - nsCOMPtr<nsIWeakReference> source = do_GetWeakReference(aSource); - if (mCurrentNodes[i]->mSources.IndexOf(source) != - mCurrentNodes[i]->mSources.NoIndex) { - mCurrentNodes[i]->mSources.RemoveElement(source); - if (mCurrentNodes[i]->mSources.IsEmpty()) { - mCurrentNodes[i]->CancelChannel(NS_BINDING_ABORTED); - mCurrentNodes.RemoveElementAt(i); - } - return NS_OK; - } - return NS_ERROR_FAILURE; - } - } - - // - // look into the prefetch queue - // - for (std::deque<RefPtr<nsPrefetchNode>>::iterator nodeIt = mQueue.begin(); - nodeIt != mQueue.end(); nodeIt++) { - bool equals; - RefPtr<nsPrefetchNode> node = nodeIt->get(); - if (NS_SUCCEEDED(node->mURI->Equals(aURI, &equals)) && equals) { - nsCOMPtr<nsIWeakReference> source = do_GetWeakReference(aSource); - if (node->mSources.IndexOf(source) != - node->mSources.NoIndex) { - -#ifdef DEBUG - int32_t inx = node->mSources.IndexOf(source); - nsCOMPtr<nsIDOMNode> domNode = - do_QueryReferent(node->mSources.ElementAt(inx)); - MOZ_ASSERT(domNode); -#endif - - node->mSources.RemoveElement(source); - if (node->mSources.IsEmpty()) { - mQueue.erase(nodeIt); - } - return NS_OK; - } - return NS_ERROR_FAILURE; - } - } - - // not found! - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -nsPrefetchService::PrefetchURI(nsIURI *aURI, - nsIURI *aReferrerURI, - nsIDOMNode *aSource, - bool aExplicit) -{ - return Prefetch(aURI, aReferrerURI, aSource, aExplicit); -} - -NS_IMETHODIMP -nsPrefetchService::HasMoreElements(bool *aHasMore) -{ - *aHasMore = (mCurrentNodes.Length() || !mQueue.empty()); - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsPrefetchService::nsIWebProgressListener -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsPrefetchService::OnProgressChange(nsIWebProgress *aProgress, - nsIRequest *aRequest, - int32_t curSelfProgress, - int32_t maxSelfProgress, - int32_t curTotalProgress, - int32_t maxTotalProgress) -{ - NS_NOTREACHED("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -NS_IMETHODIMP -nsPrefetchService::OnStateChange(nsIWebProgress* aWebProgress, - nsIRequest *aRequest, - uint32_t progressStateFlags, - nsresult aStatus) -{ - if (mAggressive) { - LOG(("Document load state is ignored in aggressive mode")); - return NS_OK; - } - - if (progressStateFlags & STATE_IS_DOCUMENT) { - if (progressStateFlags & STATE_STOP) - StartPrefetching(); - else if (progressStateFlags & STATE_START) - StopPrefetching(); - } - - return NS_OK; -} - - -NS_IMETHODIMP -nsPrefetchService::OnLocationChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - nsIURI *location, - uint32_t aFlags) -{ - NS_NOTREACHED("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -NS_IMETHODIMP -nsPrefetchService::OnStatusChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - nsresult aStatus, - const char16_t* aMessage) -{ - NS_NOTREACHED("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -NS_IMETHODIMP -nsPrefetchService::OnSecurityChange(nsIWebProgress *aWebProgress, - nsIRequest *aRequest, - uint32_t state) -{ - NS_NOTREACHED("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -//----------------------------------------------------------------------------- -// nsPrefetchService::nsIObserver -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -nsPrefetchService::Observe(nsISupports *aSubject, - const char *aTopic, - const char16_t *aData) -{ - LOG(("nsPrefetchService::Observe [topic=%s]\n", aTopic)); - - if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { - StopPrefetching(); - EmptyQueue(); - mDisabled = true; - } - else if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { - const nsCString converted = NS_ConvertUTF16toUTF8(aData); - const char* pref = converted.get(); - if (!strcmp(pref, PREFETCH_PREF)) { - if (Preferences::GetBool(PREFETCH_PREF, false)) { - if (mDisabled) { - LOG(("enabling prefetching\n")); - mDisabled = false; - AddProgressListener(); - } - } else { - if (!mDisabled) { - LOG(("disabling prefetching\n")); - StopPrefetching(); - EmptyQueue(); - mDisabled = true; - RemoveProgressListener(); - } - } - } else if (!strcmp(pref, PARALLELISM_PREF)) { - mMaxParallelism = Preferences::GetInt(PARALLELISM_PREF, mMaxParallelism); - if (mMaxParallelism < 1) { - mMaxParallelism = 1; - } - // If our parallelism has increased, go ahead and kick off enough - // prefetches to fill up our allowance. If we're now over our - // allowance, we'll just silently let some of them finish to get - // back below our limit. - while (!mQueue.empty() && mCurrentNodes.Length() < static_cast<uint32_t>(mMaxParallelism)) { - ProcessNextURI(nullptr); - } - } else if (!strcmp(pref, AGGRESSIVE_PREF)) { - mAggressive = Preferences::GetBool(AGGRESSIVE_PREF, false); - // in aggressive mode, clear stop count and start prefetching immediately - if (mAggressive) { - mStopCount = 0; - StartPrefetching(); - } - } - } - - return NS_OK; -} - -// vim: ts=4 sw=4 expandtab diff --git a/system/docshell/prefetch/nsPrefetchService.h b/system/docshell/prefetch/nsPrefetchService.h deleted file mode 100644 index 883449e68..000000000 --- a/system/docshell/prefetch/nsPrefetchService.h +++ /dev/null @@ -1,121 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsPrefetchService_h__ -#define nsPrefetchService_h__ - -#include "nsCPrefetchService.h" -#include "nsIObserver.h" -#include "nsIInterfaceRequestor.h" -#include "nsIChannelEventSink.h" -#include "nsIRedirectResultListener.h" -#include "nsIWebProgressListener.h" -#include "nsIStreamListener.h" -#include "nsIChannel.h" -#include "nsIURI.h" -#include "nsWeakReference.h" -#include "nsCOMPtr.h" -#include "nsAutoPtr.h" -#include "mozilla/Attributes.h" -#include <deque> - -class nsPrefetchService; -class nsPrefetchNode; - -//----------------------------------------------------------------------------- -// nsPrefetchService -//----------------------------------------------------------------------------- - -class nsPrefetchService final : public nsIPrefetchService - , public nsIWebProgressListener - , public nsIObserver - , public nsSupportsWeakReference -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIPREFETCHSERVICE - NS_DECL_NSIWEBPROGRESSLISTENER - NS_DECL_NSIOBSERVER - - nsPrefetchService(); - - nsresult Init(); - void ProcessNextURI(nsPrefetchNode *aFinished); - - void NotifyLoadRequested(nsPrefetchNode *node); - void NotifyLoadCompleted(nsPrefetchNode *node); - void DispatchEvent(nsPrefetchNode *node, bool aSuccess); - -private: - ~nsPrefetchService(); - - nsresult Prefetch(nsIURI *aURI, - nsIURI *aReferrerURI, - nsIDOMNode *aSource, - bool aExplicit); - - void AddProgressListener(); - void RemoveProgressListener(); - nsresult EnqueueURI(nsIURI *aURI, nsIURI *aReferrerURI, - nsIDOMNode *aSource, nsPrefetchNode **node); - void EmptyQueue(); - - void StartPrefetching(); - void StopPrefetching(); - - std::deque<RefPtr<nsPrefetchNode>> mQueue; - nsTArray<RefPtr<nsPrefetchNode>> mCurrentNodes; - int32_t mMaxParallelism; - int32_t mStopCount; - // true if pending document loads have ever reached zero. - int32_t mHaveProcessed; - bool mDisabled; - - // In usual case prefetch does not start until all normal loads are done. - // Aggressive mode ignores normal loads and just start prefetch ASAP. - // It's mainly for testing purpose and discoraged for normal use; - // see https://bugzilla.mozilla.org/show_bug.cgi?id=1281415 for details. - bool mAggressive; -}; - -//----------------------------------------------------------------------------- -// nsPrefetchNode -//----------------------------------------------------------------------------- - -class nsPrefetchNode final : public nsIStreamListener - , public nsIInterfaceRequestor - , public nsIChannelEventSink - , public nsIRedirectResultListener -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSICHANNELEVENTSINK - NS_DECL_NSIREDIRECTRESULTLISTENER - - nsPrefetchNode(nsPrefetchService *aPrefetchService, - nsIURI *aURI, - nsIURI *aReferrerURI, - nsIDOMNode *aSource); - - nsresult OpenChannel(); - nsresult CancelChannel(nsresult error); - - nsCOMPtr<nsIURI> mURI; - nsCOMPtr<nsIURI> mReferrerURI; - nsTArray<nsCOMPtr<nsIWeakReference>> mSources; - -private: - ~nsPrefetchNode() {} - - RefPtr<nsPrefetchService> mService; - nsCOMPtr<nsIChannel> mChannel; - nsCOMPtr<nsIChannel> mRedirectChannel; - int64_t mBytesRead; - bool mShouldFireLoadEvent; -}; - -#endif // !nsPrefetchService_h__ |