netwerk/cache2/CacheFileMetadata.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "CacheLog.h"
     6 #include "CacheFileMetadata.h"
     8 #include "CacheFileIOManager.h"
     9 #include "nsICacheEntry.h"
    10 #include "CacheHashUtils.h"
    11 #include "CacheFileChunk.h"
    12 #include "CacheFileUtils.h"
    13 #include "nsILoadContextInfo.h"
    14 #include "../cache/nsCacheUtils.h"
    15 #include "nsIFile.h"
    16 #include "mozilla/Telemetry.h"
    17 #include "mozilla/DebugOnly.h"
    18 #include "prnetdb.h"
    21 namespace mozilla {
    22 namespace net {
    24 #define kMinMetadataRead 1024  // TODO find optimal value from telemetry
    25 #define kAlignSize       4096
    27 #define kCacheEntryVersion 1
    29 NS_IMPL_ISUPPORTS(CacheFileMetadata, CacheFileIOListener)
    31 CacheFileMetadata::CacheFileMetadata(CacheFileHandle *aHandle, const nsACString &aKey)
    32   : CacheMemoryConsumer(NORMAL)
    33   , mHandle(aHandle)
    34   , mHashArray(nullptr)
    35   , mHashArraySize(0)
    36   , mHashCount(0)
    37   , mOffset(-1)
    38   , mBuf(nullptr)
    39   , mBufSize(0)
    40   , mWriteBuf(nullptr)
    41   , mElementsSize(0)
    42   , mIsDirty(false)
    43   , mAnonymous(false)
    44   , mInBrowser(false)
    45   , mAppId(nsILoadContextInfo::NO_APP_ID)
    46 {
    47   LOG(("CacheFileMetadata::CacheFileMetadata() [this=%p, handle=%p, key=%s]",
    48        this, aHandle, PromiseFlatCString(aKey).get()));
    50   MOZ_COUNT_CTOR(CacheFileMetadata);
    51   memset(&mMetaHdr, 0, sizeof(CacheFileMetadataHeader));
    52   mMetaHdr.mVersion = kCacheEntryVersion;
    53   mMetaHdr.mExpirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
    54   mKey = aKey;
    56   DebugOnly<nsresult> rv;
    57   rv = ParseKey(aKey);
    58   MOZ_ASSERT(NS_SUCCEEDED(rv));
    59 }
    61 CacheFileMetadata::CacheFileMetadata(bool aMemoryOnly, const nsACString &aKey)
    62   : CacheMemoryConsumer(aMemoryOnly ? MEMORY_ONLY : NORMAL)
    63   , mHandle(nullptr)
    64   , mHashArray(nullptr)
    65   , mHashArraySize(0)
    66   , mHashCount(0)
    67   , mOffset(0)
    68   , mBuf(nullptr)
    69   , mBufSize(0)
    70   , mWriteBuf(nullptr)
    71   , mElementsSize(0)
    72   , mIsDirty(true)
    73   , mAnonymous(false)
    74   , mInBrowser(false)
    75   , mAppId(nsILoadContextInfo::NO_APP_ID)
    76 {
    77   LOG(("CacheFileMetadata::CacheFileMetadata() [this=%p, key=%s]",
    78        this, PromiseFlatCString(aKey).get()));
    80   MOZ_COUNT_CTOR(CacheFileMetadata);
    81   memset(&mMetaHdr, 0, sizeof(CacheFileMetadataHeader));
    82   mMetaHdr.mVersion = kCacheEntryVersion;
    83   mMetaHdr.mExpirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
    84   mMetaHdr.mFetchCount = 1;
    85   mKey = aKey;
    86   mMetaHdr.mKeySize = mKey.Length();
    88   DebugOnly<nsresult> rv;
    89   rv = ParseKey(aKey);
    90   MOZ_ASSERT(NS_SUCCEEDED(rv));
    91 }
    93 CacheFileMetadata::CacheFileMetadata()
    94   : CacheMemoryConsumer(DONT_REPORT /* This is a helper class */)
    95   , mHandle(nullptr)
    96   , mHashArray(nullptr)
    97   , mHashArraySize(0)
    98   , mHashCount(0)
    99   , mOffset(0)
   100   , mBuf(nullptr)
   101   , mBufSize(0)
   102   , mWriteBuf(nullptr)
   103   , mElementsSize(0)
   104   , mIsDirty(false)
   105   , mAnonymous(false)
   106   , mInBrowser(false)
   107   , mAppId(nsILoadContextInfo::NO_APP_ID)
   108 {
   109   LOG(("CacheFileMetadata::CacheFileMetadata() [this=%p]", this));
   111   MOZ_COUNT_CTOR(CacheFileMetadata);
   112   memset(&mMetaHdr, 0, sizeof(CacheFileMetadataHeader));
   113 }
   115 CacheFileMetadata::~CacheFileMetadata()
   116 {
   117   LOG(("CacheFileMetadata::~CacheFileMetadata() [this=%p]", this));
   119   MOZ_COUNT_DTOR(CacheFileMetadata);
   120   MOZ_ASSERT(!mListener);
   122   if (mHashArray) {
   123     free(mHashArray);
   124     mHashArray = nullptr;
   125     mHashArraySize = 0;
   126   }
   128   if (mBuf) {
   129     free(mBuf);
   130     mBuf = nullptr;
   131     mBufSize = 0;
   132   }
   133 }
   135 void
   136 CacheFileMetadata::SetHandle(CacheFileHandle *aHandle)
   137 {
   138   LOG(("CacheFileMetadata::SetHandle() [this=%p, handle=%p]", this, aHandle));
   140   MOZ_ASSERT(!mHandle);
   142   mHandle = aHandle;
   143 }
   145 nsresult
   146 CacheFileMetadata::GetKey(nsACString &_retval)
   147 {
   148   _retval = mKey;
   149   return NS_OK;
   150 }
   152 nsresult
   153 CacheFileMetadata::ReadMetadata(CacheFileMetadataListener *aListener)
   154 {
   155   LOG(("CacheFileMetadata::ReadMetadata() [this=%p, listener=%p]", this, aListener));
   157   MOZ_ASSERT(!mListener);
   158   MOZ_ASSERT(!mHashArray);
   159   MOZ_ASSERT(!mBuf);
   160   MOZ_ASSERT(!mWriteBuf);
   162   nsresult rv;
   164   int64_t size = mHandle->FileSize();
   165   MOZ_ASSERT(size != -1);
   167   if (size == 0) {
   168     // this is a new entry
   169     LOG(("CacheFileMetadata::ReadMetadata() - Filesize == 0, creating empty "
   170          "metadata. [this=%p]", this));
   172     InitEmptyMetadata();
   173     aListener->OnMetadataRead(NS_OK);
   174     return NS_OK;
   175   }
   177   if (size < int64_t(sizeof(CacheFileMetadataHeader) + 2*sizeof(uint32_t))) {
   178     // there must be at least checksum, header and offset
   179     LOG(("CacheFileMetadata::ReadMetadata() - File is corrupted, creating "
   180          "empty metadata. [this=%p, filesize=%lld]", this, size));
   182     InitEmptyMetadata();
   183     aListener->OnMetadataRead(NS_OK);
   184     return NS_OK;
   185   }
   187   // round offset to 4k blocks
   188   int64_t offset = (size / kAlignSize) * kAlignSize;
   190   if (size - offset < kMinMetadataRead && offset > kAlignSize)
   191     offset -= kAlignSize;
   193   mBufSize = size - offset;
   194   mBuf = static_cast<char *>(moz_xmalloc(mBufSize));
   196   DoMemoryReport(MemoryUsage());
   198   LOG(("CacheFileMetadata::ReadMetadata() - Reading metadata from disk, trying "
   199        "offset=%lld, filesize=%lld [this=%p]", offset, size, this));
   201   mListener = aListener;
   202   rv = CacheFileIOManager::Read(mHandle, offset, mBuf, mBufSize, true, this);
   203   if (NS_FAILED(rv)) {
   204     LOG(("CacheFileMetadata::ReadMetadata() - CacheFileIOManager::Read() failed"
   205          " synchronously, creating empty metadata. [this=%p, rv=0x%08x]",
   206          this, rv));
   208     mListener = nullptr;
   209     InitEmptyMetadata();
   210     aListener->OnMetadataRead(NS_OK);
   211     return NS_OK;
   212   }
   214   return NS_OK;
   215 }
   217 nsresult
   218 CacheFileMetadata::WriteMetadata(uint32_t aOffset,
   219                                  CacheFileMetadataListener *aListener)
   220 {
   221   LOG(("CacheFileMetadata::WriteMetadata() [this=%p, offset=%d, listener=%p]",
   222        this, aOffset, aListener));
   224   MOZ_ASSERT(!mListener);
   225   MOZ_ASSERT(!mWriteBuf);
   227   nsresult rv;
   229   mIsDirty = false;
   231   mWriteBuf = static_cast<char *>(moz_xmalloc(sizeof(uint32_t) +
   232                 mHashCount * sizeof(CacheHash::Hash16_t) +
   233                 sizeof(CacheFileMetadataHeader) + mKey.Length() + 1 +
   234                 mElementsSize + sizeof(uint32_t)));
   236   char *p = mWriteBuf + sizeof(uint32_t);
   237   memcpy(p, mHashArray, mHashCount * sizeof(CacheHash::Hash16_t));
   238   p += mHashCount * sizeof(CacheHash::Hash16_t);
   239   mMetaHdr.WriteToBuf(p);
   240   p += sizeof(CacheFileMetadataHeader);
   241   memcpy(p, mKey.get(), mKey.Length());
   242   p += mKey.Length();
   243   *p = 0;
   244   p++;
   245   memcpy(p, mBuf, mElementsSize);
   246   p += mElementsSize;
   248   CacheHash::Hash32_t hash;
   249   hash = CacheHash::Hash(mWriteBuf + sizeof(uint32_t),
   250                          p - mWriteBuf - sizeof(uint32_t));
   251   NetworkEndian::writeUint32(mWriteBuf, hash);
   253   NetworkEndian::writeUint32(p, aOffset);
   254   p += sizeof(uint32_t);
   256   char * writeBuffer;
   257   if (aListener) {
   258     mListener = aListener;
   259     writeBuffer = mWriteBuf;
   260   } else {
   261     // We are not going to pass |this| as callback to CacheFileIOManager::Write
   262     // so we must allocate a new buffer that will be released automatically when
   263     // write is finished.  This is actually better than to let
   264     // CacheFileMetadata::OnDataWritten do the job, since when dispatching the
   265     // result from some reason fails during shutdown, we would unnecessarily leak
   266     // both this object and the buffer.
   267     writeBuffer = static_cast<char *>(moz_xmalloc(p - mWriteBuf));
   268     memcpy(mWriteBuf, writeBuffer, p - mWriteBuf);
   269   }
   271   rv = CacheFileIOManager::Write(mHandle, aOffset, writeBuffer, p - mWriteBuf,
   272                                  true, aListener ? this : nullptr);
   273   if (NS_FAILED(rv)) {
   274     LOG(("CacheFileMetadata::WriteMetadata() - CacheFileIOManager::Write() "
   275          "failed synchronously. [this=%p, rv=0x%08x]", this, rv));
   277     mListener = nullptr;
   278     if (writeBuffer != mWriteBuf) {
   279       free(writeBuffer);
   280     }
   281     free(mWriteBuf);
   282     mWriteBuf = nullptr;
   283     NS_ENSURE_SUCCESS(rv, rv);
   284   }
   286   DoMemoryReport(MemoryUsage());
   288   return NS_OK;
   289 }
   291 nsresult
   292 CacheFileMetadata::SyncReadMetadata(nsIFile *aFile)
   293 {
   294   LOG(("CacheFileMetadata::SyncReadMetadata() [this=%p]", this));
   296   MOZ_ASSERT(!mListener);
   297   MOZ_ASSERT(!mHandle);
   298   MOZ_ASSERT(!mHashArray);
   299   MOZ_ASSERT(!mBuf);
   300   MOZ_ASSERT(!mWriteBuf);
   301   MOZ_ASSERT(mKey.IsEmpty());
   303   nsresult rv;
   305   int64_t fileSize;
   306   rv = aFile->GetFileSize(&fileSize);
   307   NS_ENSURE_SUCCESS(rv, rv);
   309   PRFileDesc *fd;
   310   rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0600, &fd);
   311   NS_ENSURE_SUCCESS(rv, rv);
   313   int64_t offset = PR_Seek64(fd, fileSize - sizeof(uint32_t), PR_SEEK_SET);
   314   if (offset == -1) {
   315     PR_Close(fd);
   316     return NS_ERROR_FAILURE;
   317   }
   319   uint32_t metaOffset;
   320   int32_t bytesRead = PR_Read(fd, &metaOffset, sizeof(uint32_t));
   321   if (bytesRead != sizeof(uint32_t)) {
   322     PR_Close(fd);
   323     return NS_ERROR_FAILURE;
   324   }
   326   metaOffset = NetworkEndian::readUint32(&metaOffset);
   327   if (metaOffset > fileSize) {
   328     PR_Close(fd);
   329     return NS_ERROR_FAILURE;
   330   }
   332   mBufSize = fileSize - metaOffset;
   333   mBuf = static_cast<char *>(moz_xmalloc(mBufSize));
   335   DoMemoryReport(MemoryUsage());
   337   offset = PR_Seek64(fd, metaOffset, PR_SEEK_SET);
   338   if (offset == -1) {
   339     PR_Close(fd);
   340     return NS_ERROR_FAILURE;
   341   }
   343   bytesRead = PR_Read(fd, mBuf, mBufSize);
   344   PR_Close(fd);
   345   if (bytesRead != static_cast<int32_t>(mBufSize)) {
   346     return NS_ERROR_FAILURE;
   347   }
   349   rv = ParseMetadata(metaOffset, 0, false);
   350   NS_ENSURE_SUCCESS(rv, rv);
   352   return NS_OK;
   353 }
   355 const char *
   356 CacheFileMetadata::GetElement(const char *aKey)
   357 {
   358   const char *data = mBuf;
   359   const char *limit = mBuf + mElementsSize;
   361   while (data < limit) {
   362     // Point to the value part
   363     const char *value = data + strlen(data) + 1;
   364     MOZ_ASSERT(value < limit, "Metadata elements corrupted");
   365     if (strcmp(data, aKey) == 0) {
   366       LOG(("CacheFileMetadata::GetElement() - Key found [this=%p, key=%s]",
   367            this, aKey));
   368       return value;
   369     }
   371     // Skip value part
   372     data = value + strlen(value) + 1;
   373   }
   374   MOZ_ASSERT(data == limit, "Metadata elements corrupted");
   375   LOG(("CacheFileMetadata::GetElement() - Key not found [this=%p, key=%s]",
   376        this, aKey));
   377   return nullptr;
   378 }
   380 nsresult
   381 CacheFileMetadata::SetElement(const char *aKey, const char *aValue)
   382 {
   383   LOG(("CacheFileMetadata::SetElement() [this=%p, key=%s, value=%p]",
   384        this, aKey, aValue));
   386   MarkDirty();
   388   const uint32_t keySize = strlen(aKey) + 1;
   389   char *pos = const_cast<char *>(GetElement(aKey));
   391   if (!aValue) {
   392     // No value means remove the key/value pair completely, if existing
   393     if (pos) {
   394       uint32_t oldValueSize = strlen(pos) + 1;
   395       uint32_t offset = pos - mBuf;
   396       uint32_t remainder = mElementsSize - (offset + oldValueSize);
   398       memmove(pos - keySize, pos + oldValueSize, remainder);
   399       mElementsSize -= keySize + oldValueSize;
   400     }
   401     return NS_OK;
   402   }
   404   const uint32_t valueSize = strlen(aValue) + 1;
   405   uint32_t newSize = mElementsSize + valueSize;
   406   if (pos) {
   407     const uint32_t oldValueSize = strlen(pos) + 1;
   408     const uint32_t offset = pos - mBuf;
   409     const uint32_t remainder = mElementsSize - (offset + oldValueSize);
   411     // Update the value in place
   412     newSize -= oldValueSize;
   413     EnsureBuffer(newSize);
   415     // Move the remainder to the right place
   416     pos = mBuf + offset;
   417     memmove(pos + valueSize, pos + oldValueSize, remainder);
   418   } else {
   419     // allocate new meta data element
   420     newSize += keySize;
   421     EnsureBuffer(newSize);
   423     // Add after last element
   424     pos = mBuf + mElementsSize;
   425     memcpy(pos, aKey, keySize);
   426     pos += keySize;
   427   }
   429   // Update value
   430   memcpy(pos, aValue, valueSize);
   431   mElementsSize = newSize;
   433   return NS_OK;
   434 }
   436 CacheHash::Hash16_t
   437 CacheFileMetadata::GetHash(uint32_t aIndex)
   438 {
   439   MOZ_ASSERT(aIndex < mHashCount);
   440   return NetworkEndian::readUint16(&mHashArray[aIndex]);
   441 }
   443 nsresult
   444 CacheFileMetadata::SetHash(uint32_t aIndex, CacheHash::Hash16_t aHash)
   445 {
   446   LOG(("CacheFileMetadata::SetHash() [this=%p, idx=%d, hash=%x]",
   447        this, aIndex, aHash));
   449   MarkDirty();
   451   MOZ_ASSERT(aIndex <= mHashCount);
   453   if (aIndex > mHashCount) {
   454     return NS_ERROR_INVALID_ARG;
   455   } else if (aIndex == mHashCount) {
   456     if ((aIndex + 1) * sizeof(CacheHash::Hash16_t) > mHashArraySize) {
   457       // reallocate hash array buffer
   458       if (mHashArraySize == 0)
   459         mHashArraySize = 32 * sizeof(CacheHash::Hash16_t);
   460       else
   461         mHashArraySize *= 2;
   462       mHashArray = static_cast<CacheHash::Hash16_t *>(
   463                      moz_xrealloc(mHashArray, mHashArraySize));
   464     }
   466     mHashCount++;
   467   }
   469   NetworkEndian::writeUint16(&mHashArray[aIndex], aHash);
   471   DoMemoryReport(MemoryUsage());
   473   return NS_OK;
   474 }
   476 nsresult
   477 CacheFileMetadata::SetExpirationTime(uint32_t aExpirationTime)
   478 {
   479   LOG(("CacheFileMetadata::SetExpirationTime() [this=%p, expirationTime=%d]",
   480        this, aExpirationTime));
   482   MarkDirty();
   483   mMetaHdr.mExpirationTime = aExpirationTime;
   484   return NS_OK;
   485 }
   487 nsresult
   488 CacheFileMetadata::GetExpirationTime(uint32_t *_retval)
   489 {
   490   *_retval = mMetaHdr.mExpirationTime;
   491   return NS_OK;
   492 }
   494 nsresult
   495 CacheFileMetadata::SetLastModified(uint32_t aLastModified)
   496 {
   497   LOG(("CacheFileMetadata::SetLastModified() [this=%p, lastModified=%d]",
   498        this, aLastModified));
   500   MarkDirty();
   501   mMetaHdr.mLastModified = aLastModified;
   502   return NS_OK;
   503 }
   505 nsresult
   506 CacheFileMetadata::GetLastModified(uint32_t *_retval)
   507 {
   508   *_retval = mMetaHdr.mLastModified;
   509   return NS_OK;
   510 }
   512 nsresult
   513 CacheFileMetadata::SetFrecency(uint32_t aFrecency)
   514 {
   515   LOG(("CacheFileMetadata::SetFrecency() [this=%p, frecency=%f]",
   516        this, (double)aFrecency));
   518   MarkDirty();
   519   mMetaHdr.mFrecency = aFrecency;
   520   return NS_OK;
   521 }
   523 nsresult
   524 CacheFileMetadata::GetFrecency(uint32_t *_retval)
   525 {
   526   *_retval = mMetaHdr.mFrecency;
   527   return NS_OK;
   528 }
   530 nsresult
   531 CacheFileMetadata::GetLastFetched(uint32_t *_retval)
   532 {
   533   *_retval = mMetaHdr.mLastFetched;
   534   return NS_OK;
   535 }
   537 nsresult
   538 CacheFileMetadata::GetFetchCount(uint32_t *_retval)
   539 {
   540   *_retval = mMetaHdr.mFetchCount;
   541   return NS_OK;
   542 }
   544 nsresult
   545 CacheFileMetadata::OnFileOpened(CacheFileHandle *aHandle, nsresult aResult)
   546 {
   547   MOZ_CRASH("CacheFileMetadata::OnFileOpened should not be called!");
   548   return NS_ERROR_UNEXPECTED;
   549 }
   551 nsresult
   552 CacheFileMetadata::OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
   553                                  nsresult aResult)
   554 {
   555   LOG(("CacheFileMetadata::OnDataWritten() [this=%p, handle=%p, result=0x%08x]",
   556        this, aHandle, aResult));
   558   MOZ_ASSERT(mListener);
   559   MOZ_ASSERT(mWriteBuf);
   561   free(mWriteBuf);
   562   mWriteBuf = nullptr;
   564   nsCOMPtr<CacheFileMetadataListener> listener;
   566   mListener.swap(listener);
   567   listener->OnMetadataWritten(aResult);
   569   DoMemoryReport(MemoryUsage());
   571   return NS_OK;
   572 }
   574 nsresult
   575 CacheFileMetadata::OnDataRead(CacheFileHandle *aHandle, char *aBuf,
   576                               nsresult aResult)
   577 {
   578   LOG(("CacheFileMetadata::OnDataRead() [this=%p, handle=%p, result=0x%08x]",
   579        this, aHandle, aResult));
   581   MOZ_ASSERT(mListener);
   583   nsresult rv, retval;
   584   nsCOMPtr<CacheFileMetadataListener> listener;
   586   if (NS_FAILED(aResult)) {
   587     LOG(("CacheFileMetadata::OnDataRead() - CacheFileIOManager::Read() failed"
   588          ", creating empty metadata. [this=%p, rv=0x%08x]", this, aResult));
   590     InitEmptyMetadata();
   591     retval = NS_OK;
   593     mListener.swap(listener);
   594     listener->OnMetadataRead(retval);
   595     return NS_OK;
   596   }
   598   // check whether we have read all necessary data
   599   uint32_t realOffset = NetworkEndian::readUint32(mBuf + mBufSize -
   600                                                   sizeof(uint32_t));
   602   int64_t size = mHandle->FileSize();
   603   MOZ_ASSERT(size != -1);
   605   if (realOffset >= size) {
   606     LOG(("CacheFileMetadata::OnDataRead() - Invalid realOffset, creating "
   607          "empty metadata. [this=%p, realOffset=%d, size=%lld]", this,
   608          realOffset, size));
   610     InitEmptyMetadata();
   611     retval = NS_OK;
   613     mListener.swap(listener);
   614     listener->OnMetadataRead(retval);
   615     return NS_OK;
   616   }
   618   uint32_t usedOffset = size - mBufSize;
   620   if (realOffset < usedOffset) {
   621     uint32_t missing = usedOffset - realOffset;
   622     // we need to read more data
   623     mBuf = static_cast<char *>(moz_xrealloc(mBuf, mBufSize + missing));
   624     memmove(mBuf + missing, mBuf, mBufSize);
   625     mBufSize += missing;
   627     DoMemoryReport(MemoryUsage());
   629     LOG(("CacheFileMetadata::OnDataRead() - We need to read %d more bytes to "
   630          "have full metadata. [this=%p]", missing, this));
   632     rv = CacheFileIOManager::Read(mHandle, realOffset, mBuf, missing, true, this);
   633     if (NS_FAILED(rv)) {
   634       LOG(("CacheFileMetadata::OnDataRead() - CacheFileIOManager::Read() "
   635            "failed synchronously, creating empty metadata. [this=%p, "
   636            "rv=0x%08x]", this, rv));
   638       InitEmptyMetadata();
   639       retval = NS_OK;
   641       mListener.swap(listener);
   642       listener->OnMetadataRead(retval);
   643       return NS_OK;
   644     }
   646     return NS_OK;
   647   }
   649   // We have all data according to offset information at the end of the entry.
   650   // Try to parse it.
   651   rv = ParseMetadata(realOffset, realOffset - usedOffset, true);
   652   if (NS_FAILED(rv)) {
   653     LOG(("CacheFileMetadata::OnDataRead() - Error parsing metadata, creating "
   654          "empty metadata. [this=%p]", this));
   655     InitEmptyMetadata();
   656     retval = NS_OK;
   657   }
   658   else {
   659     retval = NS_OK;
   660   }
   662   mListener.swap(listener);
   663   listener->OnMetadataRead(retval);
   665   return NS_OK;
   666 }
   668 nsresult
   669 CacheFileMetadata::OnFileDoomed(CacheFileHandle *aHandle, nsresult aResult)
   670 {
   671   MOZ_CRASH("CacheFileMetadata::OnFileDoomed should not be called!");
   672   return NS_ERROR_UNEXPECTED;
   673 }
   675 nsresult
   676 CacheFileMetadata::OnEOFSet(CacheFileHandle *aHandle, nsresult aResult)
   677 {
   678   MOZ_CRASH("CacheFileMetadata::OnEOFSet should not be called!");
   679   return NS_ERROR_UNEXPECTED;
   680 }
   682 nsresult
   683 CacheFileMetadata::OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult)
   684 {
   685   MOZ_CRASH("CacheFileMetadata::OnFileRenamed should not be called!");
   686   return NS_ERROR_UNEXPECTED;
   687 }
   689 void
   690 CacheFileMetadata::InitEmptyMetadata()
   691 {
   692   if (mBuf) {
   693     free(mBuf);
   694     mBuf = nullptr;
   695     mBufSize = 0;
   696   }
   697   mOffset = 0;
   698   mMetaHdr.mVersion = kCacheEntryVersion;
   699   mMetaHdr.mFetchCount = 1;
   700   mMetaHdr.mExpirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
   701   mMetaHdr.mKeySize = mKey.Length();
   703   DoMemoryReport(MemoryUsage());
   704 }
   706 nsresult
   707 CacheFileMetadata::ParseMetadata(uint32_t aMetaOffset, uint32_t aBufOffset,
   708                                  bool aHaveKey)
   709 {
   710   LOG(("CacheFileMetadata::ParseMetadata() [this=%p, metaOffset=%d, "
   711        "bufOffset=%d, haveKey=%u]", this, aMetaOffset, aBufOffset, aHaveKey));
   713   nsresult rv;
   715   uint32_t metaposOffset = mBufSize - sizeof(uint32_t);
   716   uint32_t hashesOffset = aBufOffset + sizeof(uint32_t);
   717   uint32_t hashCount = aMetaOffset / kChunkSize;
   718   if (aMetaOffset % kChunkSize)
   719     hashCount++;
   720   uint32_t hashesLen = hashCount * sizeof(CacheHash::Hash16_t);
   721   uint32_t hdrOffset = hashesOffset + hashesLen;
   722   uint32_t keyOffset = hdrOffset + sizeof(CacheFileMetadataHeader);
   724   LOG(("CacheFileMetadata::ParseMetadata() [this=%p]\n  metaposOffset=%d\n  "
   725        "hashesOffset=%d\n  hashCount=%d\n  hashesLen=%d\n  hdfOffset=%d\n  "
   726        "keyOffset=%d\n", this, metaposOffset, hashesOffset, hashCount,
   727        hashesLen,hdrOffset, keyOffset));
   729   if (keyOffset > metaposOffset) {
   730     LOG(("CacheFileMetadata::ParseMetadata() - Wrong keyOffset! [this=%p]",
   731          this));
   732     return NS_ERROR_FILE_CORRUPTED;
   733   }
   735   mMetaHdr.ReadFromBuf(mBuf + hdrOffset);
   737   if (mMetaHdr.mVersion != kCacheEntryVersion) {
   738     LOG(("CacheFileMetadata::ParseMetadata() - Not a version we understand to. "
   739          "[version=0x%x, this=%p]", mMetaHdr.mVersion, this));
   740     return NS_ERROR_UNEXPECTED;
   741   }
   743   uint32_t elementsOffset = mMetaHdr.mKeySize + keyOffset + 1;
   745   if (elementsOffset > metaposOffset) {
   746     LOG(("CacheFileMetadata::ParseMetadata() - Wrong elementsOffset %d "
   747          "[this=%p]", elementsOffset, this));
   748     return NS_ERROR_FILE_CORRUPTED;
   749   }
   751   // check that key ends with \0
   752   if (mBuf[elementsOffset - 1] != 0) {
   753     LOG(("CacheFileMetadata::ParseMetadata() - Elements not null terminated. "
   754          "[this=%p]", this));
   755     return NS_ERROR_FILE_CORRUPTED;
   756   }
   759   if (!aHaveKey) {
   760     // get the key form metadata
   761     mKey.Assign(mBuf + keyOffset, mMetaHdr.mKeySize);
   763     rv = ParseKey(mKey);
   764     if (NS_FAILED(rv))
   765       return rv;
   766   }
   767   else {
   768     if (mMetaHdr.mKeySize != mKey.Length()) {
   769       LOG(("CacheFileMetadata::ParseMetadata() - Key collision (1), key=%s "
   770            "[this=%p]", nsCString(mBuf + keyOffset, mMetaHdr.mKeySize).get(),
   771            this));
   772       return NS_ERROR_FILE_CORRUPTED;
   773     }
   775     if (memcmp(mKey.get(), mBuf + keyOffset, mKey.Length()) != 0) {
   776       LOG(("CacheFileMetadata::ParseMetadata() - Key collision (2), key=%s "
   777            "[this=%p]", nsCString(mBuf + keyOffset, mMetaHdr.mKeySize).get(),
   778            this));
   779       return NS_ERROR_FILE_CORRUPTED;
   780     }
   781   }
   783   // check metadata hash (data from hashesOffset to metaposOffset)
   784   CacheHash::Hash32_t hashComputed, hashExpected;
   785   hashComputed = CacheHash::Hash(mBuf + hashesOffset,
   786                                  metaposOffset - hashesOffset);
   787   hashExpected = NetworkEndian::readUint32(mBuf + aBufOffset);
   789   if (hashComputed != hashExpected) {
   790     LOG(("CacheFileMetadata::ParseMetadata() - Metadata hash mismatch! Hash of "
   791          "the metadata is %x, hash in file is %x [this=%p]", hashComputed,
   792          hashExpected, this));
   793     return NS_ERROR_FILE_CORRUPTED;
   794   }
   796   // check elements
   797   rv = CheckElements(mBuf + elementsOffset, metaposOffset - elementsOffset);
   798   if (NS_FAILED(rv))
   799     return rv;
   801   mHashArraySize = hashesLen;
   802   mHashCount = hashCount;
   803   if (mHashArraySize) {
   804     mHashArray = static_cast<CacheHash::Hash16_t *>(
   805                    moz_xmalloc(mHashArraySize));
   806     memcpy(mHashArray, mBuf + hashesOffset, mHashArraySize);
   807   }
   810   mMetaHdr.mFetchCount++;
   811   MarkDirty();
   813   mElementsSize = metaposOffset - elementsOffset;
   814   memmove(mBuf, mBuf + elementsOffset, mElementsSize);
   815   mOffset = aMetaOffset;
   817   // TODO: shrink memory if buffer is too big
   819   DoMemoryReport(MemoryUsage());
   821   return NS_OK;
   822 }
   824 nsresult
   825 CacheFileMetadata::CheckElements(const char *aBuf, uint32_t aSize)
   826 {
   827   if (aSize) {
   828     // Check if the metadata ends with a zero byte.
   829     if (aBuf[aSize - 1] != 0) {
   830       NS_ERROR("Metadata elements are not null terminated");
   831       LOG(("CacheFileMetadata::CheckElements() - Elements are not null "
   832            "terminated. [this=%p]", this));
   833       return NS_ERROR_FILE_CORRUPTED;
   834     }
   835     // Check that there are an even number of zero bytes
   836     // to match the pattern { key \0 value \0 }
   837     bool odd = false;
   838     for (uint32_t i = 0; i < aSize; i++) {
   839       if (aBuf[i] == 0)
   840         odd = !odd;
   841     }
   842     if (odd) {
   843       NS_ERROR("Metadata elements are malformed");
   844       LOG(("CacheFileMetadata::CheckElements() - Elements are malformed. "
   845            "[this=%p]", this));
   846       return NS_ERROR_FILE_CORRUPTED;
   847     }
   848   }
   849   return NS_OK;
   850 }
   852 void
   853 CacheFileMetadata::EnsureBuffer(uint32_t aSize)
   854 {
   855   if (mBufSize < aSize) {
   856     mBufSize = aSize;
   857     mBuf = static_cast<char *>(moz_xrealloc(mBuf, mBufSize));
   858   }
   860   DoMemoryReport(MemoryUsage());
   861 }
   863 nsresult
   864 CacheFileMetadata::ParseKey(const nsACString &aKey)
   865 {
   866   nsCOMPtr<nsILoadContextInfo> info = CacheFileUtils::ParseKey(aKey);
   867   NS_ENSURE_TRUE(info, NS_ERROR_FAILURE);
   869   mAnonymous =  info->IsAnonymous();
   870   mAppId = info->AppId();
   871   mInBrowser = info->IsInBrowserElement();
   873   return NS_OK;
   874 }
   876 // Memory reporting
   878 size_t
   879 CacheFileMetadata::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
   880 {
   881   size_t n = 0;
   882   // mHandle reported via CacheFileIOManager.
   883   n += mKey.SizeOfExcludingThisIfUnshared(mallocSizeOf);
   884   n += mallocSizeOf(mHashArray);
   885   n += mallocSizeOf(mBuf);
   886   n += mallocSizeOf(mWriteBuf);
   887   // mListener is usually the owning CacheFile.
   889   return n;
   890 }
   892 size_t
   893 CacheFileMetadata::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
   894 {
   895   return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
   896 }
   898 } // net
   899 } // mozilla

mercurial