blob: ab56273d270eeee2b62da404fa7d0204aae538a5 [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 "core/dom/ExecutionContext.h"
#include "core/frame/Frame.h"
#include "core/frame/LocalFrame.h"
#include "modules/permissions/PermissionUtils.h"
#include "modules/quota/StorageEstimate.h"
#include "platform/StorageQuotaCallbacks.h"
#include "platform/wtf/Assertions.h"
#include "platform/wtf/Functional.h"
#include "public/platform/Platform.h"
#include "public/platform/WebStorageQuotaError.h"
namespace blink {
using mojom::blink::PermissionName;
using mojom::blink::PermissionService;
using mojom::blink::PermissionStatus;
namespace {
const char kUniqueOriginErrorMessage[] =
"The operation is not supported in this context.";
class EstimateCallbacks final : public StorageQuotaCallbacks {
WTF_MAKE_NONCOPYABLE(EstimateCallbacks);
public:
explicit EstimateCallbacks(ScriptPromiseResolver* resolver)
: resolver_(resolver) {}
~EstimateCallbacks() override {}
void DidQueryStorageUsageAndQuota(
unsigned long long usage_in_bytes,
unsigned long long quota_in_bytes) override {
StorageEstimate estimate;
estimate.setUsage(usage_in_bytes);
estimate.setQuota(quota_in_bytes);
resolver_->Resolve(estimate);
}
void DidFail(WebStorageQuotaError error) override {
resolver_->Reject(DOMException::Create(static_cast<ExceptionCode>(error)));
}
virtual void Trace(blink::Visitor* visitor) {
visitor->Trace(resolver_);
StorageQuotaCallbacks::Trace(visitor);
}
private:
Member<ScriptPromiseResolver> resolver_;
};
} // namespace
ScriptPromise StorageManager::persist(ScriptState* script_state) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
ExecutionContext* execution_context = ExecutionContext::From(script_state);
DCHECK(execution_context->IsSecureContext()); // [SecureContext] in IDL
SecurityOrigin* security_origin = execution_context->GetSecurityOrigin();
if (security_origin->IsUnique()) {
resolver->Reject(V8ThrowException::CreateTypeError(
script_state->GetIsolate(), kUniqueOriginErrorMessage));
return promise;
}
DCHECK(execution_context->IsDocument());
Document* doc = ToDocumentOrNull(execution_context);
GetPermissionService(ExecutionContext::From(script_state))
.RequestPermission(
CreatePermissionDescriptor(PermissionName::DURABLE_STORAGE),
ExecutionContext::From(script_state)->GetSecurityOrigin(),
Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr),
ConvertToBaseCallback(
WTF::Bind(&StorageManager::PermissionRequestComplete,
WrapPersistent(this), WrapPersistent(resolver))));
return promise;
}
ScriptPromise StorageManager::persisted(ScriptState* script_state) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
ExecutionContext* execution_context = ExecutionContext::From(script_state);
DCHECK(execution_context->IsSecureContext()); // [SecureContext] in IDL
SecurityOrigin* security_origin = execution_context->GetSecurityOrigin();
if (security_origin->IsUnique()) {
resolver->Reject(V8ThrowException::CreateTypeError(
script_state->GetIsolate(), kUniqueOriginErrorMessage));
return promise;
}
GetPermissionService(ExecutionContext::From(script_state))
.HasPermission(
CreatePermissionDescriptor(PermissionName::DURABLE_STORAGE),
ExecutionContext::From(script_state)->GetSecurityOrigin(),
ConvertToBaseCallback(
WTF::Bind(&StorageManager::PermissionRequestComplete,
WrapPersistent(this), WrapPersistent(resolver))));
return promise;
}
ScriptPromise StorageManager::estimate(ScriptState* script_state) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
ExecutionContext* execution_context = ExecutionContext::From(script_state);
DCHECK(execution_context->IsSecureContext()); // [SecureContext] in IDL
SecurityOrigin* security_origin = execution_context->GetSecurityOrigin();
if (security_origin->IsUnique()) {
resolver->Reject(V8ThrowException::CreateTypeError(
script_state->GetIsolate(), kUniqueOriginErrorMessage));
return promise;
}
KURL storage_partition = KURL(NullURL(), security_origin->ToString());
Platform::Current()->QueryStorageUsageAndQuota(
storage_partition, kWebStorageQuotaTypeTemporary,
new EstimateCallbacks(resolver));
return promise;
}
PermissionService& StorageManager::GetPermissionService(
ExecutionContext* execution_context) {
if (!permission_service_) {
ConnectToPermissionService(execution_context,
mojo::MakeRequest(&permission_service_));
permission_service_.set_connection_error_handler(ConvertToBaseCallback(
WTF::Bind(&StorageManager::PermissionServiceConnectionError,
WrapWeakPersistent(this))));
}
return *permission_service_;
}
void StorageManager::PermissionServiceConnectionError() {
permission_service_.reset();
}
void StorageManager::PermissionRequestComplete(ScriptPromiseResolver* resolver,
PermissionStatus status) {
if (!resolver->GetExecutionContext() ||
resolver->GetExecutionContext()->IsContextDestroyed())
return;
resolver->Resolve(status == PermissionStatus::GRANTED);
}
STATIC_ASSERT_ENUM(kWebStorageQuotaErrorNotSupported, kNotSupportedError);
STATIC_ASSERT_ENUM(kWebStorageQuotaErrorInvalidModification,
kInvalidModificationError);
STATIC_ASSERT_ENUM(kWebStorageQuotaErrorInvalidAccess, kInvalidAccessError);
STATIC_ASSERT_ENUM(kWebStorageQuotaErrorAbort, kAbortError);
} // namespace blink