| /* |
| * Copyright (C) 2021 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "WorkerFileSystemStorageConnection.h" |
| |
| #include "FileSystemHandleCloseScope.h" |
| #include "FileSystemSyncAccessHandle.h" |
| #include "WorkerGlobalScope.h" |
| #include "WorkerLoaderProxy.h" |
| #include "WorkerThread.h" |
| #include <wtf/Scope.h> |
| |
| namespace WebCore { |
| |
| Ref<WorkerFileSystemStorageConnection> WorkerFileSystemStorageConnection::create(WorkerGlobalScope& scope, Ref<FileSystemStorageConnection>&& mainThreadConnection) |
| { |
| return adoptRef(*new WorkerFileSystemStorageConnection(scope, WTFMove(mainThreadConnection))); |
| } |
| |
| WorkerFileSystemStorageConnection::WorkerFileSystemStorageConnection(WorkerGlobalScope& scope, Ref<FileSystemStorageConnection>&& connection) |
| : m_scope(scope) |
| , m_mainThreadConnection(WTFMove(connection)) |
| { |
| } |
| |
| WorkerFileSystemStorageConnection::~WorkerFileSystemStorageConnection() |
| { |
| if (m_mainThreadConnection) |
| callOnMainThread([mainThreadConenction = WTFMove(m_mainThreadConnection)]() { }); |
| } |
| |
| void WorkerFileSystemStorageConnection::connectionClosed() |
| { |
| for (auto handle : m_syncAccessHandles.values()) |
| handle->invalidate(); |
| |
| scopeClosed(); |
| } |
| |
| void WorkerFileSystemStorageConnection::scopeClosed() |
| { |
| auto sameEntryCallbacks = std::exchange(m_sameEntryCallbacks, { }); |
| for (auto& callback : sameEntryCallbacks.values()) |
| callback(Exception { InvalidStateError }); |
| |
| auto getHandleCallbacks = std::exchange(m_getHandleCallbacks, { }); |
| for (auto& callback : getHandleCallbacks.values()) |
| callback(Exception { InvalidStateError }); |
| |
| auto removeEntryCallbacks = std::exchange(m_voidCallbacks, { }); |
| for (auto& callback : removeEntryCallbacks.values()) |
| callback(Exception { InvalidStateError }); |
| |
| auto resolveCallbacks = std::exchange(m_resolveCallbacks, { }); |
| for (auto& callback : resolveCallbacks.values()) |
| callback(Exception { InvalidStateError }); |
| |
| auto stringCallbacks = std::exchange(m_stringCallbacks, { }); |
| for (auto& callback : stringCallbacks.values()) |
| callback(Exception { InvalidStateError }); |
| |
| m_scope = nullptr; |
| } |
| |
| void WorkerFileSystemStorageConnection::closeHandle(FileSystemHandleIdentifier identifier) |
| { |
| callOnMainThread([mainThreadConnection = m_mainThreadConnection, identifier]() mutable { |
| if (mainThreadConnection) |
| mainThreadConnection->closeHandle(identifier); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::isSameEntry(FileSystemHandleIdentifier identifier, FileSystemHandleIdentifier otherIdentifier, FileSystemStorageConnection::SameEntryCallback&& callback) |
| { |
| if (!m_scope) |
| return callback(Exception { InvalidStateError }); |
| |
| auto callbackIdentifier = CallbackIdentifier::generateThreadSafe(); |
| m_sameEntryCallbacks.add(callbackIdentifier, WTFMove(callback)); |
| |
| callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, otherIdentifier]() mutable { |
| auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto result) mutable { |
| workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(result)] (auto& scope) mutable { |
| if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection()) |
| connection->didIsSameEntry(callbackIdentifier, WTFMove(result)); |
| }, WorkerRunLoop::defaultMode()); |
| }; |
| |
| mainThreadConnection->isSameEntry(identifier, otherIdentifier, WTFMove(mainThreadCallback)); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::didIsSameEntry(CallbackIdentifier callbackIdentifier, ExceptionOr<bool>&& result) |
| { |
| if (auto callback = m_sameEntryCallbacks.take(callbackIdentifier)) |
| callback(WTFMove(result)); |
| } |
| |
| void WorkerFileSystemStorageConnection::getFileHandle(FileSystemHandleIdentifier identifier, const String& name, bool createIfNecessary, FileSystemStorageConnection::GetHandleCallback&& callback) |
| { |
| if (!m_scope) |
| return callback(Exception { InvalidStateError }); |
| |
| auto callbackIdentifier = CallbackIdentifier::generateThreadSafe(); |
| m_getHandleCallbacks.add(callbackIdentifier, WTFMove(callback)); |
| |
| callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, name = name.isolatedCopy(), createIfNecessary]() mutable { |
| auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto result) mutable { |
| workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(result)] (auto& scope) mutable { |
| if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection()) |
| connection->didGetHandle(callbackIdentifier, WTFMove(result)); |
| }, WorkerRunLoop::defaultMode()); |
| }; |
| |
| mainThreadConnection->getFileHandle(identifier, name, createIfNecessary, WTFMove(mainThreadCallback)); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::getDirectoryHandle(FileSystemHandleIdentifier identifier, const String& name, bool createIfNecessary, FileSystemStorageConnection::GetHandleCallback&& callback) |
| { |
| if (!m_scope) |
| return callback(Exception { InvalidStateError }); |
| |
| auto callbackIdentifier = CallbackIdentifier::generateThreadSafe(); |
| m_getHandleCallbacks.add(callbackIdentifier, WTFMove(callback)); |
| |
| callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, name = name.isolatedCopy(), createIfNecessary]() mutable { |
| auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto result) mutable { |
| workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(result)] (auto& scope) mutable { |
| if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection()) |
| connection->didGetHandle(callbackIdentifier, WTFMove(result)); |
| }, WorkerRunLoop::defaultMode()); |
| }; |
| |
| mainThreadConnection->getDirectoryHandle(identifier, name, createIfNecessary, WTFMove(mainThreadCallback)); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::didGetHandle(CallbackIdentifier callbackIdentifier, ExceptionOr<Ref<FileSystemHandleCloseScope>>&& result) |
| { |
| if (auto callback = m_getHandleCallbacks.take(callbackIdentifier)) |
| callback(WTFMove(result)); |
| } |
| |
| void WorkerFileSystemStorageConnection::removeEntry(FileSystemHandleIdentifier identifier, const String& name, bool deleteRecursively, FileSystemStorageConnection::VoidCallback&& callback) |
| { |
| if (!m_scope) |
| return callback(Exception { InvalidStateError }); |
| |
| auto callbackIdentifier = CallbackIdentifier::generateThreadSafe(); |
| m_voidCallbacks.add(callbackIdentifier, WTFMove(callback)); |
| |
| callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, name = name.isolatedCopy(), deleteRecursively]() mutable { |
| auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto result) mutable { |
| workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(result)] (auto& scope) mutable { |
| if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection()) |
| connection->completeVoidCallback(callbackIdentifier, WTFMove(result)); |
| }, WorkerRunLoop::defaultMode()); |
| }; |
| |
| mainThreadConnection->removeEntry(identifier, name, deleteRecursively, WTFMove(mainThreadCallback)); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::resolve(FileSystemHandleIdentifier identifier, FileSystemHandleIdentifier otherIdentifier, FileSystemStorageConnection::ResolveCallback&& callback) |
| { |
| if (!m_scope) |
| return callback(Exception { InvalidStateError }); |
| |
| auto callbackIdentifier = CallbackIdentifier::generateThreadSafe(); |
| m_resolveCallbacks.add(callbackIdentifier, WTFMove(callback)); |
| |
| callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, otherIdentifier]() mutable { |
| auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto result) mutable { |
| workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(result)] (auto& scope) mutable { |
| if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection()) |
| connection->didResolve(callbackIdentifier, WTFMove(result)); |
| }, WorkerRunLoop::defaultMode()); |
| }; |
| |
| mainThreadConnection->resolve(identifier, otherIdentifier, WTFMove(mainThreadCallback)); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::didResolve(CallbackIdentifier callbackIdentifier, ExceptionOr<Vector<String>>&& result) |
| { |
| if (auto callback = m_resolveCallbacks.take(callbackIdentifier)) |
| callback(WTFMove(result)); |
| } |
| |
| void WorkerFileSystemStorageConnection::getFile(FileSystemHandleIdentifier identifier, StringCallback&& callback) |
| { |
| if (!m_scope) |
| return callback(Exception { InvalidStateError }); |
| |
| auto callbackIdentifier = CallbackIdentifier::generateThreadSafe(); |
| m_stringCallbacks.add(callbackIdentifier, WTFMove(callback)); |
| |
| callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier]() mutable { |
| auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto result) mutable { |
| workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(result)] (auto& scope) mutable { |
| if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection()) |
| connection->completeStringCallback(callbackIdentifier, WTFMove(result)); |
| }, WorkerRunLoop::defaultMode()); |
| }; |
| |
| mainThreadConnection->getFile(identifier, WTFMove(mainThreadCallback)); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::completeStringCallback(CallbackIdentifier callbackIdentifier, ExceptionOr<String>&& result) |
| { |
| if (auto callback = m_stringCallbacks.take(callbackIdentifier)) |
| callback(WTFMove(result)); |
| } |
| |
| void WorkerFileSystemStorageConnection::didCreateSyncAccessHandle(CallbackIdentifier callbackIdentifier, ExceptionOr<std::pair<FileSystemSyncAccessHandleIdentifier, FileHandle>>&& result) |
| { |
| if (auto callback = m_getAccessHandlCallbacks.take(callbackIdentifier)) |
| callback(WTFMove(result)); |
| } |
| |
| void WorkerFileSystemStorageConnection::completeVoidCallback(CallbackIdentifier callbackIdentifier, ExceptionOr<void>&& result) |
| { |
| if (auto callback = m_voidCallbacks.take(callbackIdentifier)) |
| callback(WTFMove(result)); |
| } |
| |
| void WorkerFileSystemStorageConnection::createSyncAccessHandle(FileSystemHandleIdentifier identifier, FileSystemStorageConnection::GetAccessHandleCallback&& callback) |
| { |
| if (!m_scope) |
| return callback(Exception { InvalidStateError }); |
| |
| auto callbackIdentifier = CallbackIdentifier::generateThreadSafe(); |
| m_getAccessHandlCallbacks.add(callbackIdentifier, WTFMove(callback)); |
| |
| callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier]() mutable { |
| auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto result) mutable { |
| if (result.hasException()) |
| result = crossThreadCopy(result.exception()); |
| workerThread->runLoop().postTaskForMode([callbackIdentifier, result = WTFMove(result)] (auto& scope) mutable { |
| if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection()) |
| connection->didCreateSyncAccessHandle(callbackIdentifier, WTFMove(result)); |
| }, WorkerRunLoop::defaultMode()); |
| }; |
| |
| mainThreadConnection->createSyncAccessHandle(identifier, WTFMove(mainThreadCallback)); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::closeSyncAccessHandle(FileSystemHandleIdentifier identifier, FileSystemSyncAccessHandleIdentifier accessHandleIdentifier, FileSystemStorageConnection::VoidCallback&& callback) |
| { |
| if (!m_scope) |
| return callback(Exception { InvalidStateError }); |
| |
| auto callbackIdentifier = CallbackIdentifier::generateThreadSafe(); |
| m_voidCallbacks.add(callbackIdentifier, WTFMove(callback)); |
| |
| callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, accessHandleIdentifier]() mutable { |
| auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto result) mutable { |
| workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(result)] (auto& scope) mutable { |
| if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection()) |
| connection->completeVoidCallback(callbackIdentifier, WTFMove(result)); |
| }, WorkerRunLoop::defaultMode()); |
| }; |
| |
| mainThreadConnection->closeSyncAccessHandle(identifier, accessHandleIdentifier, WTFMove(mainThreadCallback)); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::registerSyncAccessHandle(FileSystemSyncAccessHandleIdentifier identifier, FileSystemSyncAccessHandle& handle) |
| { |
| if (!m_scope) |
| return; |
| |
| m_syncAccessHandles.add(identifier, WeakPtr { handle }); |
| callOnMainThread([identifier, contextIdentifier = m_scope->identifier(), mainThreadConnection = m_mainThreadConnection]() mutable { |
| mainThreadConnection->registerSyncAccessHandle(identifier, contextIdentifier); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::unregisterSyncAccessHandle(FileSystemSyncAccessHandleIdentifier identifier) |
| { |
| m_syncAccessHandles.remove(identifier); |
| callOnMainThread([identifier, mainThreadConnection = m_mainThreadConnection]() mutable { |
| mainThreadConnection->unregisterSyncAccessHandle(identifier); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::invalidateAccessHandle(WebCore::FileSystemSyncAccessHandleIdentifier identifier) |
| { |
| if (auto handle = m_syncAccessHandles.get(identifier)) |
| handle->invalidate(); |
| } |
| |
| void WorkerFileSystemStorageConnection::getHandleNames(FileSystemHandleIdentifier identifier, GetHandleNamesCallback&& callback) |
| { |
| if (!m_scope) |
| return callback(Exception { InvalidStateError }); |
| |
| auto callbackIdentifier = CallbackIdentifier::generateThreadSafe(); |
| m_getHandleNamesCallbacks.add(callbackIdentifier, WTFMove(callback)); |
| |
| callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier]() mutable { |
| auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto result) mutable { |
| workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(result)] (auto& scope) mutable { |
| if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection()) |
| connection->didGetHandleNames(callbackIdentifier, WTFMove(result)); |
| }, WorkerRunLoop::defaultMode()); |
| }; |
| |
| mainThreadConnection->getHandleNames(identifier, WTFMove(mainThreadCallback)); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::didGetHandleNames(CallbackIdentifier callbackIdentifier, ExceptionOr<Vector<String>>&& result) |
| { |
| if (auto callback = m_getHandleNamesCallbacks.take(callbackIdentifier)) |
| callback(WTFMove(result)); |
| } |
| |
| void WorkerFileSystemStorageConnection::getHandle(FileSystemHandleIdentifier identifier, const String& name, GetHandleCallback&& callback) |
| { |
| if (!m_scope) |
| return callback(Exception { InvalidStateError }); |
| |
| auto callbackIdentifier = CallbackIdentifier::generateThreadSafe(); |
| m_getHandleCallbacks.add(callbackIdentifier, WTFMove(callback)); |
| |
| callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, name = name.isolatedCopy()]() mutable { |
| auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto result) mutable { |
| workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(result)] (auto& scope) mutable { |
| if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection()) |
| connection->didGetHandle(callbackIdentifier, WTFMove(result)); |
| }, WorkerRunLoop::defaultMode()); |
| }; |
| |
| mainThreadConnection->getHandle(identifier, name, WTFMove(mainThreadCallback)); |
| }); |
| } |
| |
| void WorkerFileSystemStorageConnection::move(FileSystemHandleIdentifier identifier, FileSystemHandleIdentifier destinationIdentifier, const String& newName, VoidCallback&& callback) |
| { |
| if (!m_scope) |
| return callback(Exception { InvalidStateError }); |
| |
| auto callbackIdentifier = CallbackIdentifier::generateThreadSafe(); |
| m_voidCallbacks.add(callbackIdentifier, WTFMove(callback)); |
| |
| callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, destinationIdentifier, name = crossThreadCopy(newName)]() mutable { |
| auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto result) mutable { |
| workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(result)] (auto& scope) mutable { |
| if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection()) |
| connection->completeVoidCallback(callbackIdentifier, WTFMove(result)); |
| }, WorkerRunLoop::defaultMode()); |
| }; |
| |
| mainThreadConnection->move(identifier, destinationIdentifier, name, WTFMove(mainThreadCallback)); |
| }); |
| } |
| |
| } // namespace WebCore |