michael@0: /* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "OfflineCacheUpdateGlue.h" michael@0: #include "nsOfflineCacheUpdate.h" michael@0: #include "mozilla/Services.h" michael@0: michael@0: #include "nsIApplicationCache.h" michael@0: #include "nsIApplicationCacheChannel.h" michael@0: #include "nsIApplicationCacheContainer.h" michael@0: #include "nsIChannel.h" michael@0: #include "nsIDocument.h" michael@0: #include "prlog.h" michael@0: michael@0: #if defined(PR_LOGGING) michael@0: // michael@0: // To enable logging (see prlog.h for full details): michael@0: // michael@0: // set NSPR_LOG_MODULES=nsOfflineCacheUpdate:5 michael@0: // set NSPR_LOG_FILE=offlineupdate.log michael@0: // michael@0: // this enables PR_LOG_ALWAYS level information and places all output in michael@0: // the file offlineupdate.log michael@0: // michael@0: extern PRLogModuleInfo *gOfflineCacheUpdateLog; michael@0: #endif michael@0: michael@0: #undef LOG michael@0: #define LOG(args) PR_LOG(gOfflineCacheUpdateLog, 4, args) michael@0: michael@0: #undef LOG_ENABLED michael@0: #define LOG_ENABLED() PR_LOG_TEST(gOfflineCacheUpdateLog, 4) michael@0: michael@0: namespace mozilla { michael@0: namespace docshell { michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // OfflineCacheUpdateGlue::nsISupports michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: NS_IMPL_ISUPPORTS(OfflineCacheUpdateGlue, michael@0: nsIOfflineCacheUpdate, michael@0: nsIOfflineCacheUpdateObserver, michael@0: nsISupportsWeakReference) michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // OfflineCacheUpdateGlue michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: OfflineCacheUpdateGlue::OfflineCacheUpdateGlue() michael@0: { michael@0: LOG(("OfflineCacheUpdateGlue::OfflineCacheUpdateGlue [%p]", this)); michael@0: } michael@0: michael@0: OfflineCacheUpdateGlue::~OfflineCacheUpdateGlue() michael@0: { michael@0: LOG(("OfflineCacheUpdateGlue::~OfflineCacheUpdateGlue [%p]", this)); michael@0: } michael@0: michael@0: nsIOfflineCacheUpdate* michael@0: OfflineCacheUpdateGlue::EnsureUpdate() michael@0: { michael@0: if (!mUpdate) { michael@0: mUpdate = new nsOfflineCacheUpdate(); michael@0: LOG(("OfflineCacheUpdateGlue [%p] is using update [%p]", this, mUpdate.get())); michael@0: } michael@0: michael@0: return mUpdate; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: OfflineCacheUpdateGlue::Schedule() michael@0: { michael@0: nsCOMPtr observerService = michael@0: mozilla::services::GetObserverService(); michael@0: if (observerService) { michael@0: LOG(("Calling offline-cache-update-added")); michael@0: observerService->NotifyObservers(static_cast(this), michael@0: "offline-cache-update-added", michael@0: nullptr); michael@0: LOG(("Done offline-cache-update-added")); michael@0: } michael@0: michael@0: if (!EnsureUpdate()) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: // Do not use weak reference, we must survive! michael@0: mUpdate->AddObserver(this, false); michael@0: michael@0: return mUpdate->Schedule(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: OfflineCacheUpdateGlue::Init(nsIURI *aManifestURI, michael@0: nsIURI *aDocumentURI, michael@0: nsIDOMDocument *aDocument, michael@0: nsIFile *aCustomProfileDir, michael@0: uint32_t aAppID, michael@0: bool aInBrowser) michael@0: { michael@0: if (!EnsureUpdate()) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: mDocumentURI = aDocumentURI; michael@0: michael@0: if (aDocument) michael@0: SetDocument(aDocument); michael@0: michael@0: return mUpdate->Init(aManifestURI, aDocumentURI, nullptr, aCustomProfileDir, aAppID, aInBrowser); michael@0: } michael@0: michael@0: void michael@0: OfflineCacheUpdateGlue::SetDocument(nsIDOMDocument *aDocument) michael@0: { michael@0: // The design is one document for one cache update on the content process. michael@0: NS_ASSERTION(!mDocument, michael@0: "Setting more then a single document on an instance of OfflineCacheUpdateGlue"); michael@0: michael@0: LOG(("Document %p added to update glue %p", aDocument, this)); michael@0: michael@0: // Add document only if it was not loaded from an offline cache. michael@0: // If it were loaded from an offline cache then it has already michael@0: // been associated with it and must not be again cached as michael@0: // implicit (which are the reasons we collect documents here). michael@0: nsCOMPtr document = do_QueryInterface(aDocument); michael@0: if (!document) michael@0: return; michael@0: michael@0: nsIChannel* channel = document->GetChannel(); michael@0: nsCOMPtr appCacheChannel = michael@0: do_QueryInterface(channel); michael@0: if (!appCacheChannel) michael@0: return; michael@0: michael@0: bool loadedFromAppCache; michael@0: appCacheChannel->GetLoadedFromApplicationCache(&loadedFromAppCache); michael@0: if (loadedFromAppCache) michael@0: return; michael@0: michael@0: if (EnsureUpdate()) { michael@0: mUpdate->StickDocument(mDocumentURI); michael@0: } michael@0: michael@0: mDocument = aDocument; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: OfflineCacheUpdateGlue::UpdateStateChanged(nsIOfflineCacheUpdate *aUpdate, uint32_t state) michael@0: { michael@0: if (state == nsIOfflineCacheUpdateObserver::STATE_FINISHED) { michael@0: LOG(("OfflineCacheUpdateGlue got STATE_FINISHED [%p]", this)); michael@0: michael@0: nsCOMPtr observerService = michael@0: mozilla::services::GetObserverService(); michael@0: if (observerService) { michael@0: LOG(("Calling offline-cache-update-completed")); michael@0: observerService->NotifyObservers(static_cast(this), michael@0: "offline-cache-update-completed", michael@0: nullptr); michael@0: LOG(("Done offline-cache-update-completed")); michael@0: } michael@0: michael@0: aUpdate->RemoveObserver(this); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: OfflineCacheUpdateGlue::ApplicationCacheAvailable(nsIApplicationCache *aApplicationCache) michael@0: { michael@0: NS_ENSURE_ARG(aApplicationCache); michael@0: michael@0: // Check that the document that requested this update was michael@0: // previously associated with an application cache. If not, it michael@0: // should be associated with the new one. michael@0: nsCOMPtr container = michael@0: do_QueryInterface(mDocument); michael@0: if (!container) michael@0: return NS_OK; michael@0: michael@0: nsCOMPtr existingCache; michael@0: nsresult rv = container->GetApplicationCache(getter_AddRefs(existingCache)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (!existingCache) { michael@0: #if defined(PR_LOGGING) michael@0: if (LOG_ENABLED()) { michael@0: nsAutoCString clientID; michael@0: if (aApplicationCache) { michael@0: aApplicationCache->GetClientID(clientID); michael@0: } michael@0: LOG(("Update %p: associating app cache %s to document %p", michael@0: this, clientID.get(), mDocument.get())); michael@0: } michael@0: #endif michael@0: michael@0: rv = container->SetApplicationCache(aApplicationCache); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: } michael@0: }