Bug 1468501 - Implement a way to delete network cache by nsIPrincipal, r=mayhemer, r=michal

This commit is contained in:
Andrea Marchesini 2018-07-20 13:57:18 +02:00
parent d55ae44eff
commit 28962b5168
10 changed files with 297 additions and 55 deletions

View file

@ -16,6 +16,7 @@
#include "nsIDirectoryEnumerator.h" #include "nsIDirectoryEnumerator.h"
#include "mozilla/Base64.h" #include "mozilla/Base64.h"
#include "mozilla/IntegerPrintfMacros.h" #include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/net/MozURL.h"
namespace mozilla { namespace mozilla {
@ -93,7 +94,8 @@ CacheFileContextEvictor::ContextsCount()
nsresult nsresult
CacheFileContextEvictor::AddContext(nsILoadContextInfo *aLoadContextInfo, CacheFileContextEvictor::AddContext(nsILoadContextInfo *aLoadContextInfo,
bool aPinned) bool aPinned,
const nsAString& aOrigin)
{ {
LOG(("CacheFileContextEvictor::AddContext() [this=%p, loadContextInfo=%p, pinned=%d]", LOG(("CacheFileContextEvictor::AddContext() [this=%p, loadContextInfo=%p, pinned=%d]",
this, aLoadContextInfo, aPinned)); this, aLoadContextInfo, aPinned));
@ -107,7 +109,8 @@ CacheFileContextEvictor::AddContext(nsILoadContextInfo *aLoadContextInfo,
for (uint32_t i = 0; i < mEntries.Length(); ++i) { for (uint32_t i = 0; i < mEntries.Length(); ++i) {
if (mEntries[i]->mInfo && if (mEntries[i]->mInfo &&
mEntries[i]->mInfo->Equals(aLoadContextInfo) && mEntries[i]->mInfo->Equals(aLoadContextInfo) &&
mEntries[i]->mPinned == aPinned) { mEntries[i]->mPinned == aPinned &&
mEntries[i]->mOrigin.Equals(aOrigin)) {
entry = mEntries[i]; entry = mEntries[i];
break; break;
} }
@ -119,7 +122,8 @@ CacheFileContextEvictor::AddContext(nsILoadContextInfo *aLoadContextInfo,
for (uint32_t i = mEntries.Length(); i > 0;) { for (uint32_t i = mEntries.Length(); i > 0;) {
--i; --i;
if (mEntries[i]->mInfo && mEntries[i]->mPinned == aPinned) { if (mEntries[i]->mInfo && mEntries[i]->mPinned == aPinned) {
RemoveEvictInfoFromDisk(mEntries[i]->mInfo, mEntries[i]->mPinned); RemoveEvictInfoFromDisk(mEntries[i]->mInfo, mEntries[i]->mPinned,
mEntries[i]->mOrigin);
mEntries.RemoveElementAt(i); mEntries.RemoveElementAt(i);
} }
} }
@ -129,12 +133,13 @@ CacheFileContextEvictor::AddContext(nsILoadContextInfo *aLoadContextInfo,
entry = new CacheFileContextEvictorEntry(); entry = new CacheFileContextEvictorEntry();
entry->mInfo = aLoadContextInfo; entry->mInfo = aLoadContextInfo;
entry->mPinned = aPinned; entry->mPinned = aPinned;
entry->mOrigin = aOrigin;
mEntries.AppendElement(entry); mEntries.AppendElement(entry);
} }
entry->mTimeStamp = PR_Now() / PR_USEC_PER_MSEC; entry->mTimeStamp = PR_Now() / PR_USEC_PER_MSEC;
PersistEvictionInfoToDisk(aLoadContextInfo, aPinned); PersistEvictionInfoToDisk(aLoadContextInfo, aPinned, aOrigin);
if (mIndexIsUpToDate) { if (mIndexIsUpToDate) {
// Already existing context could be added again, in this case the iterator // Already existing context could be added again, in this case the iterator
@ -263,7 +268,8 @@ CacheFileContextEvictor::WasEvicted(const nsACString &aKey, nsIFile *aFile,
nsresult nsresult
CacheFileContextEvictor::PersistEvictionInfoToDisk( CacheFileContextEvictor::PersistEvictionInfoToDisk(
nsILoadContextInfo *aLoadContextInfo, bool aPinned) nsILoadContextInfo *aLoadContextInfo, bool aPinned,
const nsAString& aOrigin)
{ {
LOG(("CacheFileContextEvictor::PersistEvictionInfoToDisk() [this=%p, " LOG(("CacheFileContextEvictor::PersistEvictionInfoToDisk() [this=%p, "
"loadContextInfo=%p]", this, aLoadContextInfo)); "loadContextInfo=%p]", this, aLoadContextInfo));
@ -273,7 +279,7 @@ CacheFileContextEvictor::PersistEvictionInfoToDisk(
MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); MOZ_ASSERT(CacheFileIOManager::IsOnIOThread());
nsCOMPtr<nsIFile> file; nsCOMPtr<nsIFile> file;
rv = GetContextFile(aLoadContextInfo, aPinned, getter_AddRefs(file)); rv = GetContextFile(aLoadContextInfo, aPinned, aOrigin, getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return rv; return rv;
} }
@ -299,7 +305,7 @@ CacheFileContextEvictor::PersistEvictionInfoToDisk(
nsresult nsresult
CacheFileContextEvictor::RemoveEvictInfoFromDisk( CacheFileContextEvictor::RemoveEvictInfoFromDisk(
nsILoadContextInfo *aLoadContextInfo, bool aPinned) nsILoadContextInfo *aLoadContextInfo, bool aPinned, const nsAString& aOrigin)
{ {
LOG(("CacheFileContextEvictor::RemoveEvictInfoFromDisk() [this=%p, " LOG(("CacheFileContextEvictor::RemoveEvictInfoFromDisk() [this=%p, "
"loadContextInfo=%p]", this, aLoadContextInfo)); "loadContextInfo=%p]", this, aLoadContextInfo));
@ -309,7 +315,7 @@ CacheFileContextEvictor::RemoveEvictInfoFromDisk(
MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); MOZ_ASSERT(CacheFileIOManager::IsOnIOThread());
nsCOMPtr<nsIFile> file; nsCOMPtr<nsIFile> file;
rv = GetContextFile(aLoadContextInfo, aPinned, getter_AddRefs(file)); rv = GetContextFile(aLoadContextInfo, aPinned, aOrigin, getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return rv; return rv;
} }
@ -393,6 +399,16 @@ CacheFileContextEvictor::LoadEvictInfoFromDisk()
decoded = Substring(decoded, 1); decoded = Substring(decoded, 1);
} }
// Let's see if we have an origin.
nsAutoCString origin;
if (decoded.Contains('\t')) {
auto split = decoded.Split('\t');
MOZ_ASSERT(decoded.CountChar('\t') == 2);
origin = split.Get(0);
decoded = split.Get(1);
}
nsCOMPtr<nsILoadContextInfo> info; nsCOMPtr<nsILoadContextInfo> info;
if (!NS_LITERAL_CSTRING("*").Equals(decoded)) { if (!NS_LITERAL_CSTRING("*").Equals(decoded)) {
// "*" is indication of 'delete all', info left null will pass // "*" is indication of 'delete all', info left null will pass
@ -417,6 +433,7 @@ CacheFileContextEvictor::LoadEvictInfoFromDisk()
CacheFileContextEvictorEntry *entry = new CacheFileContextEvictorEntry(); CacheFileContextEvictorEntry *entry = new CacheFileContextEvictorEntry();
entry->mInfo = info; entry->mInfo = info;
entry->mPinned = pinned; entry->mPinned = pinned;
CopyUTF8toUTF16(origin, entry->mOrigin);
entry->mTimeStamp = lastModifiedTime; entry->mTimeStamp = lastModifiedTime;
mEntries.AppendElement(entry); mEntries.AppendElement(entry);
} }
@ -427,6 +444,7 @@ CacheFileContextEvictor::LoadEvictInfoFromDisk()
nsresult nsresult
CacheFileContextEvictor::GetContextFile(nsILoadContextInfo *aLoadContextInfo, CacheFileContextEvictor::GetContextFile(nsILoadContextInfo *aLoadContextInfo,
bool aPinned, bool aPinned,
const nsAString& aOrigin,
nsIFile **_retval) nsIFile **_retval)
{ {
nsresult rv; nsresult rv;
@ -445,6 +463,10 @@ CacheFileContextEvictor::GetContextFile(nsILoadContextInfo *aLoadContextInfo,
} else { } else {
keyPrefix.Append('*'); keyPrefix.Append('*');
} }
if (!aOrigin.IsEmpty()) {
keyPrefix.Append('\t');
keyPrefix.Append(NS_ConvertUTF16toUTF8(aOrigin));
}
nsAutoCString data64; nsAutoCString data64;
rv = Base64Encode(keyPrefix, data64); rv = Base64Encode(keyPrefix, data64);
@ -516,7 +538,7 @@ CacheFileContextEvictor::StartEvicting()
MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); MOZ_ASSERT(CacheFileIOManager::IsOnIOThread());
if (mEvicting) { if (mEvicting) {
LOG(("CacheFileContextEvictor::StartEvicting() - already evicintg.")); LOG(("CacheFileContextEvictor::StartEvicting() - already evicting."));
return; return;
} }
@ -590,7 +612,8 @@ CacheFileContextEvictor::EvictEntries()
LOG(("CacheFileContextEvictor::EvictEntries() - No more entries left in " LOG(("CacheFileContextEvictor::EvictEntries() - No more entries left in "
"iterator. [iterator=%p, info=%p]", mEntries[0]->mIterator.get(), "iterator. [iterator=%p, info=%p]", mEntries[0]->mIterator.get(),
mEntries[0]->mInfo.get())); mEntries[0]->mInfo.get()));
RemoveEvictInfoFromDisk(mEntries[0]->mInfo, mEntries[0]->mPinned); RemoveEvictInfoFromDisk(mEntries[0]->mInfo, mEntries[0]->mPinned,
mEntries[0]->mOrigin);
mEntries.RemoveElementAt(0); mEntries.RemoveElementAt(0);
continue; continue;
} else if (NS_FAILED(rv)) { } else if (NS_FAILED(rv)) {
@ -634,6 +657,47 @@ CacheFileContextEvictor::EvictEntries()
continue; continue;
} }
if (!mEntries[0]->mOrigin.IsEmpty()) {
nsCOMPtr<nsIFile> file;
CacheFileIOManager::gInstance->GetFile(&hash, getter_AddRefs(file));
// Read metadata from the file synchronously
RefPtr<CacheFileMetadata> metadata = new CacheFileMetadata();
rv = metadata->SyncReadMetadata(file);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
// Now get the context + enhance id + URL from the key.
nsAutoCString key;
metadata->GetKey(key);
nsAutoCString uriSpec;
RefPtr<nsILoadContextInfo> info =
CacheFileUtils::ParseKey(key, nullptr, &uriSpec);
MOZ_ASSERT(info);
if (!info) {
continue;
}
RefPtr<MozURL> url;
rv = MozURL::Init(getter_AddRefs(url), uriSpec);
if (NS_FAILED(rv)) {
LOG(("CacheFileContextEvictor::EvictEntries() - Skipping entry since MozURL "
"fails in the parsing of the uriSpec"));
continue;
}
nsAutoCString urlOrigin;
url->Origin(urlOrigin);
if (urlOrigin.Equals(NS_ConvertUTF16toUTF8(mEntries[0]->mOrigin))) {
LOG(("CacheFileContextEvictor::EvictEntries() - Skipping entry since origin "
"doesn't match"));
continue;
}
}
nsAutoCString leafName; nsAutoCString leafName;
CacheFileIOManager::HashToStr(&hash, leafName); CacheFileIOManager::HashToStr(&hash, leafName);

View file

@ -21,6 +21,7 @@ struct CacheFileContextEvictorEntry
{ {
nsCOMPtr<nsILoadContextInfo> mInfo; nsCOMPtr<nsILoadContextInfo> mInfo;
bool mPinned; bool mPinned;
nsString mOrigin; // it can be empty
PRTime mTimeStamp; // in milliseconds PRTime mTimeStamp; // in milliseconds
RefPtr<CacheIndexIterator> mIterator; RefPtr<CacheIndexIterator> mIterator;
}; };
@ -41,8 +42,9 @@ public:
// Returns number of contexts that are being evicted. // Returns number of contexts that are being evicted.
uint32_t ContextsCount(); uint32_t ContextsCount();
// Start evicting given context. // Start evicting given context and an origin, if not empty.
nsresult AddContext(nsILoadContextInfo *aLoadContextInfo, bool aPinned); nsresult AddContext(nsILoadContextInfo *aLoadContextInfo, bool aPinned,
const nsAString& aOrigin);
// CacheFileIOManager calls this method when CacheIndex's state changes. We // CacheFileIOManager calls this method when CacheIndex's state changes. We
// check whether the index is up to date and start or stop evicting according // check whether the index is up to date and start or stop evicting according
// to index's state. // to index's state.
@ -60,15 +62,17 @@ private:
// done for every context added to the evictor to be able to recover eviction // done for every context added to the evictor to be able to recover eviction
// after a shutdown or crash. When the context file is found after startup, we // after a shutdown or crash. When the context file is found after startup, we
// restore mTimeStamp from the last modified time of the file. // restore mTimeStamp from the last modified time of the file.
nsresult PersistEvictionInfoToDisk(nsILoadContextInfo *aLoadContextInfo, bool aPinned); nsresult PersistEvictionInfoToDisk(nsILoadContextInfo *aLoadContextInfo,
bool aPinned, const nsAString& aOrigin);
// Once we are done with eviction for the given context, the eviction info is // Once we are done with eviction for the given context, the eviction info is
// removed from the disk. // removed from the disk.
nsresult RemoveEvictInfoFromDisk(nsILoadContextInfo *aLoadContextInfo, bool aPinned); nsresult RemoveEvictInfoFromDisk(nsILoadContextInfo *aLoadContextInfo,
bool aPinned, const nsAString& aOrigin);
// Tries to load all contexts from the disk. This method is called just once // Tries to load all contexts from the disk. This method is called just once
// after startup. // after startup.
nsresult LoadEvictInfoFromDisk(); nsresult LoadEvictInfoFromDisk();
nsresult GetContextFile(nsILoadContextInfo *aLoadContextInfo, bool aPinned, nsresult GetContextFile(nsILoadContextInfo *aLoadContextInfo, bool aPinned,
nsIFile **_retval); const nsAString& aOrigin, nsIFile **_retval);
void CreateIterators(); void CreateIterators();
void CloseIterators(); void CloseIterators();

View file

@ -21,6 +21,7 @@
#include "nsIObserverService.h" #include "nsIObserverService.h"
#include "nsICacheStorageVisitor.h" #include "nsICacheStorageVisitor.h"
#include "nsISizeOf.h" #include "nsISizeOf.h"
#include "mozilla/net/MozURL.h"
#include "mozilla/Telemetry.h" #include "mozilla/Telemetry.h"
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "mozilla/Services.h" #include "mozilla/Services.h"
@ -3134,7 +3135,9 @@ CacheFileIOManager::EvictAllInternal()
// static // static
nsresult nsresult
CacheFileIOManager::EvictByContext(nsILoadContextInfo *aLoadContextInfo, bool aPinned) CacheFileIOManager::EvictByContext(nsILoadContextInfo *aLoadContextInfo,
bool aPinned,
const nsAString& aOrigin)
{ {
LOG(("CacheFileIOManager::EvictByContext() [loadContextInfo=%p]", LOG(("CacheFileIOManager::EvictByContext() [loadContextInfo=%p]",
aLoadContextInfo)); aLoadContextInfo));
@ -3147,12 +3150,13 @@ CacheFileIOManager::EvictByContext(nsILoadContextInfo *aLoadContextInfo, bool aP
} }
nsCOMPtr<nsIRunnable> ev; nsCOMPtr<nsIRunnable> ev;
ev = NewRunnableMethod<nsCOMPtr<nsILoadContextInfo>, bool>( ev = NewRunnableMethod<nsCOMPtr<nsILoadContextInfo>, bool, nsString>(
"net::CacheFileIOManager::EvictByContextInternal", "net::CacheFileIOManager::EvictByContextInternal",
ioMan, ioMan,
&CacheFileIOManager::EvictByContextInternal, &CacheFileIOManager::EvictByContextInternal,
aLoadContextInfo, aLoadContextInfo,
aPinned); aPinned,
aOrigin);
rv = ioMan->mIOThread->DispatchAfterPendingOpens(ev); rv = ioMan->mIOThread->DispatchAfterPendingOpens(ev);
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
@ -3163,7 +3167,9 @@ CacheFileIOManager::EvictByContext(nsILoadContextInfo *aLoadContextInfo, bool aP
} }
nsresult nsresult
CacheFileIOManager::EvictByContextInternal(nsILoadContextInfo *aLoadContextInfo, bool aPinned) CacheFileIOManager::EvictByContextInternal(nsILoadContextInfo *aLoadContextInfo,
bool aPinned,
const nsAString& aOrigin)
{ {
LOG(("CacheFileIOManager::EvictByContextInternal() [loadContextInfo=%p, pinned=%d]", LOG(("CacheFileIOManager::EvictByContextInternal() [loadContextInfo=%p, pinned=%d]",
aLoadContextInfo, aPinned)); aLoadContextInfo, aPinned));
@ -3206,6 +3212,8 @@ CacheFileIOManager::EvictByContextInternal(nsILoadContextInfo *aLoadContextInfo,
} }
} }
NS_ConvertUTF16toUTF8 origin(aOrigin);
// Doom all active handles that matches the load context // Doom all active handles that matches the load context
nsTArray<RefPtr<CacheFileHandle> > handles; nsTArray<RefPtr<CacheFileHandle> > handles;
mHandles.GetActiveHandles(&handles); mHandles.GetActiveHandles(&handles);
@ -3213,18 +3221,30 @@ CacheFileIOManager::EvictByContextInternal(nsILoadContextInfo *aLoadContextInfo,
for (uint32_t i = 0; i < handles.Length(); ++i) { for (uint32_t i = 0; i < handles.Length(); ++i) {
CacheFileHandle* handle = handles[i]; CacheFileHandle* handle = handles[i];
if (aLoadContextInfo) { nsAutoCString uriSpec;
bool equals; RefPtr<nsILoadContextInfo> info =
rv = CacheFileUtils::KeyMatchesLoadContextInfo(handle->Key(), CacheFileUtils::ParseKey(handle->Key(), nullptr, &uriSpec);
aLoadContextInfo, if (!info) {
&equals); LOG(("CacheFileIOManager::EvictByContextInternal() - Cannot parse key in "
"handle! [handle=%p, key=%s]", handle, handle->Key().get()));
MOZ_CRASH("Unexpected error!");
}
if (aLoadContextInfo && !info->Equals(aLoadContextInfo)) {
continue;
}
if (!origin.IsEmpty()) {
RefPtr<MozURL> url;
rv = MozURL::Init(getter_AddRefs(url), uriSpec);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
LOG(("CacheFileIOManager::EvictByContextInternal() - Cannot parse key in " continue;
"handle! [handle=%p, key=%s]", handle, handle->Key().get()));
MOZ_CRASH("Unexpected error!");
} }
if (!equals) { nsAutoCString urlOrigin;
url->Origin(urlOrigin);
if (!urlOrigin.Equals(origin)) {
continue; continue;
} }
} }
@ -3250,7 +3270,7 @@ CacheFileIOManager::EvictByContextInternal(nsILoadContextInfo *aLoadContextInfo,
mContextEvictor->Init(mCacheDirectory); mContextEvictor->Init(mCacheDirectory);
} }
mContextEvictor->AddContext(aLoadContextInfo, aPinned); mContextEvictor->AddContext(aLoadContextInfo, aPinned, aOrigin);
return NS_OK; return NS_OK;
} }

View file

@ -332,7 +332,8 @@ public:
static nsresult EvictIfOverLimit(); static nsresult EvictIfOverLimit();
static nsresult EvictAll(); static nsresult EvictAll();
static nsresult EvictByContext(nsILoadContextInfo *aLoadContextInfo, static nsresult EvictByContext(nsILoadContextInfo *aLoadContextInfo,
bool aPinning); bool aPinning,
const nsAString& aOrigin);
static nsresult InitIndexEntry(CacheFileHandle *aHandle, static nsresult InitIndexEntry(CacheFileHandle *aHandle,
OriginAttrsHash aOriginAttrsHash, OriginAttrsHash aOriginAttrsHash,
@ -417,7 +418,7 @@ private:
nsresult OverLimitEvictionInternal(); nsresult OverLimitEvictionInternal();
nsresult EvictAllInternal(); nsresult EvictAllInternal();
nsresult EvictByContextInternal(nsILoadContextInfo *aLoadContextInfo, nsresult EvictByContextInternal(nsILoadContextInfo *aLoadContextInfo,
bool aPinning); bool aPinning, const nsAString& aOrigin);
nsresult TrashDirectory(nsIFile *aFile); nsresult TrashDirectory(nsIFile *aFile);
static void OnTrashTimer(nsITimer *aTimer, void *aClosure); static void OnTrashTimer(nsITimer *aTimer, void *aClosure);

View file

@ -24,6 +24,7 @@
#include "nsIFile.h" #include "nsIFile.h"
#include "nsIURI.h" #include "nsIURI.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "nsNetCID.h" #include "nsNetCID.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
@ -795,7 +796,117 @@ NS_IMETHODIMP CacheStorageService::Clear()
// Passing null as a load info means to evict all contexts. // Passing null as a load info means to evict all contexts.
// EvictByContext() respects the entry pinning. EvictAll() does not. // EvictByContext() respects the entry pinning. EvictAll() does not.
rv = CacheFileIOManager::EvictByContext(nullptr, false); rv = CacheFileIOManager::EvictByContext(nullptr, false, EmptyString());
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP CacheStorageService::ClearOrigin(nsIPrincipal* aPrincipal)
{
nsresult rv;
if (NS_WARN_IF(!aPrincipal)) {
return NS_ERROR_FAILURE;
}
nsAutoString origin;
rv = nsContentUtils::GetUTFOrigin(aPrincipal, origin);
NS_ENSURE_SUCCESS(rv, rv);
rv = ClearOriginInternal(origin, aPrincipal->OriginAttributesRef(), true);
NS_ENSURE_SUCCESS(rv, rv);
rv = ClearOriginInternal(origin, aPrincipal->OriginAttributesRef(), false);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
static bool
RemoveExactEntry(CacheEntryTable* aEntries,
nsACString const& aKey,
CacheEntry* aEntry,
bool aOverwrite)
{
RefPtr<CacheEntry> existingEntry;
if (!aEntries->Get(aKey, getter_AddRefs(existingEntry))) {
LOG(("RemoveExactEntry [entry=%p already gone]", aEntry));
return false; // Already removed...
}
if (!aOverwrite && existingEntry != aEntry) {
LOG(("RemoveExactEntry [entry=%p already replaced]", aEntry));
return false; // Already replaced...
}
LOG(("RemoveExactEntry [entry=%p removed]", aEntry));
aEntries->Remove(aKey);
return true;
}
nsresult
CacheStorageService::ClearOriginInternal(const nsAString& aOrigin,
const OriginAttributes& aOriginAttributes,
bool aAnonymous)
{
nsresult rv;
RefPtr<LoadContextInfo> info =
GetLoadContextInfo(aAnonymous, aOriginAttributes);
if (NS_WARN_IF(!info)) {
return NS_ERROR_FAILURE;
}
mozilla::MutexAutoLock lock(mLock);
if (sGlobalEntryTables) {
for (auto iter = sGlobalEntryTables->Iter(); !iter.Done(); iter.Next()) {
bool matches = false;
rv = CacheFileUtils::KeyMatchesLoadContextInfo(iter.Key(), info,
&matches);
NS_ENSURE_SUCCESS(rv, rv);
if (!matches) {
continue;
}
CacheEntryTable* table = iter.UserData();
MOZ_ASSERT(table);
nsTArray<RefPtr<CacheEntry>> entriesToDelete;
for (auto entryIter = table->Iter(); !entryIter.Done(); entryIter.Next()) {
CacheEntry* entry = entryIter.UserData();
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), entry->GetURI());
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString origin;
rv = nsContentUtils::GetUTFOrigin(uri, origin);
NS_ENSURE_SUCCESS(rv, rv);
if (origin != aOrigin) {
continue;
}
entriesToDelete.AppendElement(entry);
}
for (RefPtr<CacheEntry>& entry : entriesToDelete) {
nsAutoCString entryKey;
rv = entry->HashingKey(entryKey);
if (NS_FAILED(rv)) {
NS_ERROR("aEntry->HashingKey() failed?");
return rv;
}
RemoveExactEntry(table, entryKey, entry, false /* don't overwrite */);
}
}
}
rv = CacheFileIOManager::EvictByContext(info, false /* pinned */, aOrigin);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return NS_OK; return NS_OK;
@ -976,28 +1087,6 @@ AddExactEntry(CacheEntryTable* aEntries,
return true; return true;
} }
static bool
RemoveExactEntry(CacheEntryTable* aEntries,
nsACString const& aKey,
CacheEntry* aEntry,
bool aOverwrite)
{
RefPtr<CacheEntry> existingEntry;
if (!aEntries->Get(aKey, getter_AddRefs(existingEntry))) {
LOG(("RemoveExactEntry [entry=%p already gone]", aEntry));
return false; // Already removed...
}
if (!aOverwrite && existingEntry != aEntry) {
LOG(("RemoveExactEntry [entry=%p already replaced]", aEntry));
return false; // Already replaced...
}
LOG(("RemoveExactEntry [entry=%p removed]", aEntry));
aEntries->Remove(aKey);
return true;
}
bool bool
CacheStorageService::RemoveEntry(CacheEntry* aEntry, bool aOnlyUnreferenced) CacheStorageService::RemoveEntry(CacheEntry* aEntry, bool aOnlyUnreferenced)
{ {
@ -1844,7 +1933,7 @@ CacheStorageService::DoomStorageEntries(const nsACString& aContextKey,
if (aContext && !aContext->IsPrivate()) { if (aContext && !aContext->IsPrivate()) {
LOG((" dooming disk entries")); LOG((" dooming disk entries"));
CacheFileIOManager::EvictByContext(aContext, aPinned); CacheFileIOManager::EvictByContext(aContext, aPinned, EmptyString());
} }
} else { } else {
LOG((" dooming memory-only storage of %s", aContextKey.BeginReading())); LOG((" dooming memory-only storage of %s", aContextKey.BeginReading()));

View file

@ -30,6 +30,9 @@ class nsIThread;
class nsIEventTarget; class nsIEventTarget;
namespace mozilla { namespace mozilla {
class OriginAttributes;
namespace net { namespace net {
class CacheStorageService; class CacheStorageService;
@ -311,6 +314,10 @@ private:
bool aReplace, bool aReplace,
CacheEntryHandle** aResult); CacheEntryHandle** aResult);
nsresult ClearOriginInternal(const nsAString& aOrigin,
const mozilla::OriginAttributes& aOriginAttributes,
bool aAnonymous);
static CacheStorageService* sSelf; static CacheStorageService* sSelf;
mozilla::Mutex mLock; mozilla::Mutex mLock;

View file

@ -10,6 +10,7 @@ interface nsIApplicationCache;
interface nsIEventTarget; interface nsIEventTarget;
interface nsICacheStorageConsumptionObserver; interface nsICacheStorageConsumptionObserver;
interface nsICacheStorageVisitor; interface nsICacheStorageVisitor;
interface nsIPrincipal;
/** /**
* Provides access to particual cache storages of the network URI cache. * Provides access to particual cache storages of the network URI cache.
@ -70,6 +71,14 @@ interface nsICacheStorageService : nsISupports
*/ */
nsICacheStorage synthesizedCacheStorage(in nsILoadContextInfo aLoadContextInfo); nsICacheStorage synthesizedCacheStorage(in nsILoadContextInfo aLoadContextInfo);
/**
* Evict any cache entry having the same origin of aPrincipal.
*
* @param aPrincipal
* The principal to compare the entries with.
*/
void clearOrigin(in nsIPrincipal aPrincipal);
/** /**
* Evict the whole cache. * Evict the whole cache.
*/ */

View file

@ -0,0 +1,40 @@
const URL = "http://example.net";
const URL2 = "http://foo.bar";
function run_test()
{
do_get_profile();
asyncOpenCacheEntry(URL + "/a", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, null,
new OpenCallback(NEW, "e1m", "e1d", function(entry) {
asyncOpenCacheEntry(URL + "/a", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, null,
new OpenCallback(NORMAL, "e1m", "e1d", function(entry) {
asyncOpenCacheEntry(URL2 + "/a", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, null,
new OpenCallback(NEW, "f1m", "f1d", function(entry) {
asyncOpenCacheEntry(URL2 + "/a", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, null,
new OpenCallback(NORMAL, "f1m", "f1d", function(entry) {
var url = Services.io.newURI(URL);
var principal = Services.scriptSecurityManager.createCodebasePrincipal(url, {});
get_cache_service().clearOrigin(principal);
asyncOpenCacheEntry(URL + "/a", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, null,
new OpenCallback(NEW, "e1m", "e1d", function(entry) {
asyncOpenCacheEntry(URL2 + "/a", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, null,
new OpenCallback(NORMAL, "f1m", "f1d", function(entry) {
finish_cache2_test();
})
);
})
);
})
);
})
);
})
);
})
);
do_test_pending();
}

View file

@ -78,6 +78,7 @@ skip-if = true
[test_cache2-30c-pinning-deferred-doom.js] [test_cache2-30c-pinning-deferred-doom.js]
[test_cache2-30d-pinning-WasEvicted-API.js] [test_cache2-30d-pinning-WasEvicted-API.js]
[test_cache2-31-visit-all.js] [test_cache2-31-visit-all.js]
[test_cache2-32-clear-origin.js]
[test_partial_response_entry_size_smart_shrink.js] [test_partial_response_entry_size_smart_shrink.js]
[test_304_responses.js] [test_304_responses.js]
[test_421.js] [test_421.js]

View file

@ -86,6 +86,13 @@ const CookieCleaner = {
}; };
const NetworkCacheCleaner = { const NetworkCacheCleaner = {
deleteByPrincipal(aPrincipal) {
return new Promise(aResolve => {
Services.cache2.asyncClearOrigin(aPrincipal);
aResolve();
});
},
deleteAll() { deleteAll() {
return new Promise(aResolve => { return new Promise(aResolve => {
Services.cache2.clear(); Services.cache2.clear();