diff --git a/mozilla/netwerk/cache/src/nsCacheEntry.cpp b/mozilla/netwerk/cache/src/nsCacheEntry.cpp index a01a9309f4c..13e224094d0 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntry.cpp +++ b/mozilla/netwerk/cache/src/nsCacheEntry.cpp @@ -76,6 +76,22 @@ nsCacheEntry::~nsCacheEntry() delete mMetaData; } +nsresult +nsCacheEntry::GetSecurityInfo( nsISupports ** result) +{ + NS_ENSURE_ARG_POINTER(result); + NS_IF_ADDREF(*result = mSecurityInfo); + return NS_OK; +} + + +nsresult +nsCacheEntry::SetSecurityInfo( nsISupports * info) +{ + mSecurityInfo = info; + return NS_OK; +} + nsresult nsCacheEntry::GetData(nsISupports **result) @@ -197,6 +213,11 @@ nsCacheEntry::RequestAccess(nsCacheRequest * request, nsCacheAccessMode *accessG if (PR_CLIST_IS_EMPTY(&mDescriptorQ)) { // 1st descriptor for existing bound entry *accessGranted = request->AccessRequested(); + if (*accessGranted & nsICache::ACCESS_WRITE) { + MarkInvalid(); + } else { + MarkValid(); + } } else { // nth request for existing, bound entry *accessGranted = request->AccessRequested() & ~nsICache::ACCESS_WRITE; diff --git a/mozilla/netwerk/cache/src/nsCacheEntry.h b/mozilla/netwerk/cache/src/nsCacheEntry.h index c1cab67ae3f..948ff123c8e 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntry.h +++ b/mozilla/netwerk/cache/src/nsCacheEntry.h @@ -80,6 +80,9 @@ public: nsCacheDevice * CacheDevice(void) { return mCacheDevice;} void SetCacheDevice( nsCacheDevice * device) { mCacheDevice = device;} + nsresult GetSecurityInfo( nsISupports ** result); + nsresult SetSecurityInfo( nsISupports * info); + nsresult GetData( nsISupports ** result); nsresult SetData( nsISupports * data); @@ -169,10 +172,11 @@ private: PRUint32 mDataSize; // 4 PRUint32 mMetaSize; // 4 nsCacheDevice * mCacheDevice; // 4 - nsCOMPtr mData; // 4 + nsCOMPtr mSecurityInfo; + nsCOMPtr mData; // nsCacheMetaData * mMetaData; // 4 - PRCList mRequestQ; // 8 = 64 - PRCList mDescriptorQ; // 8 = 72 + PRCList mRequestQ; // 8 + PRCList mDescriptorQ; // 8 }; diff --git a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp index 13930f00c14..8176be1ae0d 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp +++ b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.cpp @@ -28,12 +28,13 @@ #include "nsReadableUtils.h" #include "nsIOutputStream.h" -NS_IMPL_ISUPPORTS2(nsCacheEntryDescriptor, nsICacheEntryDescriptor, nsITransport) +NS_IMPL_ISUPPORTS1(nsCacheEntryDescriptor, nsICacheEntryDescriptor) nsCacheEntryDescriptor::nsCacheEntryDescriptor(nsCacheEntry * entry, nsCacheAccessMode accessGranted) - : mCacheEntry(entry), mAccessGranted(accessGranted) + : mCacheEntry(entry), + mAccessGranted(accessGranted) { NS_INIT_ISUPPORTS(); PR_INIT_CLIST(this); @@ -207,7 +208,7 @@ nsCacheEntryDescriptor::GetTransport(nsITransport ** result) if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; if (!mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_NOT_STREAM; - NS_ADDREF(*result = this); + NS_ADDREF(*result = &mTransportWrapper); return NS_OK; } @@ -260,6 +261,7 @@ nsCacheEntryDescriptor::SetStoragePolicy(nsCacheStoragePolicy policy) return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHODIMP nsCacheEntryDescriptor::GetFile(nsIFile ** result) { @@ -269,6 +271,27 @@ nsCacheEntryDescriptor::GetFile(nsIFile ** result) return NS_ERROR_NOT_IMPLEMENTED; } + +NS_IMETHODIMP +nsCacheEntryDescriptor::GetSecurityInfo(nsISupports ** result) +{ + NS_ENSURE_ARG_POINTER(result); + if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; + + return mCacheEntry->GetSecurityInfo(result); +} + + +NS_IMETHODIMP +nsCacheEntryDescriptor::SetSecurityInfo(nsISupports * securityInfo) +{ + if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; + + mCacheEntry->SetSecurityInfo(securityInfo); + return NS_OK; +} + + NS_IMETHODIMP nsCacheEntryDescriptor::Doom() { @@ -353,195 +376,128 @@ nsCacheEntryDescriptor::GetMetaDataEnumerator(nsISimpleEnumerator ** result) } -NS_IMETHODIMP -nsCacheEntryDescriptor::GetSecurityInfo(nsISupports ** result) -{ - NS_ENSURE_ARG_POINTER(result); - if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; +/****************************************************************************** + * nsCacheTransportWrapper + ******************************************************************************/ - return NS_ERROR_NOT_IMPLEMENTED; +// XXX NS_IMPL_ISUPPORTS1(nsCacheEntryDescriptor::nsTransportWrapper, nsITransport); +NS_IMPL_QUERY_INTERFACE1(nsCacheEntryDescriptor::nsTransportWrapper, nsITransport) + + +// special AddRef and Release, because we are part of the descriptor +#define GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(_this) \ + ((nsCacheEntryDescriptor*)((char*)(_this) - \ + offsetof(nsCacheEntryDescriptor, mTransportWrapper))) + +NS_IMETHODIMP_(nsrefcnt) nsCacheEntryDescriptor:: +nsTransportWrapper::AddRef(void) +{ + return GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this)->AddRef(); +} + +NS_IMETHODIMP_(nsrefcnt) nsCacheEntryDescriptor:: +nsTransportWrapper::Release(void) +{ + return GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this)->Release(); } -NS_IMETHODIMP -nsCacheEntryDescriptor::GetNotificationCallbacks(nsIInterfaceRequestor **result) +nsresult nsCacheEntryDescriptor:: +nsTransportWrapper::EnsureTransportWithAccess(nsCacheAccessMode mode) { - NS_ENSURE_ARG_POINTER(result); - if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; + nsresult rv = NS_OK; - return NS_ERROR_NOT_IMPLEMENTED; -} + nsCacheEntryDescriptor * descriptor = GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this); + if (!descriptor->mCacheEntry) return NS_ERROR_NOT_AVAILABLE; + if (!descriptor->mAccessGranted & mode) { + rv = (mode == nsICache::ACCESS_READ) ? + NS_ERROR_CACHE_READ_ACCESS_DENIED : NS_ERROR_CACHE_WRITE_ACCESS_DENIED; + return rv; + } - -NS_IMETHODIMP -nsCacheEntryDescriptor::SetNotificationCallbacks(nsIInterfaceRequestor *requestor, - PRBool isBackground) -{ - if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - - return NS_ERROR_NOT_IMPLEMENTED; -} - - -NS_IMETHODIMP -nsCacheEntryDescriptor::OpenInputStream(PRUint32 offset, - PRUint32 count, - PRUint32 flags, - nsIInputStream ** result) -{ - NS_ENSURE_ARG_POINTER(result); - if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - if (!(mAccessGranted & nsICache::ACCESS_READ)) - return NS_ERROR_CACHE_READ_ACCESS_DENIED; if (!mTransport) { nsresult rv; rv = nsCacheService::GlobalInstance()-> - GetTransportForEntry(mCacheEntry, - mAccessGranted, + GetTransportForEntry(descriptor->mCacheEntry, + descriptor->mAccessGranted, getter_AddRefs(mTransport)); if (NS_FAILED(rv)) return rv; } - - return mTransport->OpenInputStream(offset, count, flags, result); -} - - -/** - * nsCacheOutputStream - a wrapper for nsIOutputstream to track the amount of data - * written to a cache entry. - */ -class nsCacheOutputStream : public nsIOutputStream { - nsCacheEntryDescriptor* mDescriptor; - nsCOMPtr mOutput; -public: - NS_DECL_ISUPPORTS - - nsCacheOutputStream(nsCacheEntryDescriptor* descriptor, nsIOutputStream* output) - : mDescriptor(nsnull), mOutput(output) - { - NS_INIT_ISUPPORTS(); - NS_ADDREF(mDescriptor = descriptor); - } - - virtual ~nsCacheOutputStream() - { - NS_RELEASE(mDescriptor); - } - - nsresult Init(); - - NS_IMETHOD Close() { return mOutput->Close(); } - NS_IMETHOD Flush() { return mOutput->Flush(); } - NS_IMETHOD Write(const char *buf, PRUint32 count, PRUint32 *_retval); - NS_IMETHOD WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval); - NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval); - NS_IMETHOD GetNonBlocking(PRBool *aNonBlocking) { return mOutput->GetNonBlocking(aNonBlocking); } - NS_IMETHOD SetNonBlocking(PRBool aNonBlocking) { return mOutput->SetNonBlocking(aNonBlocking); } - NS_IMETHOD GetObserver(nsIOutputStreamObserver * *aObserver) { return mOutput->GetObserver(aObserver); } - NS_IMETHOD SetObserver(nsIOutputStreamObserver * aObserver) { return mOutput->SetObserver(aObserver); } - -private: - nsresult OnWrite(PRUint32 count); -}; -NS_IMPL_ISUPPORTS1(nsCacheOutputStream, nsIOutputStream); - -nsresult -nsCacheOutputStream::Init() -{ - nsCacheAccessMode mode; - nsresult rv = mDescriptor->GetAccessGranted(&mode); - if (NS_FAILED(rv)) return rv; - if (mode == nsICache::ACCESS_WRITE) { - nsCacheEntry* cacheEntry = mDescriptor->CacheEntry(); - if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE; - nsCacheDevice* device = cacheEntry->CacheDevice(); - if (!device) return NS_ERROR_NOT_AVAILABLE; - // the entry has been truncated to zero bytes, inform the device. - PRInt32 delta = -cacheEntry->DataSize(); - rv = device->OnDataSizeChange(cacheEntry, delta); - cacheEntry->SetDataSize(0); - } - return rv; -} - -NS_IMETHODIMP -nsCacheOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *_retval) -{ - nsresult rv = OnWrite(count); - if (NS_FAILED(rv)) return rv; - return mOutput->Write(buf, count, _retval); -} - -NS_IMETHODIMP -nsCacheOutputStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval) -{ - nsresult rv = OnWrite(count); - if (NS_FAILED(rv)) return rv; - return mOutput->WriteFrom(inStr, count, _retval); -} - -NS_IMETHODIMP -nsCacheOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval) -{ - nsresult rv = OnWrite(count); - if (NS_FAILED(rv)) return rv; - return mOutput->WriteSegments(reader, closure, count, _retval); -} - -nsresult -nsCacheOutputStream::OnWrite(PRUint32 count) -{ - // XXX if count > 2^31 error_write_too_big - return mDescriptor->RequestDataSizeChange((PRInt32)count); - -#if 0 - nsCacheEntry* cacheEntry = mDescriptor->CacheEntry(); - if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE; - nsCacheDevice* device = cacheEntry->CacheDevice(); - if (!device) return NS_ERROR_NOT_AVAILABLE; - nsresult rv = device->OnDataSizeChange(cacheEntry, count); - if (NS_FAILED(rv)) return rv; - cacheEntry->SetDataSize(cacheEntry->DataSize() + count); return NS_OK; -#endif } -static nsresult NS_NewCacheOutputStream(nsIOutputStream ** result, - nsCacheEntryDescriptor * descriptor, - nsIOutputStream * output) +static nsresult NS_NewOutputStreamWrapper(nsIOutputStream ** result, + nsCacheEntryDescriptor * descriptor, + nsIOutputStream * output) { - nsCacheOutputStream* cacheOutput = new nsCacheOutputStream(descriptor, output); + nsCacheEntryDescriptor::nsOutputStreamWrapper* cacheOutput = + new nsCacheEntryDescriptor::nsOutputStreamWrapper(descriptor, output); if (!cacheOutput) return NS_ERROR_OUT_OF_MEMORY; + nsCOMPtr ref(cacheOutput); - nsresult rv = cacheOutput->Init(); + nsresult rv = cacheOutput->Init(); if (NS_FAILED(rv)) return rv; + NS_ADDREF(*result = cacheOutput); return NS_OK; } -NS_IMETHODIMP -nsCacheEntryDescriptor::OpenOutputStream(PRUint32 offset, - PRUint32 count, - PRUint32 flags, - nsIOutputStream ** result) +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsTransportWrapper::GetSecurityInfo(nsISupports ** securityInfo) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsTransportWrapper::GetNotificationCallbacks(nsIInterfaceRequestor **result) { NS_ENSURE_ARG_POINTER(result); - if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - if (!(mAccessGranted & nsICache::ACCESS_WRITE)) - return NS_ERROR_CACHE_WRITE_ACCESS_DENIED; + // if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - nsresult rv; - if (!mTransport) { - rv = nsCacheService::GlobalInstance()-> - GetTransportForEntry(mCacheEntry, - mAccessGranted, - getter_AddRefs(mTransport)); - if (NS_FAILED(rv)) return rv; - } + return NS_ERROR_NOT_IMPLEMENTED; +} - // XXX allow more than one output stream at a time on a descriptor? + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsTransportWrapper::SetNotificationCallbacks(nsIInterfaceRequestor *requestor, + PRBool isBackground) +{ + // if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; + + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsTransportWrapper::OpenInputStream(PRUint32 offset, + PRUint32 count, + PRUint32 flags, + nsIInputStream ** result) +{ + NS_ENSURE_ARG_POINTER(result); + + nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_READ); + if (NS_FAILED(rv)) return rv; + + return mTransport->OpenInputStream(offset, count, flags, result); +} + + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsTransportWrapper::OpenOutputStream(PRUint32 offset, + PRUint32 count, + PRUint32 flags, + nsIOutputStream ** result) +{ + NS_ENSURE_ARG_POINTER(result); + + nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_WRITE); + if (NS_FAILED(rv)) return rv; + + // XXX allow more than one output stream at a time on a descriptor? Why? // Create the underlying output stream using the wrapped transport. nsCOMPtr output; @@ -552,59 +508,119 @@ nsCacheEntryDescriptor::OpenOutputStream(PRUint32 offset, // to maintain the cache entry's size, and to inform the cache device. Eventually, // this mechanism will provide a way for the cache device to enforce space limits, // and to drive cache entry eviction. - return NS_NewCacheOutputStream(result, this, output); + nsCacheEntryDescriptor * descriptor = GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this); + return NS_NewOutputStreamWrapper(result, descriptor, output); } -NS_IMETHODIMP -nsCacheEntryDescriptor::AsyncRead(nsIStreamListener * listener, - nsISupports * ctxt, - PRUint32 offset, - PRUint32 count, - PRUint32 flags, - nsIRequest ** result) + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsTransportWrapper::AsyncRead(nsIStreamListener * listener, + nsISupports * ctxt, + PRUint32 offset, + PRUint32 count, + PRUint32 flags, + nsIRequest ** result) { NS_ENSURE_ARG_POINTER(result); - if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - if (!(mAccessGranted & nsICache::ACCESS_READ)) - return NS_ERROR_CACHE_READ_ACCESS_DENIED; - if (!mTransport) { - nsresult rv; - rv = nsCacheService::GlobalInstance()-> - GetTransportForEntry(mCacheEntry, - mAccessGranted, - getter_AddRefs(mTransport)); - if (NS_FAILED(rv)) return rv; - } + + nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_READ); + if (NS_FAILED(rv)) return rv; return mTransport->AsyncRead(listener, ctxt, offset, count, flags, result); } -NS_IMETHODIMP -nsCacheEntryDescriptor::AsyncWrite(nsIStreamProvider * provider, - nsISupports * ctxt, - PRUint32 offset, - PRUint32 count, - PRUint32 flags, - nsIRequest ** result) +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsTransportWrapper::AsyncWrite(nsIStreamProvider * provider, + nsISupports * ctxt, + PRUint32 offset, + PRUint32 count, + PRUint32 flags, + nsIRequest ** result) { // we're not planning on implementing this return NS_ERROR_NOT_IMPLEMENTED; #if 0 NS_ENSURE_ARG_POINTER(result); - if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; - if (!(mAccessGranted & nsICache::ACCESS_WRITE)) - return NS_ERROR_CACHE_WRITE_ACCESS_DENIED; - if (!mTransport) { - nsresult rv; - rv = nsCacheService::GlobalInstance()-> - GetTransportForEntry(mCacheEntry, - mAccessGranted, - getter_AddRefs(mTransport)); - if (NS_FAILED(rv)) return rv; - } + + nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_WRITE); + if (NS_FAILED(rv)) return rv; return mTransport->AsyncWrite(provider, ctxt, offset, count, flags, result); #endif } + + +/****************************************************************************** + * nsCacheOutputStream - a wrapper for nsIOutputstream to track the amount of + * data written to a cache entry. + ******************************************************************************/ + +NS_IMPL_ISUPPORTS1(nsCacheEntryDescriptor::nsOutputStreamWrapper, nsIOutputStream); + +nsresult nsCacheEntryDescriptor:: +nsOutputStreamWrapper::Init() +{ + nsCacheAccessMode mode; + nsresult rv = mDescriptor->GetAccessGranted(&mode); + if (NS_FAILED(rv)) return rv; + + if (mode == nsICache::ACCESS_WRITE) { + nsCacheEntry* cacheEntry = mDescriptor->CacheEntry(); + if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE; + + nsCacheDevice* device = cacheEntry->CacheDevice(); + if (!device) return NS_ERROR_NOT_AVAILABLE; + + // the entry has been truncated to zero bytes, inform the device. + PRInt32 delta = -cacheEntry->DataSize(); + rv = device->OnDataSizeChange(cacheEntry, delta); + cacheEntry->SetDataSize(0); + } + return rv; +} + + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsOutputStreamWrapper::Write(const char * buf, + PRUint32 count, + PRUint32 * result) +{ + nsresult rv = OnWrite(count); + if (NS_FAILED(rv)) return rv; + return mOutput->Write(buf, count, result); +} + + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsOutputStreamWrapper::WriteFrom(nsIInputStream * inStr, + PRUint32 count, + PRUint32 * result) +{ + nsresult rv = OnWrite(count); + if (NS_FAILED(rv)) return rv; + return mOutput->WriteFrom(inStr, count, result); +} + + +NS_IMETHODIMP nsCacheEntryDescriptor:: +nsOutputStreamWrapper::WriteSegments(nsReadSegmentFun reader, + void * closure, + PRUint32 count, + PRUint32 * result) +{ + nsresult rv = OnWrite(count); + if (NS_FAILED(rv)) return rv; + return mOutput->WriteSegments(reader, closure, count, result); +} + + +nsresult nsCacheEntryDescriptor:: +nsOutputStreamWrapper::OnWrite(PRUint32 count) +{ + // XXX if count > 2^31 error_write_too_big + return mDescriptor->RequestDataSizeChange((PRInt32)count); +} + + diff --git a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.h b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.h index d68088b5491..7329bd5bdc4 100644 --- a/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.h +++ b/mozilla/netwerk/cache/src/nsCacheEntryDescriptor.h @@ -27,15 +27,14 @@ #include "nsICacheEntryDescriptor.h" #include "nsCacheEntry.h" +#include "nsIOutputStream.h" class nsCacheEntryDescriptor : public PRCList, - public nsICacheEntryDescriptor, - public nsITransport -{ + public nsICacheEntryDescriptor + { public: NS_DECL_ISUPPORTS - NS_DECL_NSITRANSPORT NS_DECL_NSICACHEENTRYDESCRIPTOR nsCacheEntryDescriptor(nsCacheEntry * entry, nsCacheAccessMode mode); @@ -55,11 +54,103 @@ public: */ nsCacheEntry * CacheEntry(void) { return mCacheEntry; } -protected: +private: + + /** + * transport wrapper class - + * + * we want the transport wrapper to have the same lifetime as the descriptor, + * but since they each need to reference the other, we have the descriptor + * include the transport wrapper as a member, rather than just pointing to it, + * which avoids circular AddRefs. + */ + class nsTransportWrapper : public nsITransport + { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSITRANSPORT + + nsTransportWrapper() : mTransport(nsnull) {} + virtual ~nsTransportWrapper() {} + + nsresult EnsureTransportWithAccess(nsCacheAccessMode mode); + + nsCOMPtr mTransport; + }; // end of class nsTransportWrapper + friend class nsTransportWrapper; + + + /** + * output stream wrapper class - + * + * The output stream wrapper references the descriptor, but the descriptor doesn't + * need any references to the stream wrapper, so we don't need the same kind of + * tricks that we're using for the transport wrapper. + */ + class nsOutputStreamWrapper : public nsIOutputStream { + private: + nsCacheEntryDescriptor * mDescriptor; + nsCOMPtr mOutput; + public: + NS_DECL_ISUPPORTS + // NS_DECL_NSIOUTPUTSTREAM + NS_IMETHOD Close(void) { return mOutput->Close(); } + NS_IMETHOD Flush(void) { return mOutput->Flush(); } + + NS_IMETHOD Write(const char * buf, + PRUint32 count, + PRUint32 * result); + + NS_IMETHOD WriteFrom(nsIInputStream * inStr, + PRUint32 count, + PRUint32 * result); + + NS_IMETHOD WriteSegments(nsReadSegmentFun reader, + void * closure, + PRUint32 count, + PRUint32 * result); + + NS_IMETHOD GetNonBlocking(PRBool * nonBlocking) + { return mOutput->GetNonBlocking(nonBlocking); } + + NS_IMETHOD SetNonBlocking(PRBool nonBlocking) + { return mOutput->SetNonBlocking(nonBlocking); } + + NS_IMETHOD GetObserver(nsIOutputStreamObserver ** observer) + { return mOutput->GetObserver(observer); } + + NS_IMETHOD SetObserver(nsIOutputStreamObserver * observer) + { return mOutput->SetObserver(observer); } + + nsOutputStreamWrapper(nsCacheEntryDescriptor * descriptor, + nsIOutputStream * output) + : mDescriptor(nsnull), mOutput(output) + { + NS_INIT_ISUPPORTS(); + NS_ADDREF(mDescriptor = descriptor); + } - nsCacheEntry * mCacheEntry; // we are a child of the entry - nsCacheAccessMode mAccessGranted; - nsCOMPtr mTransport; + virtual ~nsOutputStreamWrapper() + { + NS_RELEASE(mDescriptor); + } + + nsresult Init(); + + + private: + nsresult OnWrite(PRUint32 count); + }; // end of class nsOutputStreamWrapper + friend class nsOutputStreamWrapper; + + + private: + /** + * nsCacheEntryDescriptor data members + */ + nsCacheEntry * mCacheEntry; // we are a child of the entry + nsCacheAccessMode mAccessGranted; + nsTransportWrapper mTransportWrapper; }; diff --git a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp index a215e1541bb..bb613552afa 100644 --- a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp +++ b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.cpp @@ -25,11 +25,21 @@ #include "nsICacheService.h" #include "nsIComponentManager.h" #include "nsNetCID.h" +#include "nsIObserverService.h" +#include "nsIPref.h" + static NS_DEFINE_CID(kStorageTransportCID, NS_STORAGETRANSPORT_CID); +const char *gMemoryCacheSizePref = "browser.cache.memory_cache_size"; + nsMemoryCacheDevice::nsMemoryCacheDevice() - : mCurrentTotal(0) + : mHardLimit(0), + mSoftLimit(0), + mTotalSize(0), + mInactiveSize(0), + mEntryCount(0), + mMaxEntryCount(0) { PR_INIT_CLIST(&mEvictionList); } @@ -37,6 +47,30 @@ nsMemoryCacheDevice::nsMemoryCacheDevice() nsMemoryCacheDevice::~nsMemoryCacheDevice() { // XXX dealloc all memory + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + prefs->UnregisterCallback(gMemoryCacheSizePref, MemoryCacheSizeChanged, this); + } +} + + +int PR_CALLBACK +nsMemoryCacheDevice::MemoryCacheSizeChanged(const char * pref, void * closure) +{ + nsresult rv; + PRUint32 softLimit = 0; + nsMemoryCacheDevice * device = (nsMemoryCacheDevice *)closure; + + NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + + rv = prefs->GetIntPref(gMemoryCacheSizePref, (PRInt32 *)&softLimit); + + PRUint32 hardLimit = softLimit + 1024*1024*2; // XXX find better limit than +2Meg + rv = device->AdjustMemoryLimits(softLimit, hardLimit); + + return 0; // XXX what are we supposed to return? } @@ -48,6 +82,23 @@ nsMemoryCacheDevice::Init() rv = mMemCacheEntries.Init(); // XXX read user prefs for memory cache limits + NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + + rv = prefs->RegisterCallback(gMemoryCacheSizePref, MemoryCacheSizeChanged, this); + if (NS_FAILED(rv)) return rv; + + // Initialize the pref + MemoryCacheSizeChanged(gMemoryCacheSizePref, this); + + // Register as a memory pressure observer + NS_WITH_SERVICE(nsIObserverService, + observerService, + NS_OBSERVERSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + // XXX rv = observerServcie->AddObserver(this, NS_MEMORY_PRESSURE_TOPIC); + } + // Ignore failure of memory pressure registration return rv; } @@ -165,7 +216,56 @@ nsMemoryCacheDevice::OnDataSizeChange( nsCacheEntry * entry, PRInt32 deltaSize) return NS_OK; } + +nsresult +nsMemoryCacheDevice::AdjustMemoryLimits(PRUint32 softLimit, PRUint32 hardLimit) +{ + mSoftLimit = softLimit; + mHardLimit = hardLimit; + + if ((mTotalSize > mHardLimit) || (mInactiveSize > softLimit)) { + // XXX rv = EvictEntries(); + } + return NS_OK; +} + + +nsresult +nsMemoryCacheDevice::EvictEntries(void) +{ + nsCacheEntry * entry; + nsresult rv = NS_OK; + + entry = (nsCacheEntry *)PR_LIST_HEAD(&mEvictionList); + while (entry != &mEvictionList) { + if (entry->IsInUse()) { + entry = (nsCacheEntry *)PR_NEXT_LINK(entry); + continue; + } + + // remove entry from our hashtable + rv = mMemCacheEntries.RemoveEntry(entry); + NS_ASSERTION(NS_SUCCEEDED(rv), "RemoveEntry() failed?"); + + // remove entry from the eviction list + PR_REMOVE_AND_INIT_LINK(entry); + + // update statistics + PRUint32 memoryRecovered = entry->DataSize() + entry->MetaDataSize(); + mTotalSize -= memoryRecovered; + mInactiveSize -= memoryRecovered; + --mEntryCount; + delete entry; + + if ((mTotalSize < mHardLimit) && (mInactiveSize < mSoftLimit)) + break; + } + + return NS_OK; +} + + + // XXX need methods for enumerating entries -// XXX check entry->IsInUse() before evicting. diff --git a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h index 8b20f913758..16937dbf673 100644 --- a/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h +++ b/mozilla/netwerk/cache/src/nsMemoryCacheDevice.h @@ -49,16 +49,25 @@ public: nsITransport **transport ); virtual nsresult OnDataSizeChange( nsCacheEntry * entry, PRInt32 deltaSize ); + + static int PR_CALLBACK MemoryCacheSizeChanged(const char * pref, void * closure); private: + nsresult AdjustMemoryLimits(PRUint32 softLimit, PRUint32 hardLimit); + nsresult EvictEntries(void); + nsCacheEntryHashTable mMemCacheEntries; + PRCList mEvictionList; PRUint32 mHardLimit; PRUint32 mSoftLimit; - PRUint32 mCurrentTotal; - PRCList mEvictionList; + PRUint32 mTotalSize; + PRUint32 mInactiveSize; + PRUint32 mEntryCount; + + PRUint32 mMaxEntryCount; // XXX what other stats do we want to keep? };