diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/modules/native_io/native_io_manager.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/modules/native_io/native_io_manager.cc | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_manager.cc b/chromium/third_party/blink/renderer/modules/native_io/native_io_manager.cc new file mode 100644 index 00000000000..0fad4c7a7a6 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_manager.cc @@ -0,0 +1,269 @@ +// Copyright 2020 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 "third_party/blink/renderer/modules/native_io/native_io_manager.h" + +#include <algorithm> +#include <utility> + +#include "base/files/file.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "third_party/blink/public/mojom/native_io/native_io.mojom-blink.h" +#include "third_party/blink/public/platform/task_type.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h" +#include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" +#include "third_party/blink/renderer/modules/native_io/native_io_file.h" +#include "third_party/blink/renderer/modules/native_io/native_io_file_sync.h" +#include "third_party/blink/renderer/platform/bindings/exception_code.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/heap/heap.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" + +namespace blink { + +namespace { + +bool IsValidNativeIONameCharacter(int name_char) { + return (name_char >= 'a' && name_char <= 'z') || + (name_char >= '0' && name_char <= '9') || name_char == '_'; +} + +bool IsValidNativeIOName(const String& name) { + if (name.IsEmpty()) + return false; + + if (name.Is8Bit()) { + return std::all_of(name.Span8().begin(), name.Span8().end(), + &IsValidNativeIONameCharacter); + } + return std::all_of(name.Span16().begin(), name.Span16().end(), + &IsValidNativeIONameCharacter); +} + +void OnOpenResult(ScriptPromiseResolver* resolver, + mojo::Remote<mojom::blink::NativeIOFileHost> backend_file, + base::File backing_file) { + ScriptState* script_state = resolver->GetScriptState(); + if (!script_state->ContextIsValid()) + return; + ScriptState::Scope scope(script_state); + + if (!backing_file.IsValid()) { + resolver->Reject(V8ThrowDOMException::CreateOrEmpty( + script_state->GetIsolate(), DOMExceptionCode::kUnknownError, + "open() failed")); + return; + } + + NativeIOFile* file = MakeGarbageCollected<NativeIOFile>( + std::move(backing_file), std::move(backend_file), + ExecutionContext::From(script_state)); + resolver->Resolve(file); +} + +void OnDeleteResult(ScriptPromiseResolver* resolver, bool backend_success) { + ScriptState* script_state = resolver->GetScriptState(); + if (!script_state->ContextIsValid()) + return; + ScriptState::Scope scope(script_state); + + if (!backend_success) { + resolver->Reject(V8ThrowDOMException::CreateOrEmpty( + script_state->GetIsolate(), DOMExceptionCode::kUnknownError, + "delete() failed")); + return; + } + + resolver->Resolve(); +} + +void OnGetAllResult(ScriptPromiseResolver* resolver, + bool backend_success, + const Vector<String>& file_names) { + ScriptState* script_state = resolver->GetScriptState(); + if (!script_state->ContextIsValid()) + return; + ScriptState::Scope scope(script_state); + + if (!backend_success) { + resolver->Reject(V8ThrowDOMException::CreateOrEmpty( + script_state->GetIsolate(), DOMExceptionCode::kUnknownError, + "getAll() failed")); + return; + } + + resolver->Resolve(file_names); +} + +} // namespace + +NativeIOManager::NativeIOManager( + ExecutionContext* execution_context, + mojo::Remote<mojom::blink::NativeIOHost> backend) + : ExecutionContextLifecycleObserver(execution_context), + // TODO(pwnall): Get a dedicated queue when the specification matures. + receiver_task_runner_( + execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)), + backend_(std::move(backend)) { + backend_.set_disconnect_handler(WTF::Bind( + &NativeIOManager::OnBackendDisconnect, WrapWeakPersistent(this))); +} + +NativeIOManager::~NativeIOManager() = default; + +ScriptPromise NativeIOManager::open(ScriptState* script_state, + String name, + ExceptionState& exception_state) { + if (!IsValidNativeIOName(name)) { + exception_state.ThrowTypeError("Invalid file name"); + return ScriptPromise(); + } + + if (!backend_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "NativeIOHost backend went away"); + return ScriptPromise(); + } + + ExecutionContext* execution_context = GetExecutionContext(); + DCHECK(execution_context); + + mojo::Remote<mojom::blink::NativeIOFileHost> backend_file; + mojo::PendingReceiver<mojom::blink::NativeIOFileHost> backend_file_receiver = + backend_file.BindNewPipeAndPassReceiver(receiver_task_runner_); + + auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); + backend_->OpenFile(name, std::move(backend_file_receiver), + WTF::Bind(&OnOpenResult, WrapPersistent(resolver), + std::move(backend_file))); + return resolver->Promise(); +} + +ScriptPromise NativeIOManager::Delete(ScriptState* script_state, + String name, + ExceptionState& exception_state) { + if (!IsValidNativeIOName(name)) { + exception_state.ThrowTypeError("Invalid file name"); + return ScriptPromise(); + } + + if (!backend_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "NativeIOHost backend went away"); + return ScriptPromise(); + } + + auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); + backend_->DeleteFile(name, + WTF::Bind(&OnDeleteResult, WrapPersistent(resolver))); + return resolver->Promise(); +} + +ScriptPromise NativeIOManager::getAll(ScriptState* script_state, + ExceptionState& exception_state) { + if (!backend_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "NativeIOHost backend went away"); + return ScriptPromise(); + } + + auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); + backend_->GetAllFileNames( + WTF::Bind(&OnGetAllResult, WrapPersistent(resolver))); + return resolver->Promise(); +} + +NativeIOFileSync* NativeIOManager::openSync(String name, + ExceptionState& exception_state) { + if (!IsValidNativeIOName(name)) { + exception_state.ThrowTypeError("Invalid file name"); + return nullptr; + } + + if (!backend_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "NativeIOHost backend went away"); + return nullptr; + } + + ExecutionContext* execution_context = GetExecutionContext(); + DCHECK(execution_context); + + mojo::Remote<mojom::blink::NativeIOFileHost> backend_file; + mojo::PendingReceiver<mojom::blink::NativeIOFileHost> backend_file_receiver = + backend_file.BindNewPipeAndPassReceiver(receiver_task_runner_); + + base::File backing_file; + bool call_succeeded = + backend_->OpenFile(name, std::move(backend_file_receiver), &backing_file); + + if (!call_succeeded || !backing_file.IsValid()) { + exception_state.ThrowDOMException(DOMExceptionCode::kUnknownError, + "openSync() failed"); + return nullptr; + } + + return MakeGarbageCollected<NativeIOFileSync>( + std::move(backing_file), std::move(backend_file), execution_context); +} + +void NativeIOManager::deleteSync(String name, ExceptionState& exception_state) { + if (!IsValidNativeIOName(name)) { + exception_state.ThrowTypeError("Invalid file name"); + return; + } + + if (!backend_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "NativeIOHost backend went away"); + return; + } + + bool backend_success = false; + bool call_succeeded = backend_->DeleteFile(name, &backend_success); + + if (!call_succeeded || !backend_success) { + exception_state.ThrowDOMException(DOMExceptionCode::kUnknownError, + "deleteSync() failed"); + } +} + +Vector<String> NativeIOManager::getAllSync(ExceptionState& exception_state) { + Vector<String> result; + if (!backend_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "NativeIOHost backend went away"); + return result; + } + + bool backend_success = false; + bool call_succeeded = backend_->GetAllFileNames(&backend_success, &result); + + if (!call_succeeded || !backend_success) { + exception_state.ThrowDOMException(DOMExceptionCode::kUnknownError, + "getAllSync() failed"); + } + return result; +} + +void NativeIOManager::Trace(Visitor* visitor) { + ScriptWrappable::Trace(visitor); + ExecutionContextLifecycleObserver::Trace(visitor); +} + +void NativeIOManager::ContextDestroyed() { + backend_.reset(); +} + +void NativeIOManager::OnBackendDisconnect() { + backend_.reset(); +} + +} // namespace blink |