dom/quota/QuotaObject.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     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 file,
     5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "QuotaObject.h"
     9 #include "QuotaManager.h"
    10 #include "Utilities.h"
    12 USING_QUOTA_NAMESPACE
    14 void
    15 QuotaObject::AddRef()
    16 {
    17   QuotaManager* quotaManager = QuotaManager::Get();
    18   if (!quotaManager) {
    19     NS_ERROR("Null quota manager, this shouldn't happen, possible leak!");
    21     ++mRefCnt;
    23     return;
    24   }
    26   MutexAutoLock lock(quotaManager->mQuotaMutex);
    28   ++mRefCnt;
    29 }
    31 void
    32 QuotaObject::Release()
    33 {
    34   QuotaManager* quotaManager = QuotaManager::Get();
    35   if (!quotaManager) {
    36     NS_ERROR("Null quota manager, this shouldn't happen, possible leak!");
    38     nsrefcnt count = --mRefCnt;
    39     if (count == 0) {
    40       mRefCnt = 1;
    41       delete this;
    42     }
    44     return;
    45   }
    47   {
    48     MutexAutoLock lock(quotaManager->mQuotaMutex);
    50     --mRefCnt;
    52     if (mRefCnt > 0) {
    53       return;
    54     }
    56     if (mOriginInfo) {
    57       mOriginInfo->mQuotaObjects.Remove(mPath);
    58     }
    59   }
    61   delete this;
    62 }
    64 void
    65 QuotaObject::UpdateSize(int64_t aSize)
    66 {
    67   QuotaManager* quotaManager = QuotaManager::Get();
    68   NS_ASSERTION(quotaManager, "Shouldn't be null!");
    70   MutexAutoLock lock(quotaManager->mQuotaMutex);
    72   if (!mOriginInfo) {
    73     return;
    74   }
    76   GroupInfo* groupInfo = mOriginInfo->mGroupInfo;
    78   if (groupInfo->IsForTemporaryStorage()) {
    79     quotaManager->mTemporaryStorageUsage -= mSize;
    80   }
    81   groupInfo->mUsage -= mSize;
    82   mOriginInfo->mUsage -= mSize;
    84   mSize = aSize;
    86   mOriginInfo->mUsage += mSize;
    87   groupInfo->mUsage += mSize;
    88   if (groupInfo->IsForTemporaryStorage()) {
    89     quotaManager->mTemporaryStorageUsage += mSize;
    90   }
    91 }
    93 bool
    94 QuotaObject::MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount)
    95 {
    96   int64_t end = aOffset + aCount;
    98   QuotaManager* quotaManager = QuotaManager::Get();
    99   NS_ASSERTION(quotaManager, "Shouldn't be null!");
   101   MutexAutoLock lock(quotaManager->mQuotaMutex);
   103   if (mSize >= end || !mOriginInfo) {
   104     return true;
   105   }
   107   GroupInfo* groupInfo = mOriginInfo->mGroupInfo;
   109   if (groupInfo->IsForPersistentStorage()) {
   110     uint64_t newUsage = mOriginInfo->mUsage - mSize + end;
   112     if (newUsage > mOriginInfo->mLimit) {
   113       // This will block the thread, but it will also drop the mutex while
   114       // waiting. The mutex will be reacquired again when the waiting is
   115       // finished.
   116       if (!quotaManager->LockedQuotaIsLifted()) {
   117         return false;
   118       }
   120       // Threads raced, the origin info removal has been done by some other
   121       // thread.
   122       if (!mOriginInfo) {
   123         // The other thread could allocate more space.
   124         if (end > mSize) {
   125           mSize = end;
   126         }
   128         return true;
   129       }
   131       nsCString group = mOriginInfo->mGroupInfo->mGroup;
   132       nsCString origin = mOriginInfo->mOrigin;
   134       mOriginInfo->LockedClearOriginInfos();
   135       NS_ASSERTION(!mOriginInfo,
   136                    "Should have cleared in LockedClearOriginInfos!");
   138       quotaManager->LockedRemoveQuotaForOrigin(PERSISTENCE_TYPE_PERSISTENT,
   139                                                group, origin);
   141       // Some other thread could increase the size without blocking (increasing
   142       // the origin usage without hitting the limit), but no more than this one.
   143       NS_ASSERTION(mSize < end, "This shouldn't happen!");
   145       mSize = end;
   147       return true;
   148     }
   150     mOriginInfo->mUsage = newUsage;
   152     groupInfo->mUsage = groupInfo->mUsage - mSize + end;
   154     mSize = end;
   156     return true;
   157   }
   159   NS_ASSERTION(groupInfo->mPersistenceType == PERSISTENCE_TYPE_TEMPORARY,
   160                "Huh?");
   162   uint64_t delta = end - mSize;
   164   uint64_t newUsage = mOriginInfo->mUsage + delta;
   166   // Temporary storage has no limit for origin usage (there's a group and the
   167   // global limit though).
   169   uint64_t newGroupUsage = groupInfo->mUsage + delta;
   171   // Temporary storage has a hard limit for group usage (20 % of the global
   172   // limit).
   173   if (newGroupUsage > quotaManager->GetGroupLimit()) {
   174     return false;
   175   }
   177   uint64_t newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage +
   178                                       delta;
   180   if (newTemporaryStorageUsage > quotaManager->mTemporaryStorageLimit) {
   181     // This will block the thread without holding the lock while waitting.
   183     nsAutoTArray<OriginInfo*, 10> originInfos;
   184     uint64_t sizeToBeFreed =
   185       quotaManager->LockedCollectOriginsForEviction(delta, originInfos);
   187     if (!sizeToBeFreed) {
   188       return false;
   189     }
   191     NS_ASSERTION(sizeToBeFreed >= delta, "Huh?");
   193     {
   194       MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
   196       for (uint32_t i = 0; i < originInfos.Length(); i++) {
   197         quotaManager->DeleteTemporaryFilesForOrigin(originInfos[i]->mOrigin);
   198       }
   199     }
   201     // Relocked.
   203     NS_ASSERTION(mOriginInfo, "How come?!");
   205     nsTArray<nsCString> origins;
   206     for (uint32_t i = 0; i < originInfos.Length(); i++) {
   207       OriginInfo* originInfo = originInfos[i];
   209       NS_ASSERTION(originInfo != mOriginInfo, "Deleted itself!");
   211       nsCString group = originInfo->mGroupInfo->mGroup;
   212       nsCString origin = originInfo->mOrigin;
   213       quotaManager->LockedRemoveQuotaForOrigin(PERSISTENCE_TYPE_TEMPORARY,
   214                                                group, origin);
   216 #ifdef DEBUG
   217       originInfos[i] = nullptr;
   218 #endif
   220       origins.AppendElement(origin);
   221     }
   223     // We unlocked and relocked several times so we need to recompute all the
   224     // essential variables and recheck the group limit.
   226     delta = end - mSize;
   228     newUsage = mOriginInfo->mUsage + delta;
   230     newGroupUsage = groupInfo->mUsage + delta;
   232     if (newGroupUsage > quotaManager->GetGroupLimit()) {
   233       // Unfortunately some other thread increased the group usage in the
   234       // meantime and we are not below the group limit anymore.
   236       // However, the origin eviction must be finalized in this case too.
   237       MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
   239       quotaManager->FinalizeOriginEviction(origins);
   241       return false;
   242     }
   244     newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage + delta;
   246     NS_ASSERTION(newTemporaryStorageUsage <=
   247                  quotaManager->mTemporaryStorageLimit, "How come?!");
   249     // Ok, we successfully freed enough space and the operation can continue
   250     // without throwing the quota error.
   252     mOriginInfo->mUsage = newUsage;
   253     groupInfo->mUsage = newGroupUsage;
   254     quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;;
   256     // Some other thread could increase the size in the meantime, but no more
   257     // than this one.
   258     NS_ASSERTION(mSize < end, "This shouldn't happen!");
   259     mSize = end;
   261     // Finally, release IO thread only objects and allow next synchronized
   262     // ops for the evicted origins.
   263     MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
   265     quotaManager->FinalizeOriginEviction(origins);
   267     return true;
   268   }
   270   mOriginInfo->mUsage = newUsage;
   271   groupInfo->mUsage = newGroupUsage;
   272   quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;
   274   mSize = end;
   276   return true;
   277 }
   279 void
   280 OriginInfo::LockedDecreaseUsage(int64_t aSize)
   281 {
   282   AssertCurrentThreadOwnsQuotaMutex();
   284   mUsage -= aSize;
   286   mGroupInfo->mUsage -= aSize;
   288   if (mGroupInfo->IsForTemporaryStorage()) {
   289     QuotaManager* quotaManager = QuotaManager::Get();
   290     NS_ASSERTION(quotaManager, "Shouldn't be null!");
   292     quotaManager->mTemporaryStorageUsage -= aSize;
   293   }
   294 }
   296 // static
   297 PLDHashOperator
   298 OriginInfo::ClearOriginInfoCallback(const nsAString& aKey,
   299                                     QuotaObject* aValue,
   300                                     void* aUserArg)
   301 {
   302   NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
   303   NS_ASSERTION(aValue, "Null pointer!");
   305   aValue->mOriginInfo = nullptr;
   307   return PL_DHASH_NEXT;
   308 }
   310 already_AddRefed<OriginInfo>
   311 GroupInfo::LockedGetOriginInfo(const nsACString& aOrigin)
   312 {
   313   AssertCurrentThreadOwnsQuotaMutex();
   315   for (uint32_t index = 0; index < mOriginInfos.Length(); index++) {
   316     nsRefPtr<OriginInfo>& originInfo = mOriginInfos[index];
   318     if (originInfo->mOrigin == aOrigin) {
   319       nsRefPtr<OriginInfo> result = originInfo;
   320       return result.forget();
   321     }
   322   }
   324   return nullptr;
   325 }
   327 void
   328 GroupInfo::LockedAddOriginInfo(OriginInfo* aOriginInfo)
   329 {
   330   AssertCurrentThreadOwnsQuotaMutex();
   332   NS_ASSERTION(!mOriginInfos.Contains(aOriginInfo),
   333                "Replacing an existing entry!");
   334   mOriginInfos.AppendElement(aOriginInfo);
   336   mUsage += aOriginInfo->mUsage;
   338   if (IsForTemporaryStorage()) {
   339     QuotaManager* quotaManager = QuotaManager::Get();
   340     NS_ASSERTION(quotaManager, "Shouldn't be null!");
   342     quotaManager->mTemporaryStorageUsage += aOriginInfo->mUsage;
   343   }
   344 }
   346 void
   347 GroupInfo::LockedRemoveOriginInfo(const nsACString& aOrigin)
   348 {
   349   AssertCurrentThreadOwnsQuotaMutex();
   351   for (uint32_t index = 0; index < mOriginInfos.Length(); index++) {
   352     if (mOriginInfos[index]->mOrigin == aOrigin) {
   353       mUsage -= mOriginInfos[index]->mUsage;
   355       if (IsForTemporaryStorage()) {
   356         QuotaManager* quotaManager = QuotaManager::Get();
   357         NS_ASSERTION(quotaManager, "Shouldn't be null!");
   359         quotaManager->mTemporaryStorageUsage -= mOriginInfos[index]->mUsage;
   360       }
   362       mOriginInfos.RemoveElementAt(index);
   364       return;
   365     }
   366   }
   367 }
   369 void
   370 GroupInfo::LockedRemoveOriginInfos()
   371 {
   372   AssertCurrentThreadOwnsQuotaMutex();
   374   for (uint32_t index = mOriginInfos.Length(); index > 0; index--) {
   375     mUsage -= mOriginInfos[index - 1]->mUsage;
   377     if (IsForTemporaryStorage()) {
   378       QuotaManager* quotaManager = QuotaManager::Get();
   379       NS_ASSERTION(quotaManager, "Shouldn't be null!");
   381       quotaManager->mTemporaryStorageUsage -= mOriginInfos[index - 1]->mUsage;
   382     }
   384     mOriginInfos.RemoveElementAt(index - 1);
   385   }
   386 }
   388 void
   389 GroupInfo::LockedRemoveOriginInfosForPattern(const nsACString& aPattern)
   390 {
   391   AssertCurrentThreadOwnsQuotaMutex();
   393   for (uint32_t index = mOriginInfos.Length(); index > 0; index--) {
   394     if (PatternMatchesOrigin(aPattern, mOriginInfos[index - 1]->mOrigin)) {
   395       mUsage -= mOriginInfos[index - 1]->mUsage;
   397       if (IsForTemporaryStorage()) {
   398         QuotaManager* quotaManager = QuotaManager::Get();
   399         NS_ASSERTION(quotaManager, "Shouldn't be null!");
   401         quotaManager->mTemporaryStorageUsage -= mOriginInfos[index - 1]->mUsage;
   402       }
   404       mOriginInfos.RemoveElementAt(index - 1);
   405     }
   406   }
   407 }
   409 nsRefPtr<GroupInfo>&
   410 GroupInfoPair::GetGroupInfoForPersistenceType(PersistenceType aPersistenceType)
   411 {
   412   switch (aPersistenceType) {
   413     case PERSISTENCE_TYPE_PERSISTENT:
   414       return mPersistentStorageGroupInfo;
   415     case PERSISTENCE_TYPE_TEMPORARY:
   416       return mTemporaryStorageGroupInfo;
   418     case PERSISTENCE_TYPE_INVALID:
   419     default:
   420       MOZ_CRASH("Bad persistence type value!");
   421       return mPersistentStorageGroupInfo;
   422   }
   423 }

mercurial