summaryrefslogtreecommitdiffstats
path: root/netwerk/cache2/OldWrappers.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--netwerk/cache2/OldWrappers.cpp1037
1 files changed, 1037 insertions, 0 deletions
diff --git a/netwerk/cache2/OldWrappers.cpp b/netwerk/cache2/OldWrappers.cpp
new file mode 100644
index 0000000000..b96dc2ff29
--- /dev/null
+++ b/netwerk/cache2/OldWrappers.cpp
@@ -0,0 +1,1037 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+// Stuff to link the old imp to the new api - will go away!
+
+#include "CacheLog.h"
+#include "OldWrappers.h"
+#include "CacheStorage.h"
+#include "CacheStorageService.h"
+#include "LoadContextInfo.h"
+#include "nsCacheService.h"
+
+#include "nsIURI.h"
+#include "nsICacheSession.h"
+#include "nsIApplicationCache.h"
+#include "nsIApplicationCacheService.h"
+#include "nsIStreamTransportService.h"
+#include "nsIFile.h"
+#include "nsICacheEntryDoomCallback.h"
+#include "nsICacheListener.h"
+#include "nsICacheStorageVisitor.h"
+
+#include "nsServiceManagerUtils.h"
+#include "nsNetCID.h"
+#include "nsNetUtil.h"
+#include "nsProxyRelease.h"
+#include "mozilla/IntegerPrintfMacros.h"
+#include "mozilla/Telemetry.h"
+
+static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
+
+static uint32_t const CHECK_MULTITHREADED =
+ nsICacheStorage::CHECK_MULTITHREADED;
+
+namespace mozilla {
+namespace net {
+
+namespace {
+
+// Fires the doom callback back on the main thread
+// after the cache I/O thread is looped.
+
+class DoomCallbackSynchronizer : public Runnable {
+ public:
+ explicit DoomCallbackSynchronizer(nsICacheEntryDoomCallback* cb)
+ : Runnable("net::DoomCallbackSynchronizer"), mCB(cb) {}
+ nsresult Dispatch();
+
+ private:
+ virtual ~DoomCallbackSynchronizer() = default;
+
+ NS_DECL_NSIRUNNABLE
+ nsCOMPtr<nsICacheEntryDoomCallback> mCB;
+};
+
+nsresult DoomCallbackSynchronizer::Dispatch() {
+ nsresult rv;
+
+ nsCOMPtr<nsICacheService> serv =
+ do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIEventTarget> eventTarget;
+ rv = serv->GetCacheIOTarget(getter_AddRefs(eventTarget));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = eventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP DoomCallbackSynchronizer::Run() {
+ if (!NS_IsMainThread()) {
+ NS_DispatchToMainThread(this);
+ } else {
+ if (mCB) mCB->OnCacheEntryDoomed(NS_OK);
+ }
+ return NS_OK;
+}
+
+// Receives doom callback from the old API and forwards to the new API
+
+class DoomCallbackWrapper : public nsICacheListener {
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSICACHELISTENER
+
+ explicit DoomCallbackWrapper(nsICacheEntryDoomCallback* cb) : mCB(cb) {}
+
+ private:
+ virtual ~DoomCallbackWrapper() = default;
+
+ nsCOMPtr<nsICacheEntryDoomCallback> mCB;
+};
+
+NS_IMPL_ISUPPORTS(DoomCallbackWrapper, nsICacheListener);
+
+NS_IMETHODIMP DoomCallbackWrapper::OnCacheEntryAvailable(
+ nsICacheEntryDescriptor* descriptor, nsCacheAccessMode accessGranted,
+ nsresult status) {
+ return NS_OK;
+}
+
+NS_IMETHODIMP DoomCallbackWrapper::OnCacheEntryDoomed(nsresult status) {
+ if (!mCB) return NS_ERROR_NULL_POINTER;
+
+ mCB->OnCacheEntryDoomed(status);
+ mCB = nullptr;
+ return NS_OK;
+}
+
+} // namespace
+
+// _OldVisitCallbackWrapper
+// Receives visit callbacks from the old API and forwards it to the new API
+
+NS_IMPL_ISUPPORTS(_OldVisitCallbackWrapper, nsICacheVisitor)
+
+_OldVisitCallbackWrapper::~_OldVisitCallbackWrapper() {
+ if (!mHit) {
+ // The device has not been found, to not break the chain, simulate
+ // storage info callback.
+ mCB->OnCacheStorageInfo(0, 0, 0, nullptr);
+ }
+
+ if (mVisitEntries) {
+ mCB->OnCacheEntryVisitCompleted();
+ }
+}
+
+NS_IMETHODIMP _OldVisitCallbackWrapper::VisitDevice(
+ const char* deviceID, nsICacheDeviceInfo* deviceInfo, bool* _retval) {
+ if (!mCB) return NS_ERROR_NULL_POINTER;
+
+ *_retval = false;
+ if (strcmp(deviceID, mDeviceID)) {
+ // Not the device we want to visit
+ return NS_OK;
+ }
+
+ mHit = true;
+
+ nsresult rv;
+
+ uint32_t capacity;
+ rv = deviceInfo->GetMaximumSize(&capacity);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIFile> dir;
+ if (!strcmp(mDeviceID, "disk")) {
+ nsCacheService::GetDiskCacheDirectory(getter_AddRefs(dir));
+ } else if (!strcmp(mDeviceID, "offline")) {
+ nsCacheService::GetAppCacheDirectory(getter_AddRefs(dir));
+ }
+
+ if (mLoadInfo && mLoadInfo->IsAnonymous()) {
+ // Anonymous visiting reports 0, 0 since we cannot count that
+ // early the number of anon entries.
+ mCB->OnCacheStorageInfo(0, 0, capacity, dir);
+ } else {
+ // Non-anon visitor counts all non-anon + ALL ANON entries,
+ // there is no way to determine the number of entries when
+ // using the old cache APIs - there is no concept of anonymous
+ // storage.
+ uint32_t entryCount;
+ rv = deviceInfo->GetEntryCount(&entryCount);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t totalSize;
+ rv = deviceInfo->GetTotalSize(&totalSize);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mCB->OnCacheStorageInfo(entryCount, totalSize, capacity, dir);
+ }
+
+ *_retval = mVisitEntries;
+ return NS_OK;
+}
+
+NS_IMETHODIMP _OldVisitCallbackWrapper::VisitEntry(const char* deviceID,
+ nsICacheEntryInfo* entryInfo,
+ bool* _retval) {
+ MOZ_ASSERT(!strcmp(deviceID, mDeviceID));
+
+ nsresult rv;
+
+ *_retval = true;
+
+ // Read all informative properties from the entry.
+ nsAutoCString clientId;
+ rv = entryInfo->GetClientID(clientId);
+ if (NS_FAILED(rv)) return NS_OK;
+
+ if (mLoadInfo->IsPrivate() !=
+ StringBeginsWith(clientId, "HTTP-memory-only-PB"_ns)) {
+ return NS_OK;
+ }
+
+ nsAutoCString cacheKey, enhanceId;
+ rv = entryInfo->GetKey(cacheKey);
+ if (NS_FAILED(rv)) return NS_OK;
+
+ if (StringBeginsWith(cacheKey, "anon&"_ns)) {
+ if (!mLoadInfo->IsAnonymous()) return NS_OK;
+
+ cacheKey = Substring(cacheKey, 5, cacheKey.Length());
+ } else if (mLoadInfo->IsAnonymous()) {
+ return NS_OK;
+ }
+
+ if (StringBeginsWith(cacheKey, "id="_ns)) {
+ int32_t uriSpecEnd = cacheKey.Find("&uri=");
+ if (uriSpecEnd == kNotFound) // Corrupted, ignore
+ return NS_OK;
+
+ enhanceId = Substring(cacheKey, 3, uriSpecEnd - 3);
+ cacheKey = Substring(cacheKey, uriSpecEnd + 1, cacheKey.Length());
+ }
+
+ if (StringBeginsWith(cacheKey, "uri="_ns)) {
+ cacheKey = Substring(cacheKey, 4, cacheKey.Length());
+ }
+
+ nsCOMPtr<nsIURI> uri;
+ // cacheKey is strip of any prefixes
+ rv = NS_NewURI(getter_AddRefs(uri), cacheKey);
+ if (NS_FAILED(rv)) return NS_OK;
+
+ uint32_t dataSize;
+ if (NS_FAILED(entryInfo->GetDataSize(&dataSize))) dataSize = 0;
+ int32_t fetchCount;
+ if (NS_FAILED(entryInfo->GetFetchCount(&fetchCount))) fetchCount = 0;
+ uint32_t expirationTime;
+ if (NS_FAILED(entryInfo->GetExpirationTime(&expirationTime)))
+ expirationTime = 0;
+ uint32_t lastModified;
+ if (NS_FAILED(entryInfo->GetLastModified(&lastModified))) lastModified = 0;
+
+ // Send them to the consumer.
+ rv = mCB->OnCacheEntryInfo(uri, enhanceId, (int64_t)dataSize, fetchCount,
+ lastModified, expirationTime, false, mLoadInfo);
+
+ *_retval = NS_SUCCEEDED(rv);
+ return NS_OK;
+}
+
+// _OldGetDiskConsumption
+
+// static
+nsresult _OldGetDiskConsumption::Get(
+ nsICacheStorageConsumptionObserver* aCallback) {
+ nsresult rv;
+
+ nsCOMPtr<nsICacheService> serv =
+ do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ RefPtr<_OldGetDiskConsumption> cb = new _OldGetDiskConsumption(aCallback);
+
+ // _OldGetDiskConsumption stores the found size value, but until dispatched
+ // to the main thread it doesn't call on the consupmtion observer. See bellow.
+ rv = serv->VisitEntries(cb);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // We are called from CacheStorageService::AsyncGetDiskConsumption whose IDL
+ // documentation claims the callback is always delievered asynchronously
+ // back to the main thread. Despite we know the result synchronosusly when
+ // querying the old cache, we need to stand the word and dispatch the result
+ // to the main thread asynchronously. Hence the dispatch here.
+ return NS_DispatchToMainThread(cb);
+}
+
+NS_IMPL_ISUPPORTS_INHERITED(_OldGetDiskConsumption, Runnable, nsICacheVisitor)
+
+_OldGetDiskConsumption::_OldGetDiskConsumption(
+ nsICacheStorageConsumptionObserver* aCallback)
+ : Runnable("net::_OldGetDiskConsumption"), mCallback(aCallback), mSize(0) {}
+
+NS_IMETHODIMP
+_OldGetDiskConsumption::Run() {
+ mCallback->OnNetworkCacheDiskConsumption(mSize);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+_OldGetDiskConsumption::VisitDevice(const char* deviceID,
+ nsICacheDeviceInfo* deviceInfo,
+ bool* _retval) {
+ if (!strcmp(deviceID, "disk")) {
+ uint32_t size;
+ nsresult rv = deviceInfo->GetTotalSize(&size);
+ if (NS_SUCCEEDED(rv)) mSize = (int64_t)size;
+ }
+
+ *_retval = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+_OldGetDiskConsumption::VisitEntry(const char* deviceID,
+ nsICacheEntryInfo* entryInfo,
+ bool* _retval) {
+ MOZ_CRASH("Unexpected");
+ return NS_OK;
+}
+
+// _OldCacheEntryWrapper
+
+_OldCacheEntryWrapper::_OldCacheEntryWrapper(nsICacheEntryDescriptor* desc)
+ : mOldDesc(desc), mOldInfo(desc), mCacheEntryId(CacheEntry::GetNextId()) {
+ LOG(("Creating _OldCacheEntryWrapper %p for descriptor %p", this, desc));
+}
+
+_OldCacheEntryWrapper::_OldCacheEntryWrapper(nsICacheEntryInfo* info)
+ : mOldDesc(nullptr),
+ mOldInfo(info),
+ mCacheEntryId(CacheEntry::GetNextId()) {
+ LOG(("Creating _OldCacheEntryWrapper %p for info %p", this, info));
+}
+
+_OldCacheEntryWrapper::~_OldCacheEntryWrapper() {
+ LOG(("Destroying _OldCacheEntryWrapper %p for descriptor %p", this,
+ mOldInfo.get()));
+}
+
+NS_IMETHODIMP _OldCacheEntryWrapper::GetIsForcedValid(bool* aIsForcedValid) {
+ // Unused stub
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP _OldCacheEntryWrapper::ForceValidFor(
+ uint32_t aSecondsToTheFuture) {
+ // Unused stub
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMPL_ISUPPORTS(_OldCacheEntryWrapper, nsICacheEntry)
+
+NS_IMETHODIMP _OldCacheEntryWrapper::AsyncDoom(
+ nsICacheEntryDoomCallback* listener) {
+ RefPtr<DoomCallbackWrapper> cb =
+ listener ? new DoomCallbackWrapper(listener) : nullptr;
+ return AsyncDoom(cb);
+}
+
+NS_IMETHODIMP _OldCacheEntryWrapper::GetDataSize(int64_t* aSize) {
+ uint32_t size;
+ nsresult rv = GetDataSize(&size);
+ if (NS_FAILED(rv)) return rv;
+
+ *aSize = size;
+ return NS_OK;
+}
+
+NS_IMETHODIMP _OldCacheEntryWrapper::GetAltDataSize(int64_t* aSize) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP _OldCacheEntryWrapper::GetAltDataType(nsACString& aType) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP _OldCacheEntryWrapper::GetPersistent(bool* aPersistToDisk) {
+ if (!mOldDesc) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ nsresult rv;
+
+ nsCacheStoragePolicy policy;
+ rv = mOldDesc->GetStoragePolicy(&policy);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ *aPersistToDisk = policy != nsICache::STORE_IN_MEMORY;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP _OldCacheEntryWrapper::Recreate(bool aMemoryOnly,
+ nsICacheEntry** aResult) {
+ NS_ENSURE_TRUE(mOldDesc, NS_ERROR_NOT_AVAILABLE);
+
+ nsCacheAccessMode mode;
+ nsresult rv = mOldDesc->GetAccessGranted(&mode);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!(mode & nsICache::ACCESS_WRITE)) return NS_ERROR_NOT_AVAILABLE;
+
+ LOG(("_OldCacheEntryWrapper::Recreate [this=%p]", this));
+
+ if (aMemoryOnly) mOldDesc->SetStoragePolicy(nsICache::STORE_IN_MEMORY);
+
+ nsCOMPtr<nsICacheEntry> self(this);
+ self.forget(aResult);
+ return NS_OK;
+}
+
+NS_IMETHODIMP _OldCacheEntryWrapper::OpenInputStream(int64_t offset,
+ nsIInputStream** _retval) {
+ if (offset > PR_UINT32_MAX) return NS_ERROR_INVALID_ARG;
+
+ return OpenInputStream(uint32_t(offset), _retval);
+}
+NS_IMETHODIMP _OldCacheEntryWrapper::OpenOutputStream(
+ int64_t offset, int64_t predictedSize, nsIOutputStream** _retval) {
+ if (offset > PR_UINT32_MAX) return NS_ERROR_INVALID_ARG;
+
+ return OpenOutputStream(uint32_t(offset), _retval);
+}
+
+NS_IMETHODIMP _OldCacheEntryWrapper::MaybeMarkValid() {
+ LOG(("_OldCacheEntryWrapper::MaybeMarkValid [this=%p]", this));
+
+ NS_ENSURE_TRUE(mOldDesc, NS_ERROR_NULL_POINTER);
+
+ nsCacheAccessMode mode;
+ nsresult rv = mOldDesc->GetAccessGranted(&mode);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (mode & nsICache::ACCESS_WRITE) {
+ LOG(("Marking cache entry valid [entry=%p, descr=%p]", this, mOldDesc));
+ return mOldDesc->MarkValid();
+ }
+
+ LOG(("Not marking read-only cache entry valid [entry=%p, descr=%p]", this,
+ mOldDesc));
+ return NS_OK;
+}
+
+NS_IMETHODIMP _OldCacheEntryWrapper::HasWriteAccess(bool aWriteAllowed_unused,
+ bool* aWriteAccess) {
+ NS_ENSURE_TRUE(mOldDesc, NS_ERROR_NULL_POINTER);
+ NS_ENSURE_ARG(aWriteAccess);
+
+ nsCacheAccessMode mode;
+ nsresult rv = mOldDesc->GetAccessGranted(&mode);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ *aWriteAccess = !!(mode & nsICache::ACCESS_WRITE);
+
+ LOG(("_OldCacheEntryWrapper::HasWriteAccess [this=%p, write-access=%d]", this,
+ *aWriteAccess));
+
+ return NS_OK;
+}
+
+namespace {
+
+class MetaDataVisitorWrapper : public nsICacheMetaDataVisitor {
+ virtual ~MetaDataVisitorWrapper() = default;
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICACHEMETADATAVISITOR
+ explicit MetaDataVisitorWrapper(nsICacheEntryMetaDataVisitor* cb) : mCB(cb) {}
+ nsCOMPtr<nsICacheEntryMetaDataVisitor> mCB;
+};
+
+NS_IMPL_ISUPPORTS(MetaDataVisitorWrapper, nsICacheMetaDataVisitor)
+
+NS_IMETHODIMP
+MetaDataVisitorWrapper::VisitMetaDataElement(char const* key, char const* value,
+ bool* goon) {
+ *goon = true;
+ return mCB->OnMetaDataElement(key, value);
+}
+
+} // namespace
+
+NS_IMETHODIMP _OldCacheEntryWrapper::VisitMetaData(
+ nsICacheEntryMetaDataVisitor* cb) {
+ RefPtr<MetaDataVisitorWrapper> w = new MetaDataVisitorWrapper(cb);
+ return mOldDesc->VisitMetaData(w);
+}
+
+namespace {
+
+void GetCacheSessionNameForStoragePolicy(const nsACString& scheme,
+ nsCacheStoragePolicy storagePolicy,
+ bool isPrivate,
+ OriginAttributes const* originAttribs,
+ nsACString& sessionName) {
+ MOZ_ASSERT(!isPrivate || storagePolicy == nsICache::STORE_IN_MEMORY);
+
+ // HTTP
+ if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https")) {
+ switch (storagePolicy) {
+ case nsICache::STORE_IN_MEMORY:
+ if (isPrivate)
+ sessionName.AssignLiteral("HTTP-memory-only-PB");
+ else
+ sessionName.AssignLiteral("HTTP-memory-only");
+ break;
+ case nsICache::STORE_OFFLINE:
+ // XXX This is actually never used, only added to prevent
+ // any compatibility damage.
+ sessionName.AssignLiteral("HTTP-offline");
+ break;
+ default:
+ sessionName.AssignLiteral("HTTP");
+ break;
+ }
+ }
+ // FTP
+ else if (scheme.EqualsLiteral("ftp")) {
+ if (isPrivate)
+ sessionName.AssignLiteral("FTP-private");
+ else
+ sessionName.AssignLiteral("FTP");
+ }
+ // all remaining URL scheme
+ else {
+ // Since with the new API a consumer cannot specify its own session name
+ // and partitioning of the cache is handled stricly only by the cache
+ // back-end internally, we will use a separate session name to pretend
+ // functionality of the new API wrapping the Darin's cache for all other
+ // URL schemes.
+ // Deliberately omitting |anonymous| since other session types don't
+ // recognize it too.
+ sessionName.AssignLiteral("other");
+ if (isPrivate) sessionName.AppendLiteral("-private");
+ }
+
+ nsAutoCString suffix;
+ originAttribs->CreateSuffix(suffix);
+ sessionName.Append(suffix);
+}
+
+nsresult GetCacheSession(const nsACString& aScheme, bool aWriteToDisk,
+ nsILoadContextInfo* aLoadInfo,
+ nsIApplicationCache* aAppCache,
+ nsICacheSession** _result) {
+ nsresult rv;
+
+ nsCacheStoragePolicy storagePolicy;
+ if (aAppCache)
+ storagePolicy = nsICache::STORE_OFFLINE;
+ else if (!aWriteToDisk || aLoadInfo->IsPrivate())
+ storagePolicy = nsICache::STORE_IN_MEMORY;
+ else
+ storagePolicy = nsICache::STORE_ANYWHERE;
+
+ nsAutoCString clientId;
+ if (aAppCache) {
+ aAppCache->GetClientID(clientId);
+ } else {
+ GetCacheSessionNameForStoragePolicy(
+ aScheme, storagePolicy, aLoadInfo->IsPrivate(),
+ aLoadInfo->OriginAttributesPtr(), clientId);
+ }
+
+ LOG((" GetCacheSession for client=%s, policy=%d", clientId.get(),
+ storagePolicy));
+
+ nsCOMPtr<nsICacheService> serv =
+ do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsICacheSession> session;
+ rv = nsCacheService::GlobalInstance()->CreateSessionInternal(
+ clientId.get(), storagePolicy, nsICache::STREAM_BASED,
+ getter_AddRefs(session));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = session->SetIsPrivate(aLoadInfo->IsPrivate());
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = session->SetDoomEntriesIfExpired(false);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (aAppCache) {
+ nsCOMPtr<nsIFile> profileDirectory;
+ aAppCache->GetProfileDirectory(getter_AddRefs(profileDirectory));
+ if (profileDirectory) rv = session->SetProfileDirectory(profileDirectory);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ session.forget(_result);
+ return NS_OK;
+}
+
+} // namespace
+
+NS_IMPL_ISUPPORTS_INHERITED(_OldCacheLoad, Runnable, nsICacheListener)
+
+_OldCacheLoad::_OldCacheLoad(const nsACString& aScheme,
+ const nsACString& aCacheKey,
+ nsICacheEntryOpenCallback* aCallback,
+ nsIApplicationCache* aAppCache,
+ nsILoadContextInfo* aLoadInfo, bool aWriteToDisk,
+ uint32_t aFlags)
+ : Runnable("net::_OldCacheLoad"),
+ mScheme(aScheme),
+ mCacheKey(aCacheKey),
+ mCallback(aCallback),
+ mLoadInfo(GetLoadContextInfo(aLoadInfo)),
+ mFlags(aFlags),
+ mWriteToDisk(aWriteToDisk),
+ mNew(true),
+ mOpening(true),
+ mSync(false),
+ mStatus(NS_ERROR_UNEXPECTED),
+ mRunCount(0),
+ mAppCache(aAppCache) {}
+
+_OldCacheLoad::~_OldCacheLoad() {
+ ProxyReleaseMainThread("_OldCacheLoad::mAppCache", mAppCache);
+}
+
+nsresult _OldCacheLoad::Start() {
+ LOG(("_OldCacheLoad::Start [this=%p, key=%s]", this, mCacheKey.get()));
+
+ mLoadStart = mozilla::TimeStamp::Now();
+
+ nsresult rv;
+
+ // Consumers that can invoke this code as first and off the main thread
+ // are responsible for initiating these two services on the main thread.
+ // Currently no one does that.
+
+ // XXX: Start the cache service; otherwise DispatchToCacheIOThread will
+ // fail.
+ nsCOMPtr<nsICacheService> service =
+ do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
+
+ // Ensure the stream transport service gets initialized on the main thread
+ if (NS_SUCCEEDED(rv) && NS_IsMainThread()) {
+ nsCOMPtr<nsIStreamTransportService> sts =
+ do_GetService(kStreamTransportServiceCID, &rv);
+ }
+
+ if (NS_SUCCEEDED(rv)) {
+ rv = service->GetCacheIOTarget(getter_AddRefs(mCacheThread));
+ }
+
+ if (NS_SUCCEEDED(rv)) {
+ bool onCacheTarget;
+ rv = mCacheThread->IsOnCurrentThread(&onCacheTarget);
+ if (NS_SUCCEEDED(rv) && onCacheTarget) {
+ mSync = true;
+ }
+ }
+
+ if (NS_SUCCEEDED(rv)) {
+ if (mSync) {
+ rv = Run();
+ } else {
+ rv = mCacheThread->Dispatch(this, NS_DISPATCH_NORMAL);
+ }
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+_OldCacheLoad::Run() {
+ LOG(("_OldCacheLoad::Run [this=%p, key=%s, cb=%p]", this, mCacheKey.get(),
+ mCallback.get()));
+
+ nsresult rv;
+
+ if (mOpening) {
+ mOpening = false;
+ nsCOMPtr<nsICacheSession> session;
+ rv = GetCacheSession(mScheme, mWriteToDisk, mLoadInfo, mAppCache,
+ getter_AddRefs(session));
+ if (NS_SUCCEEDED(rv)) {
+ // AsyncOpenCacheEntry isn't really async when its called on the
+ // cache service thread.
+
+ nsCacheAccessMode cacheAccess;
+ if (mFlags & nsICacheStorage::OPEN_TRUNCATE)
+ cacheAccess = nsICache::ACCESS_WRITE;
+ else if ((mFlags & nsICacheStorage::OPEN_READONLY) || mAppCache)
+ cacheAccess = nsICache::ACCESS_READ;
+ else
+ cacheAccess = nsICache::ACCESS_READ_WRITE;
+
+ LOG((" session->AsyncOpenCacheEntry with access=%d", cacheAccess));
+
+ bool bypassBusy = mFlags & nsICacheStorage::OPEN_BYPASS_IF_BUSY;
+
+ if (mSync && cacheAccess == nsICache::ACCESS_WRITE) {
+ nsCOMPtr<nsICacheEntryDescriptor> entry;
+ rv = session->OpenCacheEntry(mCacheKey, cacheAccess, bypassBusy,
+ getter_AddRefs(entry));
+
+ nsCacheAccessMode grantedAccess = 0;
+ if (NS_SUCCEEDED(rv)) {
+ entry->GetAccessGranted(&grantedAccess);
+ }
+
+ return OnCacheEntryAvailable(entry, grantedAccess, rv);
+ }
+
+ rv = session->AsyncOpenCacheEntry(mCacheKey, cacheAccess, this,
+ bypassBusy);
+ if (NS_SUCCEEDED(rv)) return NS_OK;
+ }
+
+ // Opening failed, propagate the error to the consumer
+ LOG((" Opening cache entry failed with rv=0x%08" PRIx32,
+ static_cast<uint32_t>(rv)));
+ mStatus = rv;
+ mNew = false;
+ NS_DispatchToMainThread(this);
+ } else {
+ if (!mCallback) {
+ LOG((" duplicate call, bypassed"));
+ return NS_OK;
+ }
+
+ if (NS_SUCCEEDED(mStatus)) {
+ if (mFlags & nsICacheStorage::OPEN_TRUNCATE) {
+ mozilla::Telemetry::AccumulateTimeDelta(
+ mozilla::Telemetry::NETWORK_CACHE_V1_TRUNCATE_TIME_MS, mLoadStart);
+ } else if (mNew) {
+ mozilla::Telemetry::AccumulateTimeDelta(
+ mozilla::Telemetry::NETWORK_CACHE_V1_MISS_TIME_MS, mLoadStart);
+ } else {
+ mozilla::Telemetry::AccumulateTimeDelta(
+ mozilla::Telemetry::NETWORK_CACHE_V1_HIT_TIME_MS, mLoadStart);
+ }
+ }
+
+ if (!(mFlags & CHECK_MULTITHREADED)) Check();
+
+ // break cycles
+ nsCOMPtr<nsICacheEntryOpenCallback> cb = std::move(mCallback);
+ mCacheThread = nullptr;
+ nsCOMPtr<nsICacheEntry> entry = std::move(mCacheEntry);
+
+ rv = cb->OnCacheEntryAvailable(entry, mNew, mAppCache, mStatus);
+
+ if (NS_FAILED(rv) && entry) {
+ LOG((" cb->OnCacheEntryAvailable failed with rv=0x%08" PRIx32,
+ static_cast<uint32_t>(rv)));
+ if (mNew)
+ entry->AsyncDoom(nullptr);
+ else
+ entry->Close();
+ }
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+_OldCacheLoad::OnCacheEntryAvailable(nsICacheEntryDescriptor* entry,
+ nsCacheAccessMode access,
+ nsresult status) {
+ LOG(
+ ("_OldCacheLoad::OnCacheEntryAvailable [this=%p, ent=%p, cb=%p, "
+ "appcache=%p, access=%x]",
+ this, entry, mCallback.get(), mAppCache.get(), access));
+
+ // XXX Bug 759805: Sometimes we will call this method directly from
+ // HttpCacheQuery::Run when AsyncOpenCacheEntry fails, but
+ // AsyncOpenCacheEntry will also call this method. As a workaround, we just
+ // ensure we only execute this code once.
+ NS_ENSURE_TRUE(mRunCount == 0, NS_ERROR_UNEXPECTED);
+ ++mRunCount;
+
+ mCacheEntry = entry ? new _OldCacheEntryWrapper(entry) : nullptr;
+ mStatus = status;
+ mNew = access == nsICache::ACCESS_WRITE;
+
+ if (mFlags & CHECK_MULTITHREADED) Check();
+
+ if (mSync) return Run();
+
+ return NS_DispatchToMainThread(this);
+}
+
+void _OldCacheLoad::Check() {
+ if (!mCacheEntry) return;
+
+ if (mNew) return;
+
+ uint32_t result;
+ nsresult rv = mCallback->OnCacheEntryCheck(mCacheEntry, mAppCache, &result);
+ LOG((" OnCacheEntryCheck result ent=%p, cb=%p, appcache=%p, rv=0x%08" PRIx32
+ ", result=%d",
+ mCacheEntry.get(), mCallback.get(), mAppCache.get(),
+ static_cast<uint32_t>(rv), result));
+
+ if (NS_FAILED(rv)) {
+ NS_WARNING("cache check failed");
+ }
+
+ if (NS_FAILED(rv) || result == nsICacheEntryOpenCallback::ENTRY_NOT_WANTED) {
+ mCacheEntry->Close();
+ mCacheEntry = nullptr;
+ mStatus = NS_ERROR_CACHE_KEY_NOT_FOUND;
+ }
+}
+
+NS_IMETHODIMP
+_OldCacheLoad::OnCacheEntryDoomed(nsresult) { return NS_ERROR_NOT_IMPLEMENTED; }
+
+// nsICacheStorage old cache wrapper
+
+NS_IMPL_ISUPPORTS(_OldStorage, nsICacheStorage)
+
+_OldStorage::_OldStorage(nsILoadContextInfo* aInfo, bool aAllowDisk,
+ bool aLookupAppCache, bool aOfflineStorage,
+ nsIApplicationCache* aAppCache)
+ : mLoadInfo(GetLoadContextInfo(aInfo)),
+ mAppCache(aAppCache),
+ mWriteToDisk(aAllowDisk),
+ mLookupAppCache(aLookupAppCache),
+ mOfflineStorage(aOfflineStorage) {}
+
+_OldStorage::~_OldStorage() = default;
+
+NS_IMETHODIMP _OldStorage::AsyncOpenURI(nsIURI* aURI,
+ const nsACString& aIdExtension,
+ uint32_t aFlags,
+ nsICacheEntryOpenCallback* aCallback) {
+ NS_ENSURE_ARG(aURI);
+ NS_ENSURE_ARG(aCallback);
+
+#ifdef MOZ_LOGGING
+ nsAutoCString uriSpec;
+ aURI->GetAsciiSpec(uriSpec);
+ LOG(("_OldStorage::AsyncOpenURI [this=%p, uri=%s, ide=%s, flags=%x]", this,
+ uriSpec.get(), aIdExtension.BeginReading(), aFlags));
+#endif
+
+ nsresult rv;
+
+ nsAutoCString cacheKey, scheme;
+ rv = AssembleCacheKey(aURI, aIdExtension, cacheKey, scheme);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!mAppCache && (mLookupAppCache || mOfflineStorage)) {
+ rv = ChooseApplicationCache(cacheKey, getter_AddRefs(mAppCache));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (mAppCache) {
+ // From a chosen appcache open only as readonly
+ aFlags &= ~nsICacheStorage::OPEN_TRUNCATE;
+ }
+ }
+
+ RefPtr<_OldCacheLoad> cacheLoad = new _OldCacheLoad(
+ scheme, cacheKey, aCallback, mAppCache, mLoadInfo, mWriteToDisk, aFlags);
+
+ rv = cacheLoad->Start();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP _OldStorage::OpenTruncate(nsIURI* aURI,
+ const nsACString& aIdExtension,
+ nsICacheEntry** aCacheEntry) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP _OldStorage::Exists(nsIURI* aURI, const nsACString& aIdExtension,
+ bool* aResult) {
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP _OldStorage::AsyncDoomURI(nsIURI* aURI,
+ const nsACString& aIdExtension,
+ nsICacheEntryDoomCallback* aCallback) {
+ LOG(("_OldStorage::AsyncDoomURI"));
+
+ nsresult rv;
+
+ nsAutoCString cacheKey, scheme;
+ rv = AssembleCacheKey(aURI, aIdExtension, cacheKey, scheme);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsICacheSession> session;
+ rv = GetCacheSession(scheme, mWriteToDisk, mLoadInfo, mAppCache,
+ getter_AddRefs(session));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ RefPtr<DoomCallbackWrapper> cb =
+ aCallback ? new DoomCallbackWrapper(aCallback) : nullptr;
+ rv = session->DoomEntry(cacheKey, cb);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP _OldStorage::AsyncEvictStorage(
+ nsICacheEntryDoomCallback* aCallback) {
+ LOG(("_OldStorage::AsyncEvictStorage"));
+
+ nsresult rv;
+
+ if (!mAppCache && mOfflineStorage) {
+ nsCOMPtr<nsIApplicationCacheService> appCacheService =
+ do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = appCacheService->Evict(mLoadInfo);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else if (mAppCache) {
+ nsCOMPtr<nsICacheSession> session;
+ rv = GetCacheSession(""_ns, mWriteToDisk, mLoadInfo, mAppCache,
+ getter_AddRefs(session));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = session->EvictEntries();
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ // Oh, I'll be so happy when session names are gone...
+ nsCOMPtr<nsICacheSession> session;
+ rv = GetCacheSession("http"_ns, mWriteToDisk, mLoadInfo, mAppCache,
+ getter_AddRefs(session));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = session->EvictEntries();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // This clears any data from schemes other than http or ftp.
+ rv = GetCacheSession(""_ns, mWriteToDisk, mLoadInfo, mAppCache,
+ getter_AddRefs(session));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = session->EvictEntries();
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ if (aCallback) {
+ RefPtr<DoomCallbackSynchronizer> sync =
+ new DoomCallbackSynchronizer(aCallback);
+ rv = sync->Dispatch();
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP _OldStorage::AsyncVisitStorage(nsICacheStorageVisitor* aVisitor,
+ bool aVisitEntries) {
+ LOG(("_OldStorage::AsyncVisitStorage"));
+
+ NS_ENSURE_ARG(aVisitor);
+
+ nsresult rv;
+
+ nsCOMPtr<nsICacheService> serv =
+ do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ char* deviceID;
+ if (mAppCache || mOfflineStorage) {
+ deviceID = const_cast<char*>("offline");
+ } else if (!mWriteToDisk || mLoadInfo->IsPrivate()) {
+ deviceID = const_cast<char*>("memory");
+ } else {
+ deviceID = const_cast<char*>("disk");
+ }
+
+ RefPtr<_OldVisitCallbackWrapper> cb = new _OldVisitCallbackWrapper(
+ deviceID, aVisitor, aVisitEntries, mLoadInfo);
+ rv = nsCacheService::GlobalInstance()->VisitEntriesInternal(cb);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP _OldStorage::GetCacheIndexEntryAttrs(
+ nsIURI* aURI, const nsACString& aIdExtension, bool* aHasAltData,
+ uint32_t* aSizeInKB) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// Internal
+
+nsresult _OldStorage::AssembleCacheKey(nsIURI* aURI,
+ nsACString const& aIdExtension,
+ nsACString& aCacheKey,
+ nsACString& aScheme) {
+ // Copied from nsHttpChannel::AssembleCacheKey
+
+ aCacheKey.Truncate();
+
+ nsresult rv;
+
+ rv = aURI->GetScheme(aScheme);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoCString uriSpec;
+ if (aScheme.EqualsLiteral("http") || aScheme.EqualsLiteral("https")) {
+ if (mLoadInfo->IsAnonymous()) {
+ aCacheKey.AssignLiteral("anon&");
+ }
+
+ if (!aIdExtension.IsEmpty()) {
+ aCacheKey.AppendPrintf("id=%s&", aIdExtension.BeginReading());
+ }
+
+ nsCOMPtr<nsIURI> noRefURI;
+ rv = NS_GetURIWithoutRef(aURI, getter_AddRefs(noRefURI));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = noRefURI->GetAsciiSpec(uriSpec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!aCacheKey.IsEmpty()) {
+ aCacheKey.AppendLiteral("uri=");
+ }
+ } else {
+ rv = aURI->GetAsciiSpec(uriSpec);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ aCacheKey.Append(uriSpec);
+
+ return NS_OK;
+}
+
+nsresult _OldStorage::ChooseApplicationCache(const nsACString& cacheKey,
+ nsIApplicationCache** aCache) {
+ nsresult rv;
+
+ nsCOMPtr<nsIApplicationCacheService> appCacheService =
+ do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = appCacheService->ChooseApplicationCache(cacheKey, mLoadInfo, aCache);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+} // namespace net
+} // namespace mozilla