Bug 917423 - HTTP cache v2: Migrate Wyciwyg to the new cache API, r=michal

This commit is contained in:
Honza Bambas 2013-12-18 17:06:40 +01:00
parent a75ccd73bb
commit 35f470e6f8
5 changed files with 139 additions and 136 deletions

View File

@ -4,18 +4,26 @@
var testPath = "http://mochi.test:8888/browser/content/html/content/test/";
var popup;
function checkCache(url, policy, shouldExist, cb)
{
var cache = Components.classes["@mozilla.org/network/cache-service;1"].
getService(Components.interfaces.nsICacheService);
var session = cache.createSession(
"wyciwyg", policy,
Components.interfaces.nsICache.STREAM_BASED);
let {LoadContextInfo} = Cu.import("resource://gre/modules/LoadContextInfo.jsm", null);
let {Services} = Cu.import("resource://gre/modules/Services.jsm", null);
var checkCacheListener = {
onCacheEntryAvailable: function oCEA(entry, access, status) {
function checkCache(url, inMemory, shouldExist, cb)
{
var cache = Services.cache2;
var storage = cache.diskCacheStorage(LoadContextInfo.default, false);
function CheckCacheListener(inMemory, shouldExist)
{
this.inMemory = inMemory;
this.shouldExist = shouldExist;
this.onCacheEntryCheck = function() {
return Components.interfaces.nsICacheEntryOpenCallback.ENTRY_WANTED;
};
this.onCacheEntryAvailable = function oCEA(entry, isNew, appCache, status) {
if (shouldExist) {
ok(entry, "Entry not found");
is(this.inMemory, !entry.persistToDisk, "Entry is " + (inMemory ? "" : " not ") + " in memory as expected");
is(status, Components.results.NS_OK, "Entry not found");
} else {
ok(!entry, "Entry found");
@ -24,12 +32,12 @@ function checkCache(url, policy, shouldExist, cb)
}
setTimeout(cb, 0);
}
};
};
session.asyncOpenCacheEntry(url,
Components.interfaces.nsICache.ACCESS_READ,
checkCacheListener);
storage.asyncOpenURI(Services.io.newURI(url, null, null), "",
Components.interfaces.nsICacheStorage.OPEN_READONLY,
new CheckCacheListener(inMemory, shouldExist));
}
function getPopupURL() {
var sh = popup.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
@ -45,11 +53,8 @@ function testContinue() {
is(wyciwygURL.substring(0, 10), "wyciwyg://", "Unexpected URL.");
popup.close()
checkCache(wyciwygURL, Components.interfaces.nsICache.STORE_ON_DISK, false,
function() {
checkCache(wyciwygURL, Components.interfaces.nsICache.STORE_IN_MEMORY,
true, finish);
});
// We have to find the entry and it must not be persisted to disk
checkCache(wyciwygURL, true, true, finish);
}
function waitForWyciwygDocument() {

View File

@ -8,19 +8,23 @@
#include "nsWyciwygChannel.h"
#include "nsILoadGroup.h"
#include "nsNetUtil.h"
#include "nsICacheService.h"
#include "nsICacheSession.h"
#include "LoadContextInfo.h"
#include "nsICacheService.h" // only to initialize
#include "nsICacheStorageService.h"
#include "nsICacheStorage.h"
#include "nsICacheEntry.h"
#include "CacheObserver.h"
#include "nsCharsetSource.h"
#include "nsProxyRelease.h"
#include "nsThreadUtils.h"
#include "nsICacheEntryDescriptor.h"
#include "nsIEventTarget.h"
#include "nsIInputStream.h"
#include "nsIInputStreamPump.h"
#include "nsIOutputStream.h"
#include "nsIProgressEventSink.h"
#include "nsIURI.h"
#include "nsWyciwygProtocolHandler.h"
typedef mozilla::net::LoadContextInfo LoadContextInfo;
// Must release mChannel on the main thread
class nsWyciwygAsyncEvent : public nsRunnable {
@ -55,18 +59,16 @@ public:
class nsWyciwygWriteEvent : public nsWyciwygAsyncEvent {
public:
nsWyciwygWriteEvent(nsWyciwygChannel *aChannel, const nsAString &aData,
const nsACString &spec)
: nsWyciwygAsyncEvent(aChannel), mData(aData), mSpec(spec) {}
nsWyciwygWriteEvent(nsWyciwygChannel *aChannel, const nsAString &aData)
: nsWyciwygAsyncEvent(aChannel), mData(aData) {}
NS_IMETHOD Run()
{
mChannel->WriteToCacheEntryInternal(mData, mSpec);
mChannel->WriteToCacheEntryInternal(mData);
return NS_OK;
}
private:
nsString mData;
nsCString mSpec;
};
class nsWyciwygCloseEvent : public nsWyciwygAsyncEvent {
@ -86,7 +88,8 @@ private:
// nsWyciwygChannel methods
nsWyciwygChannel::nsWyciwygChannel()
: mStatus(NS_OK),
: mMode(NONE),
mStatus(NS_OK),
mIsPending(false),
mCharsetAndSourceSet(false),
mNeedToWriteCharset(false),
@ -107,7 +110,7 @@ NS_IMPL_ISUPPORTS7(nsWyciwygChannel,
nsIRequest,
nsIStreamListener,
nsIRequestObserver,
nsICacheListener,
nsICacheEntryOpenCallback,
nsIWyciwygChannel,
nsIPrivateBrowsingChannel)
@ -118,14 +121,24 @@ nsWyciwygChannel::Init(nsIURI* uri)
nsresult rv;
if (!mozilla::net::CacheObserver::UseNewCache()) {
// Since nsWyciwygChannel can use the new cache API off the main thread
// and that API normally does this initiation, we need to take care
// of initiating the old cache service here manually. Will be removed
// with bug 913828.
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsICacheService> service =
do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
}
mURI = uri;
mOriginalURI = uri;
nsCOMPtr<nsICacheService> serv =
do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
nsCOMPtr<nsICacheStorageService> serv =
do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = serv->GetCacheIOTarget(getter_AddRefs(mCacheIOTarget));
rv = serv->GetIoTarget(getter_AddRefs(mCacheIOTarget));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -386,28 +399,29 @@ NS_IMETHODIMP
nsWyciwygChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
{
LOG(("nsWyciwygChannel::AsyncOpen [this=%p]\n", this));
MOZ_ASSERT(mMode == NONE, "nsWyciwygChannel already open");
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
NS_ENSURE_TRUE(mMode == NONE, NS_ERROR_IN_PROGRESS);
NS_ENSURE_ARG_POINTER(listener);
nsAutoCString spec;
mURI->GetSpec(spec);
mMode = READING;
// open a cache entry for this channel...
nsresult rv = OpenCacheEntry(spec, nsICache::ACCESS_READ);
if (rv == NS_ERROR_CACHE_KEY_NOT_FOUND) {
// Overwrite rv on purpose; if event dispatch fails we'll bail, and
// otherwise we'll wait until the event fires before calling back.
rv = NS_DispatchToCurrentThread(
NS_NewRunnableMethod(this, &nsWyciwygChannel::NotifyListener));
}
// mIsPending set to true since OnCacheEntryAvailable may be called
// synchronously and fails when mIsPending found false.
mIsPending = true;
nsresult rv = OpenCacheEntry(mURI, nsICacheStorage::OPEN_READONLY |
nsICacheStorage::CHECK_MULTITHREADED);
if (NS_FAILED(rv)) {
LOG(("nsWyciwygChannel::OpenCacheEntry failed [rv=%x]\n", rv));
mIsPending = false;
return rv;
}
mIsPending = true;
// There is no code path that would invoke the listener sooner than
// we get to this line in case OnCacheEntryAvailable is invoked
// synchronously.
mListener = listener;
mListenerContext = ctx;
@ -424,26 +438,35 @@ nsWyciwygChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
NS_IMETHODIMP
nsWyciwygChannel::WriteToCacheEntry(const nsAString &aData)
{
// URIs not thread-safe, so get spec now in case we need it
nsAutoCString spec;
nsresult rv = mURI->GetAsciiSpec(spec);
if (NS_FAILED(rv))
return rv;
if (mMode == READING) {
LOG(("nsWyciwygChannel::WriteToCacheEntry already open for reading"));
MOZ_ASSERT(false);
return NS_ERROR_UNEXPECTED;
}
return mCacheIOTarget->Dispatch(new nsWyciwygWriteEvent(this, aData, spec),
mMode = WRITING;
return mCacheIOTarget->Dispatch(new nsWyciwygWriteEvent(this, aData),
NS_DISPATCH_NORMAL);
}
nsresult
nsWyciwygChannel::WriteToCacheEntryInternal(const nsAString &aData, const nsACString& spec)
nsWyciwygChannel::WriteToCacheEntryInternal(const nsAString &aData)
{
LOG(("nsWyciwygChannel::WriteToCacheEntryInternal [this=%p]", this));
NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
nsresult rv;
MOZ_ASSERT(mMode == WRITING, "nsWyciwygChannel not open for writing");
if (!mCacheEntry) {
rv = OpenCacheEntry(spec, nsICache::ACCESS_WRITE);
if (NS_FAILED(rv)) return rv;
// OPEN_TRUNCATE will give us the entry instantly
rv = OpenCacheEntry(mURI, nsICacheStorage::OPEN_TRUNCATE);
if (NS_FAILED(rv) || !mCacheEntry) {
LOG((" could not synchronously open cache entry for write!"));
return NS_ERROR_FAILURE;
}
}
if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
@ -459,7 +482,7 @@ nsWyciwygChannel::WriteToCacheEntryInternal(const nsAString &aData, const nsACSt
WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
mNeedToWriteCharset = false;
}
uint32_t out;
if (!mCacheOutputStream) {
// Get the outputstream from the cache entry.
@ -496,7 +519,7 @@ nsWyciwygChannel::CloseCacheEntryInternal(nsresult reason)
mCacheInputStream = 0;
if (NS_FAILED(reason))
mCacheEntry->Doom();
mCacheEntry->AsyncDoom(nullptr); // here we were calling Doom() ...
mCacheEntry = 0;
}
@ -573,17 +596,29 @@ nsWyciwygChannel::GetCharsetAndSource(int32_t* aSource, nsACString& aCharset)
}
//////////////////////////////////////////////////////////////////////////////
// nsICachelistener
// nsICacheEntryOpenCallback
//////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor * aCacheEntry, nsCacheAccessMode aMode, nsresult aStatus)
nsWyciwygChannel::OnCacheEntryCheck(nsICacheEntry* entry, nsIApplicationCache* appCache,
uint32_t* aResult)
{
LOG(("nsWyciwygChannel::OnCacheEntryAvailable [this=%p entry=%x "
"access=%x status=%x]\n", this, aCacheEntry, aMode, aStatus));
*aResult = ENTRY_WANTED;
return NS_OK;
}
NS_IMETHODIMP
nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntry *aCacheEntry,
bool aNew,
nsIApplicationCache* aAppCache,
nsresult aStatus)
{
LOG(("nsWyciwygChannel::OnCacheEntryAvailable [this=%p entry=%p "
"new=%d status=%x]\n", this, aCacheEntry, aNew, aStatus));
// if the channel's already fired onStopRequest,
// then we should ignore this event.
if (!mIsPending)
if (!mIsPending && !aNew)
return NS_OK;
// otherwise, we have to handle this event.
@ -592,12 +627,12 @@ nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor * aCacheEntry, n
else if (NS_SUCCEEDED(mStatus))
mStatus = aStatus;
nsresult rv;
nsresult rv = NS_OK;
if (NS_FAILED(mStatus)) {
LOG(("channel was canceled [this=%p status=%x]\n", this, mStatus));
rv = mStatus;
}
else { // advance to the next state...
else if (!aNew) { // advance to the next state...
rv = ReadFromCache();
}
@ -605,18 +640,17 @@ nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor * aCacheEntry, n
if (NS_FAILED(rv)) {
CloseCacheEntry(rv);
NotifyListener();
if (!aNew) {
// Since OnCacheEntryAvailable can be called directly from AsyncOpen
// we must dispatch.
NS_DispatchToCurrentThread(NS_NewRunnableMethod(
this, &nsWyciwygChannel::NotifyListener));
}
}
return NS_OK;
}
NS_IMETHODIMP
nsWyciwygChannel::OnCacheEntryDoomed(nsresult status)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//-----------------------------------------------------------------------------
// nsWyciwygChannel::nsIStreamListener
//-----------------------------------------------------------------------------
@ -687,43 +721,30 @@ nsWyciwygChannel::OnStopRequest(nsIRequest *request, nsISupports *ctx, nsresult
//////////////////////////////////////////////////////////////////////////////
nsresult
nsWyciwygChannel::OpenCacheEntry(const nsACString & aCacheKey,
nsCacheAccessMode aAccessMode)
nsWyciwygChannel::OpenCacheEntry(nsIURI *aURI,
uint32_t aOpenFlags)
{
nsresult rv = NS_ERROR_FAILURE;
// Get cache service
nsCOMPtr<nsICacheService> cacheService =
do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
nsresult rv;
nsCOMPtr<nsICacheStorageService> cacheService =
do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
// honor security settings
nsCacheStoragePolicy storagePolicy;
if (mPrivateBrowsing || mLoadFlags & INHIBIT_PERSISTENT_CACHING)
storagePolicy = nsICache::STORE_IN_MEMORY;
bool anonymous = mLoadFlags & LOAD_ANONYMOUS;
nsRefPtr<LoadContextInfo> loadInfo = mozilla::net::GetLoadContextInfo(
mPrivateBrowsing, mAppId, mInBrowser, anonymous);
nsCOMPtr<nsICacheStorage> cacheStorage;
if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)
rv = cacheService->MemoryCacheStorage(loadInfo, getter_AddRefs(cacheStorage));
else
storagePolicy = nsICache::STORE_ANYWHERE;
rv = cacheService->DiskCacheStorage(loadInfo, false, getter_AddRefs(cacheStorage));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsICacheSession> cacheSession;
nsAutoCString sessionName;
nsWyciwygProtocolHandler::GetCacheSessionName(mAppId, mInBrowser,
mPrivateBrowsing,
sessionName);
rv = cacheStorage->AsyncOpenURI(aURI, EmptyCString(), aOpenFlags, this);
NS_ENSURE_SUCCESS(rv, rv);
// Open a stream based cache session.
rv = cacheService->CreateSession(sessionName.get(), storagePolicy, true,
getter_AddRefs(cacheSession));
if (!cacheSession)
return NS_ERROR_FAILURE;
cacheSession->SetIsPrivate(mPrivateBrowsing);
if (aAccessMode == nsICache::ACCESS_WRITE)
rv = cacheSession->OpenCacheEntry(aCacheKey, aAccessMode, false,
getter_AddRefs(mCacheEntry));
else
rv = cacheSession->AsyncOpenCacheEntry(aCacheKey, aAccessMode, this, false);
return rv;
return NS_OK;
}
nsresult

View File

@ -12,10 +12,10 @@
#include "nsIWyciwygChannel.h"
#include "nsIStreamListener.h"
#include "nsICacheListener.h"
#include "nsICacheEntryOpenCallback.h"
#include "PrivateBrowsingChannel.h"
class nsICacheEntryDescriptor;
class nsICacheEntry;
class nsIEventTarget;
class nsIInputStream;
class nsIInputStreamPump;
@ -30,7 +30,7 @@ extern PRLogModuleInfo * gWyciwygLog;
class nsWyciwygChannel: public nsIWyciwygChannel,
public nsIStreamListener,
public nsICacheListener,
public nsICacheEntryOpenCallback,
public mozilla::net::PrivateBrowsingChannel<nsWyciwygChannel>
{
public:
@ -40,7 +40,7 @@ public:
NS_DECL_NSIWYCIWYGCHANNEL
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSICACHELISTENER
NS_DECL_NSICACHEENTRYOPENCALLBACK
friend class nsWyciwygSetCharsetandSourceEvent;
friend class nsWyciwygWriteEvent;
@ -53,12 +53,12 @@ public:
nsresult Init(nsIURI *uri);
protected:
nsresult WriteToCacheEntryInternal(const nsAString& aData, const nsACString& spec);
nsresult WriteToCacheEntryInternal(const nsAString& aData);
void SetCharsetAndSourceInternal();
nsresult CloseCacheEntryInternal(nsresult reason);
nsresult ReadFromCache();
nsresult OpenCacheEntry(const nsACString & aCacheKey, nsCacheAccessMode aWriteAccess);
nsresult OpenCacheEntry(nsIURI *aURI, uint32_t aOpenFlags);
void WriteCharsetAndSourceToCache(int32_t aSource,
const nsCString& aCharset);
@ -68,6 +68,13 @@ protected:
friend class mozilla::net::PrivateBrowsingChannel<nsWyciwygChannel>;
enum EMode {
NONE,
WRITING,
READING
};
EMode mMode;
nsresult mStatus;
bool mIsPending;
bool mCharsetAndSourceSet;
@ -91,7 +98,7 @@ protected:
nsCOMPtr<nsIInputStreamPump> mPump;
// Cache related stuff
nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
nsCOMPtr<nsICacheEntry> mCacheEntry;
nsCOMPtr<nsIOutputStream> mCacheOutputStream;
nsCOMPtr<nsIInputStream> mCacheInputStream;
nsCOMPtr<nsIEventTarget> mCacheIOTarget;

View File

@ -13,8 +13,6 @@
#include "nsNetUtil.h"
#include "nsIObserverService.h"
#include "mozIApplicationClearPrivateDataParams.h"
#include "nsICacheService.h"
#include "nsICacheSession.h"
#include "mozilla/net/NeckoChild.h"
@ -38,27 +36,6 @@ nsWyciwygProtocolHandler::~nsWyciwygProtocolHandler()
LOG(("Deleting nsWyciwygProtocolHandler [this=%p]\n", this));
}
void
nsWyciwygProtocolHandler::GetCacheSessionName(uint32_t aAppId,
bool aInBrowser,
bool aPrivateBrowsing,
nsACString& aSessionName)
{
if (aPrivateBrowsing) {
aSessionName.AssignLiteral("wyciwyg-private");
} else {
aSessionName.AssignLiteral("wyciwyg");
}
if (aAppId == NECKO_NO_APP_ID && !aInBrowser) {
return;
}
aSessionName.Append('~');
aSessionName.AppendInt(aAppId);
aSessionName.Append('~');
aSessionName.AppendInt(aInBrowser);
}
NS_IMPL_ISUPPORTS1(nsWyciwygProtocolHandler,
nsIProtocolHandler)

View File

@ -17,13 +17,6 @@ public:
nsWyciwygProtocolHandler();
virtual ~nsWyciwygProtocolHandler();
nsresult Init();
static void GetCacheSessionName(uint32_t aAppId,
bool aInBrowser,
bool aPrivateBrowsing,
nsACString& aSessionName);
};
#endif /* nsWyciwygProtocolHandler_h___ */