blob: c49c45eca9c0cacad912ec11d81e6acd0246a7ad [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/quota/StorageManager.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "bindings/modules/v8/V8StorageEstimate.h"
#include "core/dom/DOMException.h"
#include "core/dom/Document.h"
#include "core/dom/ExceptionCode.h"
#include "modules/permissions/PermissionUtils.h"
#include "modules/quota/StorageEstimate.h"
#include "platform/StorageQuotaCallbacks.h"
#include "platform/UserGestureIndicator.h"
#include "public/platform/Platform.h"
#include "wtf/Functional.h"
namespace blink {
using mojom::blink::PermissionName;
using mojom::blink::PermissionService;
using mojom::blink::PermissionStatus;
namespace {
class EstimateCallbacks final : public StorageQuotaCallbacks {
WTF_MAKE_NONCOPYABLE(EstimateCallbacks);
public:
explicit EstimateCallbacks(ScriptPromiseResolver* resolver)
: m_resolver(resolver) {}
~EstimateCallbacks() override {}
void didQueryStorageUsageAndQuota(unsigned long long usageInBytes,
unsigned long long quotaInBytes) override {
StorageEstimate estimate;
estimate.setUsage(usageInBytes);
estimate.setQuota(quotaInBytes);
m_resolver->resolve(estimate);
}
void didFail(WebStorageQuotaError error) override {
m_resolver->reject(DOMException::create(static_cast<ExceptionCode>(error)));
}
DEFINE_INLINE_VIRTUAL_TRACE() {
visitor->trace(m_resolver);
StorageQuotaCallbacks::trace(visitor);
}
private:
Member<ScriptPromiseResolver> m_resolver;
};
} // namespace
ScriptPromise StorageManager::persist(ScriptState* scriptState) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
ExecutionContext* executionContext = scriptState->getExecutionContext();
SecurityOrigin* securityOrigin = executionContext->getSecurityOrigin();
// TODO(dgrogan): Is the isUnique() check covered by the later
// isSecureContext() check? If so, maybe remove it. Write a test if it
// stays.
if (securityOrigin->isUnique()) {
resolver->reject(DOMException::create(NotSupportedError));
return promise;
}
String errorMessage;
if (!executionContext->isSecureContext(errorMessage)) {
resolver->reject(DOMException::create(SecurityError, errorMessage));
return promise;
}
ASSERT(executionContext->isDocument());
PermissionService* permissionService =
getPermissionService(scriptState->getExecutionContext());
if (!permissionService) {
resolver->reject(DOMException::create(
InvalidStateError,
"In its current state, the global scope can't request permissions."));
return promise;
}
permissionService->RequestPermission(
createPermissionDescriptor(PermissionName::DURABLE_STORAGE),
scriptState->getExecutionContext()->getSecurityOrigin(),
UserGestureIndicator::processingUserGesture(),
convertToBaseCallback(
WTF::bind(&StorageManager::permissionRequestComplete,
wrapPersistent(this), wrapPersistent(resolver))));
return promise;
}
ScriptPromise StorageManager::persisted(ScriptState* scriptState) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
PermissionService* permissionService =
getPermissionService(scriptState->getExecutionContext());
if (!permissionService) {
resolver->reject(DOMException::create(
InvalidStateError,
"In its current state, the global scope can't query permissions."));
return promise;
}
permissionService->HasPermission(
createPermissionDescriptor(PermissionName::DURABLE_STORAGE),
scriptState->getExecutionContext()->getSecurityOrigin(),
convertToBaseCallback(
WTF::bind(&StorageManager::permissionRequestComplete,
wrapPersistent(this), wrapPersistent(resolver))));
return promise;
}
ScriptPromise StorageManager::estimate(ScriptState* scriptState) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
ExecutionContext* executionContext = scriptState->getExecutionContext();
SecurityOrigin* securityOrigin = executionContext->getSecurityOrigin();
if (securityOrigin->isUnique()) {
resolver->reject(DOMException::create(NotSupportedError));
return promise;
}
// IDL has: [SecureContext]
String errorMessage;
if (!executionContext->isSecureContext(errorMessage)) {
resolver->reject(DOMException::create(SecurityError, errorMessage));
return promise;
}
KURL storagePartition = KURL(KURL(), securityOrigin->toString());
Platform::current()->queryStorageUsageAndQuota(
storagePartition, WebStorageQuotaTypeTemporary,
new EstimateCallbacks(resolver));
return promise;
}
DEFINE_TRACE(StorageManager) {}
PermissionService* StorageManager::getPermissionService(
ExecutionContext* executionContext) {
if (!m_permissionService &&
connectToPermissionService(executionContext,
mojo::GetProxy(&m_permissionService)))
m_permissionService.set_connection_error_handler(convertToBaseCallback(
WTF::bind(&StorageManager::permissionServiceConnectionError,
wrapWeakPersistent(this))));
return m_permissionService.get();
}
void StorageManager::permissionServiceConnectionError() {
if (!Platform::current()) {
// TODO(rockot): Clean this up once renderer shutdown sequence is fixed.
return;
}
m_permissionService.reset();
}
void StorageManager::permissionRequestComplete(ScriptPromiseResolver* resolver,
PermissionStatus status) {
if (!resolver->getExecutionContext() ||
resolver->getExecutionContext()->isContextDestroyed())
return;
resolver->resolve(status == PermissionStatus::GRANTED);
}
} // namespace blink