mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-03 18:47:53 +00:00
Bug 856032 - 'Quota management enabled even for origins with unlimited permission granted'. r=janv.
This commit is contained in:
parent
ec8daa4925
commit
a47376de61
@ -15,6 +15,7 @@
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
#include "CheckQuotaHelper.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMStorage.h"
|
||||
#include "nsNetUtil.h"
|
||||
@ -38,9 +39,10 @@
|
||||
#define PERMISSION_DENIED nsIPermissionManager::DENY_ACTION
|
||||
#define PERMISSION_PROMPT nsIPermissionManager::ALLOW_ACTION
|
||||
|
||||
using namespace mozilla;
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
using namespace mozilla::services;
|
||||
using mozilla::dom::quota::CheckQuotaHelper;
|
||||
using mozilla::Preferences;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -111,14 +113,19 @@ CheckPermissionsHelper::Run()
|
||||
// we cannot set the permission from the child).
|
||||
if (permission != PERMISSION_PROMPT &&
|
||||
IndexedDatabaseManager::IsMainProcess()) {
|
||||
NS_ASSERTION(mWindow, "Null window!");
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
|
||||
NS_ASSERTION(sop, "Window didn't QI to nsIScriptObjectPrincipal!");
|
||||
|
||||
nsIPrincipal* windowPrincipal = sop->GetPrincipal();
|
||||
NS_ASSERTION(windowPrincipal, "Null principal!");
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
NS_ENSURE_STATE(permissionManager);
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
|
||||
NS_ENSURE_TRUE(sop, NS_ERROR_FAILURE);
|
||||
|
||||
rv = permissionManager->AddFromPrincipal(sop->GetPrincipal(),
|
||||
rv = permissionManager->AddFromPrincipal(windowPrincipal,
|
||||
PERMISSION_INDEXEDDB, permission,
|
||||
nsIPermissionManager::EXPIRE_NEVER,
|
||||
0);
|
||||
@ -141,6 +148,24 @@ CheckPermissionsHelper::Run()
|
||||
window.swap(mWindow);
|
||||
|
||||
if (permission == PERMISSION_ALLOWED) {
|
||||
// If we're running from a window then we should check the quota permission
|
||||
// as well. If we don't have a window then we're opening a chrome database
|
||||
// and the quota will be unlimited already.
|
||||
if (window) {
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(window);
|
||||
NS_ASSERTION(sop, "Window didn't QI to nsIScriptObjectPrincipal!");
|
||||
|
||||
nsIPrincipal* windowPrincipal = sop->GetPrincipal();
|
||||
NS_ASSERTION(windowPrincipal, "Null principal!");
|
||||
|
||||
uint32_t quotaPermission =
|
||||
CheckQuotaHelper::GetQuotaPermission(windowPrincipal);
|
||||
|
||||
if (quotaPermission == nsIPermissionManager::ALLOW_ACTION) {
|
||||
helper->SetUnlimitedQuotaAllowed();
|
||||
}
|
||||
}
|
||||
|
||||
quota::QuotaManager* quotaManager = quota::QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
|
||||
|
@ -2691,22 +2691,25 @@ CopyData(nsIInputStream* aInputStream, nsIOutputStream* aOutputStream)
|
||||
char copyBuffer[FILE_COPY_BUFFER_SIZE];
|
||||
|
||||
uint32_t numRead;
|
||||
rv = aInputStream->Read(copyBuffer, FILE_COPY_BUFFER_SIZE, &numRead);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aInputStream->Read(copyBuffer, sizeof(copyBuffer), &numRead);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (numRead <= 0) {
|
||||
if (!numRead) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t numWrite;
|
||||
rv = aOutputStream->Write(copyBuffer, numRead, &numWrite);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
NS_ENSURE_TRUE(numWrite == numRead, NS_ERROR_FAILURE);
|
||||
if (numWrite < numRead) {
|
||||
// Must have hit the quota limit.
|
||||
return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
rv = aOutputStream->Flush();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2914,7 +2917,7 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
NS_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = CopyData(inputStream, outputStream);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
cloneFile.mFile->AddFileInfo(fileInfo);
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ LOCAL_INCLUDES = \
|
||||
-I$(topsrcdir)/db/sqlite3/src \
|
||||
-I$(topsrcdir)/dom/base \
|
||||
-I$(topsrcdir)/dom/src/storage \
|
||||
-I$(topsrcdir)/dom/quota \
|
||||
-I$(topsrcdir)/xpcom/build \
|
||||
$(NULL)
|
||||
|
||||
|
@ -1651,7 +1651,7 @@ OpenDatabaseHelper::DoDatabaseWork()
|
||||
|
||||
nsresult rv =
|
||||
quotaManager->EnsureOriginIsInitialized(mASCIIOrigin,
|
||||
mPrivilege,
|
||||
mTrackingQuota,
|
||||
getter_AddRefs(dbDirectory));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
|
@ -6,12 +6,15 @@
|
||||
#define mozilla_dom_indexeddb_opendatabasehelper_h__
|
||||
|
||||
#include "AsyncConnectionHelper.h"
|
||||
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
#include "mozilla/dom/quota/StoragePrivilege.h"
|
||||
|
||||
#include "DatabaseInfo.h"
|
||||
#include "IDBDatabase.h"
|
||||
#include "IDBRequest.h"
|
||||
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
class mozIStorageConnection;
|
||||
|
||||
namespace mozilla {
|
||||
@ -22,8 +25,12 @@ class ContentParent;
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class CheckPermissionsHelper;
|
||||
|
||||
class OpenDatabaseHelper : public HelperBase
|
||||
{
|
||||
friend class CheckPermissionsHelper;
|
||||
|
||||
typedef mozilla::dom::quota::StoragePrivilege StoragePrivilege;
|
||||
|
||||
public:
|
||||
@ -39,7 +46,8 @@ public:
|
||||
mForDeletion(aForDeletion), mPrivilege(aPrivilege), mDatabaseId(nullptr),
|
||||
mContentParent(aContentParent), mCurrentVersion(0), mLastObjectStoreId(0),
|
||||
mLastIndexId(0), mState(eCreated), mResultCode(NS_OK),
|
||||
mLoadDBMetadata(false)
|
||||
mLoadDBMetadata(false),
|
||||
mTrackingQuota(aPrivilege != mozilla::dom::quota::Chrome)
|
||||
{
|
||||
NS_ASSERTION(!aForDeletion || !aRequestedVersion,
|
||||
"Can't be for deletion and request a version!");
|
||||
@ -102,6 +110,12 @@ protected:
|
||||
void DispatchErrorEvent();
|
||||
virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
|
||||
|
||||
// Called by CheckPermissionsHelper on the main thread before dispatch.
|
||||
void SetUnlimitedQuotaAllowed()
|
||||
{
|
||||
mTrackingQuota = false;
|
||||
}
|
||||
|
||||
// Methods only called on the DB thread
|
||||
nsresult DoDatabaseWork();
|
||||
|
||||
@ -140,6 +154,7 @@ protected:
|
||||
|
||||
nsRefPtr<DatabaseInfo> mDBInfo;
|
||||
bool mLoadDBMetadata;
|
||||
bool mTrackingQuota;
|
||||
};
|
||||
|
||||
END_INDEXEDDB_NAMESPACE
|
||||
|
@ -35,29 +35,14 @@ namespace {
|
||||
|
||||
inline
|
||||
uint32_t
|
||||
GetQuotaPermissions(nsIDOMWindow* aWindow)
|
||||
GetQuotaPermissionFromWindow(nsIDOMWindow* aWindow)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(aWindow));
|
||||
NS_ENSURE_TRUE(sop, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
if (nsContentUtils::IsSystemPrincipal(sop->GetPrincipal())) {
|
||||
return nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(permissionManager, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
uint32_t permission;
|
||||
nsresult rv =
|
||||
permissionManager->TestPermissionFromPrincipal(sop->GetPrincipal(),
|
||||
PERMISSION_INDEXEDDB_UNLIMITED,
|
||||
&permission);
|
||||
NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
return permission;
|
||||
return CheckQuotaHelper::GetQuotaPermission(sop->GetPrincipal());
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
@ -128,6 +113,30 @@ CheckQuotaHelper::Cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
uint32_t
|
||||
CheckQuotaHelper::GetQuotaPermission(nsIPrincipal* aPrincipal)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aPrincipal, "Null principal!");
|
||||
|
||||
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
|
||||
return nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> pm =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(pm, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
uint32_t permission;
|
||||
nsresult rv = pm->TestPermissionFromPrincipal(aPrincipal,
|
||||
PERMISSION_INDEXEDDB_UNLIMITED,
|
||||
&permission);
|
||||
NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS3(CheckQuotaHelper, nsIRunnable,
|
||||
nsIInterfaceRequestor,
|
||||
nsIObserver)
|
||||
@ -141,7 +150,7 @@ CheckQuotaHelper::Run()
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (!mHasPrompted) {
|
||||
mPromptResult = GetQuotaPermissions(mWindow);
|
||||
mPromptResult = GetQuotaPermissionFromWindow(mWindow);
|
||||
}
|
||||
|
||||
if (mHasPrompted) {
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/CondVar.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
BEGIN_QUOTA_NAMESPACE
|
||||
@ -37,6 +38,8 @@ public:
|
||||
|
||||
void Cancel();
|
||||
|
||||
static uint32_t GetQuotaPermission(nsIPrincipal* aPrincipal);
|
||||
|
||||
private:
|
||||
nsPIDOMWindow* mWindow;
|
||||
|
||||
|
@ -76,7 +76,10 @@ FileQuotaStreamWithWrite<FileStreamBase>::Write(const char* aBuf,
|
||||
|
||||
if (!FileQuotaStreamWithWrite::
|
||||
mQuotaObject->MaybeAllocateMoreSpace(offset, aCount)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
// A quota failure shouldn't be confused with a write failure. We don't
|
||||
// attempt the write and inform the caller.
|
||||
*_retval = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,10 +481,14 @@ QuotaManager::Init()
|
||||
|
||||
void
|
||||
QuotaManager::InitQuotaForOrigin(const nsACString& aOrigin,
|
||||
int64_t aLimit,
|
||||
int64_t aUsage)
|
||||
int64_t aLimitBytes,
|
||||
int64_t aUsageBytes)
|
||||
{
|
||||
OriginInfo* info = new OriginInfo(aOrigin, aLimit * 1024 * 1024, aUsage);
|
||||
MOZ_ASSERT(aUsageBytes >= 0);
|
||||
MOZ_ASSERT(aLimitBytes > 0);
|
||||
MOZ_ASSERT(aUsageBytes <= aLimitBytes);
|
||||
|
||||
OriginInfo* info = new OriginInfo(aOrigin, aLimitBytes, aUsageBytes);
|
||||
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
|
||||
@ -818,7 +822,7 @@ QuotaManager::GetDirectoryForOrigin(const nsACString& aASCIIOrigin,
|
||||
|
||||
nsresult
|
||||
QuotaManager::EnsureOriginIsInitialized(const nsACString& aOrigin,
|
||||
StoragePrivilege aPrivilege,
|
||||
bool aTrackQuota,
|
||||
nsIFile** aDirectory)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@ -870,7 +874,7 @@ QuotaManager::EnsureOriginIsInitialized(const nsACString& aOrigin,
|
||||
// We need to initialize directories of all clients if they exists and also
|
||||
// get the total usage to initialize the quota.
|
||||
nsAutoPtr<UsageRunnable> runnable;
|
||||
if (aPrivilege != Chrome) {
|
||||
if (aTrackQuota) {
|
||||
runnable = new UsageRunnable();
|
||||
}
|
||||
|
||||
@ -915,12 +919,25 @@ QuotaManager::EnsureOriginIsInitialized(const nsACString& aOrigin,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (aPrivilege != Chrome) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
if (aTrackQuota) {
|
||||
uint64_t quotaMaxBytes = GetStorageQuotaMB() * 1024 * 1024;
|
||||
uint64_t totalUsageBytes = runnable->TotalUsage();
|
||||
|
||||
quotaManager->InitQuotaForOrigin(aOrigin, GetStorageQuotaMB(),
|
||||
runnable->TotalUsage());
|
||||
if (totalUsageBytes > quotaMaxBytes) {
|
||||
NS_WARNING("Origin is already using more storage than allowed by quota!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// XXX This signed/unsigned mismatch must be fixed.
|
||||
int64_t limit = quotaMaxBytes >= uint64_t(INT64_MAX) ?
|
||||
INT64_MAX :
|
||||
int64_t(quotaMaxBytes);
|
||||
|
||||
int64_t usage = totalUsageBytes >= uint64_t(INT64_MAX) ?
|
||||
INT64_MAX :
|
||||
int64_t(totalUsageBytes);
|
||||
|
||||
InitQuotaForOrigin(aOrigin, limit, usage);
|
||||
}
|
||||
|
||||
mInitializedOrigins.AppendElement(aOrigin);
|
||||
|
@ -82,8 +82,8 @@ public:
|
||||
|
||||
void
|
||||
InitQuotaForOrigin(const nsACString& aOrigin,
|
||||
int64_t aLimit,
|
||||
int64_t aUsage);
|
||||
int64_t aLimitBytes,
|
||||
int64_t aUsageBytes);
|
||||
|
||||
void
|
||||
DecreaseUsageForOrigin(const nsACString& aOrigin,
|
||||
@ -192,7 +192,7 @@ public:
|
||||
|
||||
nsresult
|
||||
EnsureOriginIsInitialized(const nsACString& aOrigin,
|
||||
StoragePrivilege aPrivilege,
|
||||
bool aTrackQuota,
|
||||
nsIFile** aDirectory);
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user