LCOV - code coverage report
Current view: top level - netwerk/cache - nsCacheEntryDescriptor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 722 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 85 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  *
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsICache.h"
       8             : #include "nsCache.h"
       9             : #include "nsCacheService.h"
      10             : #include "nsCacheEntryDescriptor.h"
      11             : #include "nsCacheEntry.h"
      12             : #include "nsReadableUtils.h"
      13             : #include "nsIOutputStream.h"
      14             : #include "nsCRT.h"
      15             : #include "nsThreadUtils.h"
      16             : #include <algorithm>
      17             : #include "mozilla/IntegerPrintfMacros.h"
      18             : 
      19             : #define kMinDecompressReadBufLen 1024
      20             : #define kMinCompressWriteBufLen  1024
      21             : 
      22             : 
      23             : /******************************************************************************
      24             :  * nsAsyncDoomEvent
      25             :  *****************************************************************************/
      26             : 
      27           0 : class nsAsyncDoomEvent : public mozilla::Runnable {
      28             : public:
      29           0 :     nsAsyncDoomEvent(nsCacheEntryDescriptor *descriptor,
      30             :                      nsICacheListener *listener)
      31           0 :     : mozilla::Runnable("nsAsyncDoomEvent")
      32             :     {
      33           0 :         mDescriptor = descriptor;
      34           0 :         mListener = listener;
      35           0 :         mEventTarget = GetCurrentThreadEventTarget();
      36             :         // We addref the listener here and release it in nsNotifyDoomListener
      37             :         // on the callers thread. If posting of nsNotifyDoomListener event fails
      38             :         // we leak the listener which is better than releasing it on a wrong
      39             :         // thread.
      40           0 :         NS_IF_ADDREF(mListener);
      41           0 :     }
      42             : 
      43           0 :     NS_IMETHOD Run() override
      44             :     {
      45           0 :         nsresult status = NS_OK;
      46             : 
      47             :         {
      48           0 :             nsCacheServiceAutoLock lock(LOCK_TELEM(NSASYNCDOOMEVENT_RUN));
      49             : 
      50           0 :             if (mDescriptor->mCacheEntry) {
      51           0 :                 status = nsCacheService::gService->DoomEntry_Internal(
      52           0 :                              mDescriptor->mCacheEntry, true);
      53           0 :             } else if (!mDescriptor->mDoomedOnClose) {
      54           0 :                 status = NS_ERROR_NOT_AVAILABLE;
      55             :             }
      56             :         }
      57             : 
      58           0 :         if (mListener) {
      59           0 :             mEventTarget->Dispatch(new nsNotifyDoomListener(mListener, status),
      60           0 :                                    NS_DISPATCH_NORMAL);
      61             :             // posted event will release the reference on the correct thread
      62           0 :             mListener = nullptr;
      63             :         }
      64             : 
      65           0 :         return NS_OK;
      66             :     }
      67             : 
      68             : private:
      69             :     RefPtr<nsCacheEntryDescriptor> mDescriptor;
      70             :     nsICacheListener                *mListener;
      71             :     nsCOMPtr<nsIEventTarget>       mEventTarget;
      72             : };
      73             : 
      74             : 
      75           0 : NS_IMPL_ISUPPORTS(nsCacheEntryDescriptor,
      76             :                   nsICacheEntryDescriptor,
      77             :                   nsICacheEntryInfo)
      78             : 
      79           0 : nsCacheEntryDescriptor::nsCacheEntryDescriptor(nsCacheEntry * entry,
      80           0 :                                                nsCacheAccessMode accessGranted)
      81             :     : mCacheEntry(entry),
      82             :       mAccessGranted(accessGranted),
      83             :       mOutputWrapper(nullptr),
      84             :       mLock("nsCacheEntryDescriptor.mLock"),
      85             :       mAsyncDoomPending(false),
      86             :       mDoomedOnClose(false),
      87           0 :       mClosingDescriptor(false)
      88             : {
      89           0 :     PR_INIT_CLIST(this);
      90           0 :     NS_ADDREF(nsCacheService::GlobalInstance());  // ensure it lives for the lifetime of the descriptor
      91           0 : }
      92             : 
      93             : 
      94           0 : nsCacheEntryDescriptor::~nsCacheEntryDescriptor()
      95             : {
      96             :     // No need to close if the cache entry has already been severed.  This
      97             :     // helps avoid a shutdown assertion (bug 285519) that is caused when
      98             :     // consumers end up holding onto these objects past xpcom-shutdown.  It's
      99             :     // okay for them to do that because the cache service calls our Close
     100             :     // method during xpcom-shutdown, so we don't need to complain about it.
     101           0 :     if (mCacheEntry)
     102           0 :         Close();
     103             : 
     104           0 :     NS_ASSERTION(mInputWrappers.IsEmpty(),
     105             :                  "We have still some input wrapper!");
     106           0 :     NS_ASSERTION(!mOutputWrapper, "We have still an output wrapper!");
     107             : 
     108           0 :     nsCacheService * service = nsCacheService::GlobalInstance();
     109           0 :     NS_RELEASE(service);
     110           0 : }
     111             : 
     112             : 
     113             : NS_IMETHODIMP
     114           0 : nsCacheEntryDescriptor::GetClientID(char ** result)
     115             : {
     116           0 :     NS_ENSURE_ARG_POINTER(result);
     117             : 
     118           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETCLIENTID));
     119           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     120             : 
     121           0 :     return ClientIDFromCacheKey(*(mCacheEntry->Key()), result);
     122             : }
     123             : 
     124             : 
     125             : NS_IMETHODIMP
     126           0 : nsCacheEntryDescriptor::GetDeviceID(char ** aDeviceID)
     127             : {
     128           0 :     NS_ENSURE_ARG_POINTER(aDeviceID);
     129           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETDEVICEID));
     130           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     131             : 
     132           0 :     const char* deviceID = mCacheEntry->GetDeviceID();
     133           0 :     if (!deviceID) {
     134           0 :         *aDeviceID = nullptr;
     135           0 :         return NS_OK;
     136             :     }
     137             : 
     138           0 :     *aDeviceID = NS_strdup(deviceID);
     139           0 :     return *aDeviceID ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     140             : }
     141             : 
     142             : 
     143             : NS_IMETHODIMP
     144           0 : nsCacheEntryDescriptor::GetKey(nsACString &result)
     145             : {
     146           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETKEY));
     147           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     148             : 
     149           0 :     return ClientKeyFromCacheKey(*(mCacheEntry->Key()), result);
     150             : }
     151             : 
     152             : 
     153             : NS_IMETHODIMP
     154           0 : nsCacheEntryDescriptor::GetFetchCount(int32_t *result)
     155             : {
     156           0 :     NS_ENSURE_ARG_POINTER(result);
     157           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETFETCHCOUNT));
     158           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     159             : 
     160           0 :     *result = mCacheEntry->FetchCount();
     161           0 :     return NS_OK;
     162             : }
     163             : 
     164             : 
     165             : NS_IMETHODIMP
     166           0 : nsCacheEntryDescriptor::GetLastFetched(uint32_t *result)
     167             : {
     168           0 :     NS_ENSURE_ARG_POINTER(result);
     169           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETLASTFETCHED));
     170           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     171             : 
     172           0 :     *result = mCacheEntry->LastFetched();
     173           0 :     return NS_OK;
     174             : }
     175             : 
     176             : 
     177             : NS_IMETHODIMP
     178           0 : nsCacheEntryDescriptor::GetLastModified(uint32_t *result)
     179             : {
     180           0 :     NS_ENSURE_ARG_POINTER(result);
     181           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETLASTMODIFIED));
     182           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     183             : 
     184           0 :     *result = mCacheEntry->LastModified();
     185           0 :     return NS_OK;
     186             : }
     187             : 
     188             : 
     189             : NS_IMETHODIMP
     190           0 : nsCacheEntryDescriptor::GetExpirationTime(uint32_t *result)
     191             : {
     192           0 :     NS_ENSURE_ARG_POINTER(result);
     193           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETEXPIRATIONTIME));
     194           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     195             : 
     196           0 :     *result = mCacheEntry->ExpirationTime();
     197           0 :     return NS_OK;
     198             : }
     199             : 
     200             : 
     201             : NS_IMETHODIMP
     202           0 : nsCacheEntryDescriptor::SetExpirationTime(uint32_t expirationTime)
     203             : {
     204           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETEXPIRATIONTIME));
     205           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     206             : 
     207           0 :     mCacheEntry->SetExpirationTime(expirationTime);
     208           0 :     mCacheEntry->MarkEntryDirty();
     209           0 :     return NS_OK;
     210             : }
     211             : 
     212             : 
     213           0 : NS_IMETHODIMP nsCacheEntryDescriptor::IsStreamBased(bool *result)
     214             : {
     215           0 :     NS_ENSURE_ARG_POINTER(result);
     216           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_ISSTREAMBASED));
     217           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     218             : 
     219           0 :     *result = mCacheEntry->IsStreamData();
     220           0 :     return NS_OK;
     221             : }
     222             : 
     223           0 : NS_IMETHODIMP nsCacheEntryDescriptor::GetPredictedDataSize(int64_t *result)
     224             : {
     225           0 :     NS_ENSURE_ARG_POINTER(result);
     226           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETPREDICTEDDATASIZE));
     227           0 :     if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
     228             : 
     229           0 :     *result = mCacheEntry->PredictedDataSize();
     230           0 :     return NS_OK;
     231             : }
     232             : 
     233           0 : NS_IMETHODIMP nsCacheEntryDescriptor::SetPredictedDataSize(int64_t
     234             :                                                            predictedSize)
     235             : {
     236           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETPREDICTEDDATASIZE));
     237           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     238             : 
     239           0 :     mCacheEntry->SetPredictedDataSize(predictedSize);
     240           0 :     return NS_OK;
     241             : }
     242             : 
     243           0 : NS_IMETHODIMP nsCacheEntryDescriptor::GetDataSize(uint32_t *result)
     244             : {
     245           0 :     NS_ENSURE_ARG_POINTER(result);
     246           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETDATASIZE));
     247           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     248             : 
     249           0 :     const char* val = mCacheEntry->GetMetaDataElement("uncompressed-len");
     250           0 :     if (!val) {
     251           0 :         *result = mCacheEntry->DataSize();
     252             :     } else {
     253           0 :         *result = atol(val);
     254             :     }
     255             : 
     256           0 :     return NS_OK;
     257             : }
     258             : 
     259             : 
     260           0 : NS_IMETHODIMP nsCacheEntryDescriptor::GetStorageDataSize(uint32_t *result)
     261             : {
     262           0 :     NS_ENSURE_ARG_POINTER(result);
     263           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETSTORAGEDATASIZE));
     264           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     265             : 
     266           0 :     *result = mCacheEntry->DataSize();
     267             : 
     268           0 :     return NS_OK;
     269             : }
     270             : 
     271             : 
     272             : nsresult
     273           0 : nsCacheEntryDescriptor::RequestDataSizeChange(int32_t deltaSize)
     274             : {
     275           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_REQUESTDATASIZECHANGE));
     276           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     277             : 
     278             :     nsresult  rv;
     279           0 :     rv = nsCacheService::OnDataSizeChange(mCacheEntry, deltaSize);
     280           0 :     if (NS_SUCCEEDED(rv)) {
     281             :         // XXX review for signed/unsigned math errors
     282           0 :         uint32_t  newDataSize = mCacheEntry->DataSize() + deltaSize;
     283           0 :         mCacheEntry->SetDataSize(newDataSize);
     284           0 :         mCacheEntry->TouchData();
     285             :     }
     286           0 :     return rv;
     287             : }
     288             : 
     289             : 
     290             : NS_IMETHODIMP
     291           0 : nsCacheEntryDescriptor::SetDataSize(uint32_t dataSize)
     292             : {
     293           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETDATASIZE));
     294           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     295             : 
     296             :     // XXX review for signed/unsigned math errors
     297           0 :     int32_t  deltaSize = dataSize - mCacheEntry->DataSize();
     298             : 
     299             :     nsresult  rv;
     300           0 :     rv = nsCacheService::OnDataSizeChange(mCacheEntry, deltaSize);
     301             :     // this had better be NS_OK, this call instance is advisory for memory cache objects
     302           0 :     if (NS_SUCCEEDED(rv)) {
     303             :         // XXX review for signed/unsigned math errors
     304           0 :         uint32_t  newDataSize = mCacheEntry->DataSize() + deltaSize;
     305           0 :         mCacheEntry->SetDataSize(newDataSize);
     306           0 :         mCacheEntry->TouchData();
     307             :     } else {
     308           0 :         NS_WARNING("failed SetDataSize() on memory cache object!");
     309             :     }
     310             : 
     311           0 :     return rv;
     312             : }
     313             : 
     314             : 
     315             : NS_IMETHODIMP
     316           0 : nsCacheEntryDescriptor::OpenInputStream(uint32_t offset, nsIInputStream ** result)
     317             : {
     318           0 :     NS_ENSURE_ARG_POINTER(result);
     319             : 
     320           0 :     nsInputStreamWrapper* cacheInput = nullptr;
     321             :     {
     322           0 :         nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_OPENINPUTSTREAM));
     323           0 :         if (!mCacheEntry)                  return NS_ERROR_NOT_AVAILABLE;
     324           0 :         if (!mCacheEntry->IsStreamData())  return NS_ERROR_CACHE_DATA_IS_NOT_STREAM;
     325             : 
     326             :         // Don't open any new stream when closing descriptor or clearing entries
     327           0 :         if (mClosingDescriptor || nsCacheService::GetClearingEntries())
     328           0 :             return NS_ERROR_NOT_AVAILABLE;
     329             : 
     330             :         // ensure valid permissions
     331           0 :         if (!(mAccessGranted & nsICache::ACCESS_READ))
     332           0 :             return NS_ERROR_CACHE_READ_ACCESS_DENIED;
     333             : 
     334             :         const char *val;
     335           0 :         val = mCacheEntry->GetMetaDataElement("uncompressed-len");
     336           0 :         if (val) {
     337           0 :             cacheInput = new nsDecompressInputStreamWrapper(this, offset);
     338             :         } else {
     339           0 :             cacheInput = new nsInputStreamWrapper(this, offset);
     340             :         }
     341           0 :         if (!cacheInput) return NS_ERROR_OUT_OF_MEMORY;
     342             : 
     343           0 :         mInputWrappers.AppendElement(cacheInput);
     344             :     }
     345             : 
     346           0 :     NS_ADDREF(*result = cacheInput);
     347           0 :     return NS_OK;
     348             : }
     349             : 
     350             : NS_IMETHODIMP
     351           0 : nsCacheEntryDescriptor::OpenOutputStream(uint32_t offset, nsIOutputStream ** result)
     352             : {
     353           0 :     NS_ENSURE_ARG_POINTER(result);
     354             : 
     355           0 :     nsOutputStreamWrapper* cacheOutput = nullptr;
     356             :     {
     357           0 :         nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_OPENOUTPUTSTREAM));
     358           0 :         if (!mCacheEntry)                  return NS_ERROR_NOT_AVAILABLE;
     359           0 :         if (!mCacheEntry->IsStreamData())  return NS_ERROR_CACHE_DATA_IS_NOT_STREAM;
     360             : 
     361             :         // Don't open any new stream when closing descriptor or clearing entries
     362           0 :         if (mClosingDescriptor || nsCacheService::GetClearingEntries())
     363           0 :             return NS_ERROR_NOT_AVAILABLE;
     364             : 
     365             :         // ensure valid permissions
     366           0 :         if (!(mAccessGranted & nsICache::ACCESS_WRITE))
     367           0 :             return NS_ERROR_CACHE_WRITE_ACCESS_DENIED;
     368             : 
     369           0 :         int32_t compressionLevel = nsCacheService::CacheCompressionLevel();
     370             :         const char *val;
     371           0 :         val = mCacheEntry->GetMetaDataElement("uncompressed-len");
     372           0 :         if ((compressionLevel > 0) && val) {
     373           0 :             cacheOutput = new nsCompressOutputStreamWrapper(this, offset);
     374             :         } else {
     375             :             // clear compression flag when compression disabled - see bug 715198
     376           0 :             if (val) {
     377           0 :                 mCacheEntry->SetMetaDataElement("uncompressed-len", nullptr);
     378             :             }
     379           0 :             cacheOutput = new nsOutputStreamWrapper(this, offset);
     380             :         }
     381           0 :         if (!cacheOutput) return NS_ERROR_OUT_OF_MEMORY;
     382             : 
     383           0 :         mOutputWrapper = cacheOutput;
     384             :     }
     385             : 
     386           0 :     NS_ADDREF(*result = cacheOutput);
     387           0 :     return NS_OK;
     388             : }
     389             : 
     390             : 
     391             : NS_IMETHODIMP
     392           0 : nsCacheEntryDescriptor::GetCacheElement(nsISupports ** result)
     393             : {
     394           0 :     NS_ENSURE_ARG_POINTER(result);
     395           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETCACHEELEMENT));
     396           0 :     if (!mCacheEntry)                 return NS_ERROR_NOT_AVAILABLE;
     397           0 :     if (mCacheEntry->IsStreamData())  return NS_ERROR_CACHE_DATA_IS_STREAM;
     398             : 
     399           0 :     NS_IF_ADDREF(*result = mCacheEntry->Data());
     400           0 :     return NS_OK;
     401             : }
     402             : 
     403             : 
     404             : NS_IMETHODIMP
     405           0 : nsCacheEntryDescriptor::SetCacheElement(nsISupports * cacheElement)
     406             : {
     407           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETCACHEELEMENT));
     408           0 :     if (!mCacheEntry)                 return NS_ERROR_NOT_AVAILABLE;
     409           0 :     if (mCacheEntry->IsStreamData())  return NS_ERROR_CACHE_DATA_IS_STREAM;
     410             : 
     411           0 :     return nsCacheService::SetCacheElement(mCacheEntry, cacheElement);
     412             : }
     413             : 
     414             : 
     415             : NS_IMETHODIMP
     416           0 : nsCacheEntryDescriptor::GetAccessGranted(nsCacheAccessMode *result)
     417             : {
     418           0 :     NS_ENSURE_ARG_POINTER(result);
     419           0 :     *result = mAccessGranted;
     420           0 :     return NS_OK;
     421             : }
     422             : 
     423             : 
     424             : NS_IMETHODIMP
     425           0 : nsCacheEntryDescriptor::GetStoragePolicy(nsCacheStoragePolicy *result)
     426             : {
     427           0 :     NS_ENSURE_ARG_POINTER(result);
     428           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETSTORAGEPOLICY));
     429           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     430             : 
     431           0 :     *result = mCacheEntry->StoragePolicy();
     432           0 :     return NS_OK;
     433             : }
     434             : 
     435             : 
     436             : NS_IMETHODIMP
     437           0 : nsCacheEntryDescriptor::SetStoragePolicy(nsCacheStoragePolicy policy)
     438             : {
     439           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETSTORAGEPOLICY));
     440           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     441             :     // XXX validate policy against session?
     442             : 
     443           0 :     bool        storageEnabled = false;
     444           0 :     storageEnabled = nsCacheService::IsStorageEnabledForPolicy_Locked(policy);
     445           0 :     if (!storageEnabled)    return NS_ERROR_FAILURE;
     446             : 
     447             :     // Don't change the storage policy of entries we can't write
     448           0 :     if (!(mAccessGranted & nsICache::ACCESS_WRITE))
     449           0 :         return NS_ERROR_NOT_AVAILABLE;
     450             : 
     451             :     // Don't allow a cache entry to move from memory-only to anything else
     452           0 :     if (mCacheEntry->StoragePolicy() == nsICache::STORE_IN_MEMORY &&
     453             :         policy != nsICache::STORE_IN_MEMORY)
     454           0 :         return NS_ERROR_NOT_AVAILABLE;
     455             : 
     456           0 :     mCacheEntry->SetStoragePolicy(policy);
     457           0 :     mCacheEntry->MarkEntryDirty();
     458           0 :     return NS_OK;
     459             : }
     460             : 
     461             : 
     462             : NS_IMETHODIMP
     463           0 : nsCacheEntryDescriptor::GetFile(nsIFile ** result)
     464             : {
     465           0 :     NS_ENSURE_ARG_POINTER(result);
     466           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETFILE));
     467           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     468             : 
     469           0 :     return nsCacheService::GetFileForEntry(mCacheEntry, result);
     470             : }
     471             : 
     472             : 
     473             : NS_IMETHODIMP
     474           0 : nsCacheEntryDescriptor::GetSecurityInfo(nsISupports ** result)
     475             : {
     476           0 :     NS_ENSURE_ARG_POINTER(result);
     477           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETSECURITYINFO));
     478           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     479             : 
     480           0 :     *result = mCacheEntry->SecurityInfo();
     481           0 :     NS_IF_ADDREF(*result);
     482           0 :     return NS_OK;
     483             : }
     484             : 
     485             : 
     486             : NS_IMETHODIMP
     487           0 : nsCacheEntryDescriptor::SetSecurityInfo(nsISupports * securityInfo)
     488             : {
     489           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETSECURITYINFO));
     490           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     491             : 
     492           0 :     mCacheEntry->SetSecurityInfo(securityInfo);
     493           0 :     mCacheEntry->MarkEntryDirty();
     494           0 :     return NS_OK;
     495             : }
     496             : 
     497             : 
     498             : NS_IMETHODIMP
     499           0 : nsCacheEntryDescriptor::Doom()
     500             : {
     501           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_DOOM));
     502           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     503             : 
     504           0 :     return nsCacheService::DoomEntry(mCacheEntry);
     505             : }
     506             : 
     507             : 
     508             : NS_IMETHODIMP
     509           0 : nsCacheEntryDescriptor::DoomAndFailPendingRequests(nsresult status)
     510             : {
     511           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_DOOMANDFAILPENDINGREQUESTS));
     512           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     513             : 
     514           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     515             : }
     516             : 
     517             : 
     518             : NS_IMETHODIMP
     519           0 : nsCacheEntryDescriptor::AsyncDoom(nsICacheListener *listener)
     520             : {
     521             :     bool asyncDoomPending;
     522             :     {
     523           0 :         mozilla::MutexAutoLock lock(mLock);
     524           0 :         asyncDoomPending = mAsyncDoomPending;
     525           0 :         mAsyncDoomPending = true;
     526             :     }
     527             : 
     528           0 :     if (asyncDoomPending) {
     529             :         // AsyncDoom was already called. Notify listener if it is non-null,
     530             :         // otherwise just return success.
     531           0 :         if (listener) {
     532             :             nsresult rv = NS_DispatchToCurrentThread(
     533           0 :                 new nsNotifyDoomListener(listener, NS_ERROR_NOT_AVAILABLE));
     534           0 :             if (NS_SUCCEEDED(rv))
     535           0 :                 NS_IF_ADDREF(listener);
     536           0 :             return rv;
     537             :         }
     538           0 :         return NS_OK;
     539             :     }
     540             : 
     541           0 :     nsCOMPtr<nsIRunnable> event = new nsAsyncDoomEvent(this, listener);
     542           0 :     return nsCacheService::DispatchToCacheIOThread(event);
     543             : }
     544             : 
     545             : 
     546             : NS_IMETHODIMP
     547           0 : nsCacheEntryDescriptor::MarkValid()
     548             : {
     549           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_MARKVALID));
     550           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     551             : 
     552           0 :     nsresult  rv = nsCacheService::ValidateEntry(mCacheEntry);
     553           0 :     return rv;
     554             : }
     555             : 
     556             : 
     557             : NS_IMETHODIMP
     558           0 : nsCacheEntryDescriptor::Close()
     559             : {
     560           0 :     RefPtr<nsOutputStreamWrapper> outputWrapper;
     561           0 :     nsTArray<RefPtr<nsInputStreamWrapper> > inputWrappers;
     562             : 
     563             :     {
     564           0 :         nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_CLOSE));
     565           0 :         if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     566             : 
     567             :         // Make sure no other stream can be opened
     568           0 :         mClosingDescriptor = true;
     569           0 :         outputWrapper = mOutputWrapper;
     570           0 :         for (size_t i = 0; i < mInputWrappers.Length(); i++)
     571           0 :             inputWrappers.AppendElement(mInputWrappers[i]);
     572             :     }
     573             : 
     574             :     // Call Close() on the streams outside the lock since it might need to call
     575             :     // methods that grab the cache service lock, e.g. compressed output stream
     576             :     // when it finalizes the entry
     577           0 :     if (outputWrapper) {
     578           0 :         if (NS_FAILED(outputWrapper->Close())) {
     579           0 :             NS_WARNING("Dooming entry because Close() failed!!!");
     580           0 :             Doom();
     581             :         }
     582           0 :         outputWrapper = nullptr;
     583             :     }
     584             : 
     585           0 :     for (uint32_t i = 0 ; i < inputWrappers.Length() ; i++)
     586           0 :         inputWrappers[i]->Close();
     587             : 
     588           0 :     inputWrappers.Clear();
     589             : 
     590           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_CLOSE));
     591           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     592             : 
     593             :     // XXX perhaps closing descriptors should clear/sever transports
     594             : 
     595             :     // tell nsCacheService we're going away
     596           0 :     nsCacheService::CloseDescriptor(this);
     597           0 :     NS_ASSERTION(mCacheEntry == nullptr, "mCacheEntry not null");
     598             : 
     599           0 :     return NS_OK;
     600             : }
     601             : 
     602             : 
     603             : NS_IMETHODIMP
     604           0 : nsCacheEntryDescriptor::GetMetaDataElement(const char *key, char **result)
     605             : {
     606           0 :     NS_ENSURE_ARG_POINTER(key);
     607           0 :     *result = nullptr;
     608             : 
     609           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETMETADATAELEMENT));
     610           0 :     NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_AVAILABLE);
     611             : 
     612             :     const char *value;
     613             : 
     614           0 :     value = mCacheEntry->GetMetaDataElement(key);
     615           0 :     if (!value) return NS_ERROR_NOT_AVAILABLE;
     616             : 
     617           0 :     *result = NS_strdup(value);
     618           0 :     if (!*result) return NS_ERROR_OUT_OF_MEMORY;
     619             : 
     620           0 :     return NS_OK;
     621             : }
     622             : 
     623             : 
     624             : NS_IMETHODIMP
     625           0 : nsCacheEntryDescriptor::SetMetaDataElement(const char *key, const char *value)
     626             : {
     627           0 :     NS_ENSURE_ARG_POINTER(key);
     628             : 
     629           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETMETADATAELEMENT));
     630           0 :     NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_AVAILABLE);
     631             : 
     632             :     // XXX allow null value, for clearing key?
     633             : 
     634           0 :     nsresult rv = mCacheEntry->SetMetaDataElement(key, value);
     635           0 :     if (NS_SUCCEEDED(rv))
     636           0 :         mCacheEntry->TouchMetaData();
     637           0 :     return rv;
     638             : }
     639             : 
     640             : 
     641             : NS_IMETHODIMP
     642           0 : nsCacheEntryDescriptor::VisitMetaData(nsICacheMetaDataVisitor * visitor)
     643             : {
     644           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_VISITMETADATA));
     645             :     // XXX check callers, we're calling out of module
     646           0 :     NS_ENSURE_ARG_POINTER(visitor);
     647           0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
     648             : 
     649           0 :     return mCacheEntry->VisitMetaDataElements(visitor);
     650             : }
     651             : 
     652             : 
     653             : /******************************************************************************
     654             :  * nsCacheInputStream - a wrapper for nsIInputStream keeps the cache entry
     655             :  *                      open while referenced.
     656             :  ******************************************************************************/
     657             : 
     658           0 : NS_IMPL_ADDREF(nsCacheEntryDescriptor::nsInputStreamWrapper)
     659             : NS_IMETHODIMP_(MozExternalRefCountType)
     660           0 : nsCacheEntryDescriptor::nsInputStreamWrapper::Release()
     661             : {
     662             :     // Holding a reference to descriptor ensures that cache service won't go
     663             :     // away. Do not grab cache service lock if there is no descriptor.
     664           0 :     RefPtr<nsCacheEntryDescriptor> desc;
     665             : 
     666             :     {
     667           0 :         mozilla::MutexAutoLock lock(mLock);
     668           0 :         desc = mDescriptor;
     669             :     }
     670             : 
     671           0 :     if (desc)
     672           0 :         nsCacheService::Lock(LOCK_TELEM(NSINPUTSTREAMWRAPPER_RELEASE));
     673             : 
     674             :     nsrefcnt count;
     675           0 :     NS_PRECONDITION(0 != mRefCnt, "dup release");
     676           0 :     count = --mRefCnt;
     677           0 :     NS_LOG_RELEASE(this, count, "nsCacheEntryDescriptor::nsInputStreamWrapper");
     678             : 
     679           0 :     if (0 == count) {
     680             :         // don't use desc here since mDescriptor might be already nulled out
     681           0 :         if (mDescriptor) {
     682           0 :             NS_ASSERTION(mDescriptor->mInputWrappers.Contains(this),
     683             :                          "Wrapper not found in array!");
     684           0 :             mDescriptor->mInputWrappers.RemoveElement(this);
     685             :         }
     686             : 
     687           0 :         if (desc)
     688           0 :             nsCacheService::Unlock();
     689             : 
     690           0 :         mRefCnt = 1;
     691           0 :         delete (this);
     692           0 :         return 0;
     693             :     }
     694             : 
     695           0 :     if (desc)
     696           0 :         nsCacheService::Unlock();
     697             : 
     698           0 :     return count;
     699             : }
     700             : 
     701           0 : NS_INTERFACE_MAP_BEGIN(nsCacheEntryDescriptor::nsInputStreamWrapper)
     702           0 :   NS_INTERFACE_MAP_ENTRY(nsIInputStream)
     703           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     704           0 : NS_INTERFACE_MAP_END_THREADSAFE
     705             : 
     706           0 : nsresult nsCacheEntryDescriptor::
     707             : nsInputStreamWrapper::LazyInit()
     708             : {
     709             :     // Check if we have the descriptor. If not we can't even grab the cache
     710             :     // lock since it is not ensured that the cache service still exists.
     711           0 :     if (!mDescriptor)
     712           0 :         return NS_ERROR_NOT_AVAILABLE;
     713             : 
     714           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSINPUTSTREAMWRAPPER_LAZYINIT));
     715             : 
     716             :     nsCacheAccessMode mode;
     717           0 :     nsresult rv = mDescriptor->GetAccessGranted(&mode);
     718           0 :     if (NS_FAILED(rv)) return rv;
     719             : 
     720           0 :     NS_ENSURE_TRUE(mode & nsICache::ACCESS_READ, NS_ERROR_UNEXPECTED);
     721             : 
     722           0 :     nsCacheEntry* cacheEntry = mDescriptor->CacheEntry();
     723           0 :     if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE;
     724             : 
     725           0 :     rv = nsCacheService::OpenInputStreamForEntry(cacheEntry, mode,
     726             :                                                  mStartOffset,
     727           0 :                                                  getter_AddRefs(mInput));
     728             : 
     729           0 :     CACHE_LOG_DEBUG(("nsInputStreamWrapper::LazyInit "
     730             :                       "[entry=%p, wrapper=%p, mInput=%p, rv=%d]",
     731             :                       mDescriptor, this, mInput.get(), int(rv)));
     732             : 
     733           0 :     if (NS_FAILED(rv)) return rv;
     734             : 
     735           0 :     mInitialized = true;
     736           0 :     return NS_OK;
     737             : }
     738             : 
     739           0 : nsresult nsCacheEntryDescriptor::
     740             : nsInputStreamWrapper::EnsureInit()
     741             : {
     742           0 :     if (mInitialized) {
     743           0 :         NS_ASSERTION(mDescriptor, "Bad state");
     744           0 :         return NS_OK;
     745             :     }
     746             : 
     747           0 :     return LazyInit();
     748             : }
     749             : 
     750           0 : void nsCacheEntryDescriptor::
     751             : nsInputStreamWrapper::CloseInternal()
     752             : {
     753           0 :     mLock.AssertCurrentThreadOwns();
     754           0 :     if (!mDescriptor) {
     755           0 :         NS_ASSERTION(!mInitialized, "Bad state");
     756           0 :         NS_ASSERTION(!mInput, "Bad state");
     757           0 :         return;
     758             :     }
     759             : 
     760           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSINPUTSTREAMWRAPPER_CLOSEINTERNAL));
     761             : 
     762           0 :     if (mDescriptor) {
     763           0 :         mDescriptor->mInputWrappers.RemoveElement(this);
     764           0 :         nsCacheService::ReleaseObject_Locked(mDescriptor);
     765           0 :         mDescriptor = nullptr;
     766             :     }
     767           0 :     mInitialized = false;
     768           0 :     mInput = nullptr;
     769             : }
     770             : 
     771           0 : nsresult nsCacheEntryDescriptor::
     772             : nsInputStreamWrapper::Close()
     773             : {
     774           0 :     mozilla::MutexAutoLock lock(mLock);
     775             : 
     776           0 :     return Close_Locked();
     777             : }
     778             : 
     779           0 : nsresult nsCacheEntryDescriptor::
     780             : nsInputStreamWrapper::Close_Locked()
     781             : {
     782           0 :     nsresult rv = EnsureInit();
     783           0 :     if (NS_SUCCEEDED(rv)) {
     784           0 :         rv = mInput->Close();
     785             :     } else {
     786           0 :         NS_ASSERTION(!mInput,
     787             :                      "Shouldn't have mInput when EnsureInit() failed");
     788             :     }
     789             : 
     790             :     // Call CloseInternal() even when EnsureInit() failed, e.g. in case we are
     791             :     // closing streams with nsCacheService::CloseAllStream()
     792           0 :     CloseInternal();
     793           0 :     return rv;
     794             : }
     795             : 
     796           0 : nsresult nsCacheEntryDescriptor::
     797             : nsInputStreamWrapper::Available(uint64_t *avail)
     798             : {
     799           0 :     mozilla::MutexAutoLock lock(mLock);
     800             : 
     801           0 :     nsresult rv = EnsureInit();
     802           0 :     if (NS_FAILED(rv)) return rv;
     803             : 
     804           0 :     return mInput->Available(avail);
     805             : }
     806             : 
     807           0 : nsresult nsCacheEntryDescriptor::
     808             : nsInputStreamWrapper::Read(char *buf, uint32_t count, uint32_t *countRead)
     809             : {
     810           0 :     mozilla::MutexAutoLock lock(mLock);
     811             : 
     812           0 :     return Read_Locked(buf, count, countRead);
     813             : }
     814             : 
     815           0 : nsresult nsCacheEntryDescriptor::
     816             : nsInputStreamWrapper::Read_Locked(char *buf, uint32_t count, uint32_t *countRead)
     817             : {
     818           0 :     nsresult rv = EnsureInit();
     819           0 :     if (NS_SUCCEEDED(rv))
     820           0 :         rv = mInput->Read(buf, count, countRead);
     821             : 
     822           0 :     CACHE_LOG_DEBUG(("nsInputStreamWrapper::Read "
     823             :                       "[entry=%p, wrapper=%p, mInput=%p, rv=%" PRId32 "]",
     824             :                      mDescriptor, this, mInput.get(), static_cast<uint32_t>(rv)));
     825             : 
     826           0 :     return rv;
     827             : }
     828             : 
     829           0 : nsresult nsCacheEntryDescriptor::
     830             : nsInputStreamWrapper::ReadSegments(nsWriteSegmentFun writer, void *closure,
     831             :                                    uint32_t count, uint32_t *countRead)
     832             : {
     833             :     // cache stream not buffered
     834           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     835             : }
     836             : 
     837           0 : nsresult nsCacheEntryDescriptor::
     838             : nsInputStreamWrapper::IsNonBlocking(bool *result)
     839             : {
     840             :     // cache streams will never return NS_BASE_STREAM_WOULD_BLOCK
     841           0 :     *result = false;
     842           0 :     return NS_OK;
     843             : }
     844             : 
     845             : 
     846             : /******************************************************************************
     847             :  * nsDecompressInputStreamWrapper - an input stream wrapper that decompresses
     848             :  ******************************************************************************/
     849             : 
     850           0 : NS_IMPL_ADDREF(nsCacheEntryDescriptor::nsDecompressInputStreamWrapper)
     851             : NS_IMETHODIMP_(MozExternalRefCountType)
     852           0 : nsCacheEntryDescriptor::nsDecompressInputStreamWrapper::Release()
     853             : {
     854             :     // Holding a reference to descriptor ensures that cache service won't go
     855             :     // away. Do not grab cache service lock if there is no descriptor.
     856           0 :     RefPtr<nsCacheEntryDescriptor> desc;
     857             : 
     858             :     {
     859           0 :         mozilla::MutexAutoLock lock(mLock);
     860           0 :         desc = mDescriptor;
     861             :     }
     862             : 
     863           0 :     if (desc)
     864             :         nsCacheService::Lock(LOCK_TELEM(
     865           0 :                              NSDECOMPRESSINPUTSTREAMWRAPPER_RELEASE));
     866             : 
     867             :     nsrefcnt count;
     868           0 :     NS_PRECONDITION(0 != mRefCnt, "dup release");
     869           0 :     count = --mRefCnt;
     870             :     NS_LOG_RELEASE(this, count,
     871           0 :                    "nsCacheEntryDescriptor::nsDecompressInputStreamWrapper");
     872             : 
     873           0 :     if (0 == count) {
     874             :         // don't use desc here since mDescriptor might be already nulled out
     875           0 :         if (mDescriptor) {
     876           0 :             NS_ASSERTION(mDescriptor->mInputWrappers.Contains(this),
     877             :                          "Wrapper not found in array!");
     878           0 :             mDescriptor->mInputWrappers.RemoveElement(this);
     879             :         }
     880             : 
     881           0 :         if (desc)
     882           0 :             nsCacheService::Unlock();
     883             : 
     884           0 :         mRefCnt = 1;
     885           0 :         delete (this);
     886           0 :         return 0;
     887             :     }
     888             : 
     889           0 :     if (desc)
     890           0 :         nsCacheService::Unlock();
     891             : 
     892           0 :     return count;
     893             : }
     894             : 
     895           0 : NS_INTERFACE_MAP_BEGIN(nsCacheEntryDescriptor::nsDecompressInputStreamWrapper)
     896           0 :   NS_INTERFACE_MAP_ENTRY(nsIInputStream)
     897           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     898           0 : NS_INTERFACE_MAP_END_THREADSAFE
     899             : 
     900           0 : NS_IMETHODIMP nsCacheEntryDescriptor::
     901             : nsDecompressInputStreamWrapper::Read(char *    buf,
     902             :                                      uint32_t  count,
     903             :                                      uint32_t *countRead)
     904             : {
     905           0 :     mozilla::MutexAutoLock lock(mLock);
     906             : 
     907           0 :     int zerr = Z_OK;
     908           0 :     nsresult rv = NS_OK;
     909             : 
     910           0 :     if (!mStreamInitialized) {
     911           0 :         rv = InitZstream();
     912           0 :         if (NS_FAILED(rv)) {
     913           0 :             return rv;
     914             :         }
     915             :     }
     916             : 
     917           0 :     mZstream.next_out = (Bytef*)buf;
     918           0 :     mZstream.avail_out = count;
     919             : 
     920           0 :     if (mReadBufferLen < count) {
     921             :         // Allocate a buffer for reading from the input stream. This will
     922             :         // determine the max number of compressed bytes read from the
     923             :         // input stream at one time. Making the buffer size proportional
     924             :         // to the request size is not necessary, but helps minimize the
     925             :         // number of read requests to the input stream.
     926           0 :         uint32_t newBufLen = std::max(count, (uint32_t)kMinDecompressReadBufLen);
     927             :         unsigned char* newBuf;
     928           0 :         newBuf = (unsigned char*)moz_xrealloc(mReadBuffer,
     929           0 :             newBufLen);
     930           0 :         if (newBuf) {
     931           0 :             mReadBuffer = newBuf;
     932           0 :             mReadBufferLen = newBufLen;
     933             :         }
     934           0 :         if (!mReadBuffer) {
     935           0 :             mReadBufferLen = 0;
     936           0 :             return NS_ERROR_OUT_OF_MEMORY;
     937             :         }
     938             :     }
     939             : 
     940             :     // read and inflate data until the output buffer is full, or
     941             :     // there is no more data to read
     942           0 :     while (NS_SUCCEEDED(rv) &&
     943           0 :            zerr == Z_OK &&
     944           0 :            mZstream.avail_out > 0 &&
     945           0 :            count > 0) {
     946           0 :         if (mZstream.avail_in == 0) {
     947           0 :             rv = nsInputStreamWrapper::Read_Locked((char*)mReadBuffer,
     948             :                                                    mReadBufferLen,
     949           0 :                                                    &mZstream.avail_in);
     950           0 :             if (NS_FAILED(rv) || !mZstream.avail_in) {
     951           0 :                 break;
     952             :             }
     953           0 :             mZstream.next_in = mReadBuffer;
     954             :         }
     955           0 :         zerr = inflate(&mZstream, Z_NO_FLUSH);
     956           0 :         if (zerr == Z_STREAM_END) {
     957             :             // The compressed data may have been stored in multiple
     958             :             // chunks/streams. To allow for this case, re-initialize
     959             :             // the inflate stream and continue decompressing from
     960             :             // the next byte.
     961           0 :             Bytef * saveNextIn = mZstream.next_in;
     962           0 :             unsigned int saveAvailIn = mZstream.avail_in;
     963           0 :             Bytef * saveNextOut = mZstream.next_out;
     964           0 :             unsigned int saveAvailOut = mZstream.avail_out;
     965           0 :             inflateReset(&mZstream);
     966           0 :             mZstream.next_in = saveNextIn;
     967           0 :             mZstream.avail_in = saveAvailIn;
     968           0 :             mZstream.next_out = saveNextOut;
     969           0 :             mZstream.avail_out = saveAvailOut;
     970           0 :             zerr = Z_OK;
     971           0 :         } else if (zerr != Z_OK) {
     972           0 :             rv = NS_ERROR_INVALID_CONTENT_ENCODING;
     973             :         }
     974             :     }
     975           0 :     if (NS_SUCCEEDED(rv)) {
     976           0 :         *countRead = count - mZstream.avail_out;
     977             :     }
     978           0 :     return rv;
     979             : }
     980             : 
     981           0 : nsresult nsCacheEntryDescriptor::
     982             : nsDecompressInputStreamWrapper::Close()
     983             : {
     984           0 :     mozilla::MutexAutoLock lock(mLock);
     985             : 
     986           0 :     if (!mDescriptor)
     987           0 :         return NS_ERROR_NOT_AVAILABLE;
     988             : 
     989           0 :     EndZstream();
     990           0 :     if (mReadBuffer) {
     991           0 :         free(mReadBuffer);
     992           0 :         mReadBuffer = 0;
     993           0 :         mReadBufferLen = 0;
     994             :     }
     995           0 :     return nsInputStreamWrapper::Close_Locked();
     996             : }
     997             : 
     998           0 : nsresult nsCacheEntryDescriptor::
     999             : nsDecompressInputStreamWrapper::InitZstream()
    1000             : {
    1001           0 :     if (!mDescriptor)
    1002           0 :         return NS_ERROR_NOT_AVAILABLE;
    1003             : 
    1004           0 :     if (mStreamEnded)
    1005           0 :         return NS_ERROR_FAILURE;
    1006             : 
    1007             :     // Initialize zlib inflate stream
    1008           0 :     mZstream.zalloc = Z_NULL;
    1009           0 :     mZstream.zfree = Z_NULL;
    1010           0 :     mZstream.opaque = Z_NULL;
    1011           0 :     mZstream.next_out = Z_NULL;
    1012           0 :     mZstream.avail_out = 0;
    1013           0 :     mZstream.next_in = Z_NULL;
    1014           0 :     mZstream.avail_in = 0;
    1015           0 :     if (inflateInit(&mZstream) != Z_OK) {
    1016           0 :         return NS_ERROR_FAILURE;
    1017             :     }
    1018           0 :     mStreamInitialized = true;
    1019           0 :     return NS_OK;
    1020             : }
    1021             : 
    1022           0 : nsresult nsCacheEntryDescriptor::
    1023             : nsDecompressInputStreamWrapper::EndZstream()
    1024             : {
    1025           0 :     if (mStreamInitialized && !mStreamEnded) {
    1026           0 :         inflateEnd(&mZstream);
    1027           0 :         mStreamInitialized = false;
    1028           0 :         mStreamEnded = true;
    1029             :     }
    1030           0 :     return NS_OK;
    1031             : }
    1032             : 
    1033             : 
    1034             : /******************************************************************************
    1035             :  * nsOutputStreamWrapper - a wrapper for nsIOutputstream to track the amount of
    1036             :  *                         data written to a cache entry.
    1037             :  *                       - also keeps the cache entry open while referenced.
    1038             :  ******************************************************************************/
    1039             : 
    1040           0 : NS_IMPL_ADDREF(nsCacheEntryDescriptor::nsOutputStreamWrapper)
    1041             : NS_IMETHODIMP_(MozExternalRefCountType)
    1042           0 : nsCacheEntryDescriptor::nsOutputStreamWrapper::Release()
    1043             : {
    1044             :     // Holding a reference to descriptor ensures that cache service won't go
    1045             :     // away. Do not grab cache service lock if there is no descriptor.
    1046           0 :     RefPtr<nsCacheEntryDescriptor> desc;
    1047             : 
    1048             :     {
    1049           0 :         mozilla::MutexAutoLock lock(mLock);
    1050           0 :         desc = mDescriptor;
    1051             :     }
    1052             : 
    1053           0 :     if (desc)
    1054           0 :         nsCacheService::Lock(LOCK_TELEM(NSOUTPUTSTREAMWRAPPER_RELEASE));
    1055             : 
    1056             :     nsrefcnt count;
    1057           0 :     NS_PRECONDITION(0 != mRefCnt, "dup release");
    1058           0 :     count = --mRefCnt;
    1059             :     NS_LOG_RELEASE(this, count,
    1060           0 :                    "nsCacheEntryDescriptor::nsOutputStreamWrapper");
    1061             : 
    1062           0 :     if (0 == count) {
    1063             :         // don't use desc here since mDescriptor might be already nulled out
    1064           0 :         if (mDescriptor)
    1065           0 :             mDescriptor->mOutputWrapper = nullptr;
    1066             : 
    1067           0 :         if (desc)
    1068           0 :             nsCacheService::Unlock();
    1069             : 
    1070           0 :         mRefCnt = 1;
    1071           0 :         delete (this);
    1072           0 :         return 0;
    1073             :     }
    1074             : 
    1075           0 :     if (desc)
    1076           0 :         nsCacheService::Unlock();
    1077             : 
    1078           0 :     return count;
    1079             : }
    1080             : 
    1081           0 : NS_INTERFACE_MAP_BEGIN(nsCacheEntryDescriptor::nsOutputStreamWrapper)
    1082           0 :   NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
    1083           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
    1084           0 : NS_INTERFACE_MAP_END_THREADSAFE
    1085             : 
    1086           0 : nsresult nsCacheEntryDescriptor::
    1087             : nsOutputStreamWrapper::LazyInit()
    1088             : {
    1089             :     // Check if we have the descriptor. If not we can't even grab the cache
    1090             :     // lock since it is not ensured that the cache service still exists.
    1091           0 :     if (!mDescriptor)
    1092           0 :         return NS_ERROR_NOT_AVAILABLE;
    1093             : 
    1094           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSOUTPUTSTREAMWRAPPER_LAZYINIT));
    1095             : 
    1096             :     nsCacheAccessMode mode;
    1097           0 :     nsresult rv = mDescriptor->GetAccessGranted(&mode);
    1098           0 :     if (NS_FAILED(rv)) return rv;
    1099             : 
    1100           0 :     NS_ENSURE_TRUE(mode & nsICache::ACCESS_WRITE, NS_ERROR_UNEXPECTED);
    1101             : 
    1102           0 :     nsCacheEntry* cacheEntry = mDescriptor->CacheEntry();
    1103           0 :     if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE;
    1104             : 
    1105           0 :     NS_ASSERTION(mOutput == nullptr, "mOutput set in LazyInit");
    1106             : 
    1107           0 :     nsCOMPtr<nsIOutputStream> stream;
    1108           0 :     rv = nsCacheService::OpenOutputStreamForEntry(cacheEntry, mode, mStartOffset,
    1109           0 :                                                   getter_AddRefs(stream));
    1110           0 :     if (NS_FAILED(rv))
    1111           0 :         return rv;
    1112             : 
    1113           0 :     nsCacheDevice* device = cacheEntry->CacheDevice();
    1114           0 :     if (device) {
    1115             :         // the entry has been truncated to mStartOffset bytes, inform device
    1116           0 :         int32_t size = cacheEntry->DataSize();
    1117           0 :         rv = device->OnDataSizeChange(cacheEntry, mStartOffset - size);
    1118           0 :         if (NS_SUCCEEDED(rv))
    1119           0 :             cacheEntry->SetDataSize(mStartOffset);
    1120             :     } else {
    1121           0 :         rv = NS_ERROR_NOT_AVAILABLE;
    1122             :     }
    1123             : 
    1124             :     // If anything above failed, clean up internal state and get out of here
    1125             :     // (see bug #654926)...
    1126           0 :     if (NS_FAILED(rv)) {
    1127           0 :         nsCacheService::ReleaseObject_Locked(stream.forget().take());
    1128           0 :         mDescriptor->mOutputWrapper = nullptr;
    1129           0 :         nsCacheService::ReleaseObject_Locked(mDescriptor);
    1130           0 :         mDescriptor = nullptr;
    1131           0 :         mInitialized = false;
    1132           0 :         return rv;
    1133             :     }
    1134             : 
    1135           0 :     mOutput = stream;
    1136           0 :     mInitialized = true;
    1137           0 :     return NS_OK;
    1138             : }
    1139             : 
    1140           0 : nsresult nsCacheEntryDescriptor::
    1141             : nsOutputStreamWrapper::EnsureInit()
    1142             : {
    1143           0 :     if (mInitialized) {
    1144           0 :         NS_ASSERTION(mDescriptor, "Bad state");
    1145           0 :         return NS_OK;
    1146             :     }
    1147             : 
    1148           0 :     return LazyInit();
    1149             : }
    1150             : 
    1151           0 : nsresult nsCacheEntryDescriptor::
    1152             : nsOutputStreamWrapper::OnWrite(uint32_t count)
    1153             : {
    1154           0 :     if (count > INT32_MAX)  return NS_ERROR_UNEXPECTED;
    1155           0 :     return mDescriptor->RequestDataSizeChange((int32_t)count);
    1156             : }
    1157             : 
    1158           0 : void nsCacheEntryDescriptor::
    1159             : nsOutputStreamWrapper::CloseInternal()
    1160             : {
    1161           0 :     mLock.AssertCurrentThreadOwns();
    1162           0 :     if (!mDescriptor) {
    1163           0 :         NS_ASSERTION(!mInitialized, "Bad state");
    1164           0 :         NS_ASSERTION(!mOutput, "Bad state");
    1165           0 :         return;
    1166             :     }
    1167             : 
    1168           0 :     nsCacheServiceAutoLock lock(LOCK_TELEM(NSOUTPUTSTREAMWRAPPER_CLOSEINTERNAL));
    1169             : 
    1170           0 :     if (mDescriptor) {
    1171           0 :         mDescriptor->mOutputWrapper = nullptr;
    1172           0 :         nsCacheService::ReleaseObject_Locked(mDescriptor);
    1173           0 :         mDescriptor = nullptr;
    1174             :     }
    1175           0 :     mInitialized = false;
    1176           0 :     mOutput = nullptr;
    1177             : }
    1178             : 
    1179             : 
    1180           0 : NS_IMETHODIMP nsCacheEntryDescriptor::
    1181             : nsOutputStreamWrapper::Close()
    1182             : {
    1183           0 :     mozilla::MutexAutoLock lock(mLock);
    1184             : 
    1185           0 :     return Close_Locked();
    1186             : }
    1187             : 
    1188           0 : nsresult nsCacheEntryDescriptor::
    1189             : nsOutputStreamWrapper::Close_Locked()
    1190             : {
    1191           0 :     nsresult rv = EnsureInit();
    1192           0 :     if (NS_SUCCEEDED(rv)) {
    1193           0 :         rv = mOutput->Close();
    1194             :     } else {
    1195           0 :         NS_ASSERTION(!mOutput,
    1196             :                      "Shouldn't have mOutput when EnsureInit() failed");
    1197             :     }
    1198             : 
    1199             :     // Call CloseInternal() even when EnsureInit() failed, e.g. in case we are
    1200             :     // closing streams with nsCacheService::CloseAllStream()
    1201           0 :     CloseInternal();
    1202           0 :     return rv;
    1203             : }
    1204             : 
    1205           0 : NS_IMETHODIMP nsCacheEntryDescriptor::
    1206             : nsOutputStreamWrapper::Flush()
    1207             : {
    1208           0 :     mozilla::MutexAutoLock lock(mLock);
    1209             : 
    1210           0 :     nsresult rv = EnsureInit();
    1211           0 :     if (NS_FAILED(rv)) return rv;
    1212             : 
    1213           0 :     return mOutput->Flush();
    1214             : }
    1215             : 
    1216           0 : NS_IMETHODIMP nsCacheEntryDescriptor::
    1217             : nsOutputStreamWrapper::Write(const char * buf,
    1218             :                              uint32_t     count,
    1219             :                              uint32_t *   result)
    1220             : {
    1221           0 :     mozilla::MutexAutoLock lock(mLock);
    1222           0 :     return Write_Locked(buf, count, result);
    1223             : }
    1224             : 
    1225           0 : nsresult nsCacheEntryDescriptor::
    1226             : nsOutputStreamWrapper::Write_Locked(const char * buf,
    1227             :                                     uint32_t count,
    1228             :                                     uint32_t * result)
    1229             : {
    1230           0 :     nsresult rv = EnsureInit();
    1231           0 :     if (NS_FAILED(rv)) return rv;
    1232             : 
    1233           0 :     rv = OnWrite(count);
    1234           0 :     if (NS_FAILED(rv)) return rv;
    1235             : 
    1236           0 :     return mOutput->Write(buf, count, result);
    1237             : }
    1238             : 
    1239           0 : NS_IMETHODIMP nsCacheEntryDescriptor::
    1240             : nsOutputStreamWrapper::WriteFrom(nsIInputStream * inStr,
    1241             :                                  uint32_t         count,
    1242             :                                  uint32_t *       result)
    1243             : {
    1244           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1245             : }
    1246             : 
    1247           0 : NS_IMETHODIMP nsCacheEntryDescriptor::
    1248             : nsOutputStreamWrapper::WriteSegments(nsReadSegmentFun  reader,
    1249             :                                      void *            closure,
    1250             :                                      uint32_t          count,
    1251             :                                      uint32_t *        result)
    1252             : {
    1253           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1254             : }
    1255             : 
    1256           0 : NS_IMETHODIMP nsCacheEntryDescriptor::
    1257             : nsOutputStreamWrapper::IsNonBlocking(bool *result)
    1258             : {
    1259             :     // cache streams will never return NS_BASE_STREAM_WOULD_BLOCK
    1260           0 :     *result = false;
    1261           0 :     return NS_OK;
    1262             : }
    1263             : 
    1264             : 
    1265             : /******************************************************************************
    1266             :  * nsCompressOutputStreamWrapper - an output stream wrapper that compresses
    1267             :  *   data before it is written
    1268             :  ******************************************************************************/
    1269             : 
    1270           0 : NS_IMPL_ADDREF(nsCacheEntryDescriptor::nsCompressOutputStreamWrapper)
    1271             : NS_IMETHODIMP_(MozExternalRefCountType)
    1272           0 : nsCacheEntryDescriptor::nsCompressOutputStreamWrapper::Release()
    1273             : {
    1274             :     // Holding a reference to descriptor ensures that cache service won't go
    1275             :     // away. Do not grab cache service lock if there is no descriptor.
    1276           0 :     RefPtr<nsCacheEntryDescriptor> desc;
    1277             : 
    1278             :     {
    1279           0 :         mozilla::MutexAutoLock lock(mLock);
    1280           0 :         desc = mDescriptor;
    1281             :     }
    1282             : 
    1283           0 :     if (desc)
    1284           0 :         nsCacheService::Lock(LOCK_TELEM(NSCOMPRESSOUTPUTSTREAMWRAPPER_RELEASE));
    1285             : 
    1286             :     nsrefcnt count;
    1287           0 :     NS_PRECONDITION(0 != mRefCnt, "dup release");
    1288           0 :     count = --mRefCnt;
    1289             :     NS_LOG_RELEASE(this, count,
    1290           0 :                    "nsCacheEntryDescriptor::nsCompressOutputStreamWrapper");
    1291             : 
    1292           0 :     if (0 == count) {
    1293             :         // don't use desc here since mDescriptor might be already nulled out
    1294           0 :         if (mDescriptor)
    1295           0 :             mDescriptor->mOutputWrapper = nullptr;
    1296             : 
    1297           0 :         if (desc)
    1298           0 :             nsCacheService::Unlock();
    1299             : 
    1300           0 :         mRefCnt = 1;
    1301           0 :         delete (this);
    1302           0 :         return 0;
    1303             :     }
    1304             : 
    1305           0 :     if (desc)
    1306           0 :         nsCacheService::Unlock();
    1307             : 
    1308           0 :     return count;
    1309             : }
    1310             : 
    1311           0 : NS_INTERFACE_MAP_BEGIN(nsCacheEntryDescriptor::nsCompressOutputStreamWrapper)
    1312           0 :   NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
    1313           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
    1314           0 : NS_INTERFACE_MAP_END_THREADSAFE
    1315             : 
    1316           0 : NS_IMETHODIMP nsCacheEntryDescriptor::
    1317             : nsCompressOutputStreamWrapper::Write(const char * buf,
    1318             :                                      uint32_t     count,
    1319             :                                      uint32_t *   result)
    1320             : {
    1321           0 :     mozilla::MutexAutoLock lock(mLock);
    1322             : 
    1323           0 :     int zerr = Z_OK;
    1324           0 :     nsresult rv = NS_OK;
    1325             : 
    1326           0 :     if (!mStreamInitialized) {
    1327           0 :         rv = InitZstream();
    1328           0 :         if (NS_FAILED(rv)) {
    1329           0 :             return rv;
    1330             :         }
    1331             :     }
    1332             : 
    1333           0 :     if (!mWriteBuffer) {
    1334             :         // Once allocated, this buffer is referenced by the zlib stream and
    1335             :         // cannot be grown. We use 2x(initial write request) to approximate
    1336             :         // a stream buffer size proportional to request buffers.
    1337           0 :         mWriteBufferLen = std::max(count*2, (uint32_t)kMinCompressWriteBufLen);
    1338           0 :         mWriteBuffer = (unsigned char*)moz_xmalloc(mWriteBufferLen);
    1339           0 :         if (!mWriteBuffer) {
    1340           0 :             mWriteBufferLen = 0;
    1341           0 :             return NS_ERROR_OUT_OF_MEMORY;
    1342             :         }
    1343           0 :         mZstream.next_out = mWriteBuffer;
    1344           0 :         mZstream.avail_out = mWriteBufferLen;
    1345             :     }
    1346             : 
    1347             :     // Compress (deflate) the requested buffer. Keep going
    1348             :     // until the entire buffer has been deflated.
    1349           0 :     mZstream.avail_in = count;
    1350           0 :     mZstream.next_in = (Bytef*)buf;
    1351           0 :     while (mZstream.avail_in > 0) {
    1352           0 :         zerr = deflate(&mZstream, Z_NO_FLUSH);
    1353           0 :         if (zerr == Z_STREAM_ERROR) {
    1354           0 :             deflateEnd(&mZstream);
    1355           0 :             mStreamEnded = true;
    1356           0 :             mStreamInitialized = false;
    1357           0 :             return NS_ERROR_FAILURE;
    1358             :         }
    1359             :         // Note: Z_BUF_ERROR is non-fatal and sometimes expected here.
    1360             : 
    1361             :         // If the compression stream output buffer is filled, write
    1362             :         // it out to the underlying stream wrapper.
    1363           0 :         if (mZstream.avail_out == 0) {
    1364           0 :             rv = WriteBuffer();
    1365           0 :             if (NS_FAILED(rv)) {
    1366           0 :                 deflateEnd(&mZstream);
    1367           0 :                 mStreamEnded = true;
    1368           0 :                 mStreamInitialized = false;
    1369           0 :                 return rv;
    1370             :             }
    1371             :         }
    1372             :     }
    1373           0 :     *result = count;
    1374           0 :     mUncompressedCount += *result;
    1375           0 :     return NS_OK;
    1376             : }
    1377             : 
    1378           0 : NS_IMETHODIMP nsCacheEntryDescriptor::
    1379             : nsCompressOutputStreamWrapper::Close()
    1380             : {
    1381           0 :     mozilla::MutexAutoLock lock(mLock);
    1382             : 
    1383           0 :     if (!mDescriptor)
    1384           0 :         return NS_ERROR_NOT_AVAILABLE;
    1385             : 
    1386           0 :     nsresult retval = NS_OK;
    1387             :     nsresult rv;
    1388           0 :     int zerr = 0;
    1389             : 
    1390           0 :     if (mStreamInitialized) {
    1391             :         // complete compression of any data remaining in the zlib stream
    1392           0 :         do {
    1393           0 :             zerr = deflate(&mZstream, Z_FINISH);
    1394           0 :             rv = WriteBuffer();
    1395           0 :             if (NS_FAILED(rv))
    1396           0 :                 retval = rv;
    1397           0 :         } while (zerr == Z_OK && rv == NS_OK);
    1398           0 :         deflateEnd(&mZstream);
    1399           0 :         mStreamInitialized = false;
    1400             :     }
    1401             :     // Do not allow to initialize stream after calling Close().
    1402           0 :     mStreamEnded = true;
    1403             : 
    1404           0 :     if (mDescriptor->CacheEntry()) {
    1405           0 :         nsAutoCString uncompressedLenStr;
    1406           0 :         rv = mDescriptor->GetMetaDataElement("uncompressed-len",
    1407           0 :                                              getter_Copies(uncompressedLenStr));
    1408           0 :         if (NS_SUCCEEDED(rv)) {
    1409           0 :             int32_t oldCount = uncompressedLenStr.ToInteger(&rv);
    1410           0 :             if (NS_SUCCEEDED(rv)) {
    1411           0 :                 mUncompressedCount += oldCount;
    1412             :             }
    1413             :         }
    1414           0 :         uncompressedLenStr.Adopt(0);
    1415           0 :         uncompressedLenStr.AppendInt(mUncompressedCount);
    1416           0 :         rv = mDescriptor->SetMetaDataElement("uncompressed-len",
    1417             :             uncompressedLenStr.get());
    1418           0 :         if (NS_FAILED(rv))
    1419           0 :             retval = rv;
    1420             :     }
    1421             : 
    1422           0 :     if (mWriteBuffer) {
    1423           0 :         free(mWriteBuffer);
    1424           0 :         mWriteBuffer = 0;
    1425           0 :         mWriteBufferLen = 0;
    1426             :     }
    1427             : 
    1428           0 :     rv = nsOutputStreamWrapper::Close_Locked();
    1429           0 :     if (NS_FAILED(rv))
    1430           0 :         retval = rv;
    1431             : 
    1432           0 :     return retval;
    1433             : }
    1434             : 
    1435           0 : nsresult nsCacheEntryDescriptor::
    1436             : nsCompressOutputStreamWrapper::InitZstream()
    1437             : {
    1438           0 :     if (!mDescriptor)
    1439           0 :         return NS_ERROR_NOT_AVAILABLE;
    1440             : 
    1441           0 :     if (mStreamEnded)
    1442           0 :         return NS_ERROR_FAILURE;
    1443             : 
    1444             :     // Determine compression level: Aggressive compression
    1445             :     // may impact performance on mobile devices, while a
    1446             :     // lower compression level still provides substantial
    1447             :     // space savings for many text streams.
    1448           0 :     int32_t compressionLevel = nsCacheService::CacheCompressionLevel();
    1449             : 
    1450             :     // Initialize zlib deflate stream
    1451           0 :     mZstream.zalloc = Z_NULL;
    1452           0 :     mZstream.zfree = Z_NULL;
    1453           0 :     mZstream.opaque = Z_NULL;
    1454           0 :     if (deflateInit2(&mZstream, compressionLevel, Z_DEFLATED,
    1455             :                      MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
    1456           0 :         return NS_ERROR_FAILURE;
    1457             :     }
    1458           0 :     mZstream.next_in = Z_NULL;
    1459           0 :     mZstream.avail_in = 0;
    1460             : 
    1461           0 :     mStreamInitialized = true;
    1462             : 
    1463           0 :     return NS_OK;
    1464             : }
    1465             : 
    1466           0 : nsresult nsCacheEntryDescriptor::
    1467             : nsCompressOutputStreamWrapper::WriteBuffer()
    1468             : {
    1469           0 :     uint32_t bytesToWrite = mWriteBufferLen - mZstream.avail_out;
    1470           0 :     uint32_t result = 0;
    1471           0 :     nsresult rv = nsCacheEntryDescriptor::nsOutputStreamWrapper::Write_Locked(
    1472           0 :         (const char *)mWriteBuffer, bytesToWrite, &result);
    1473           0 :     mZstream.next_out = mWriteBuffer;
    1474           0 :     mZstream.avail_out = mWriteBufferLen;
    1475           0 :     return rv;
    1476             : }
    1477             : 

Generated by: LCOV version 1.13