blob: b324551d29897fef5f97ad0aebe6e6422561b0d1 [file] [log] [blame]
// Copyright 2019 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 "content/browser/native_file_system/native_file_system_manager_impl.h"
#include "base/task/post_task.h"
#include "content/browser/native_file_system/file_system_chooser.h"
#include "content/browser/native_file_system/native_file_system_directory_handle_impl.h"
#include "content/browser/native_file_system/native_file_system_file_handle_impl.h"
#include "content/browser/native_file_system/native_file_system_transfer_token_impl.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "storage/browser/fileapi/file_system_context.h"
#include "storage/browser/fileapi/file_system_operation_runner.h"
#include "storage/common/fileapi/file_system_util.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom.h"
using blink::mojom::NativeFileSystemError;
namespace content {
NativeFileSystemManagerImpl::NativeFileSystemManagerImpl(
scoped_refptr<storage::FileSystemContext> context,
scoped_refptr<ChromeBlobStorageContext> blob_context)
: context_(std::move(context)), blob_context_(std::move(blob_context)) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(context_);
DCHECK(blob_context_);
}
NativeFileSystemManagerImpl::~NativeFileSystemManagerImpl() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
}
void NativeFileSystemManagerImpl::BindRequest(
const url::Origin& origin,
int process_id,
int frame_id,
blink::mojom::NativeFileSystemManagerRequest request) {
DCHECK(base::FeatureList::IsEnabled(blink::features::kNativeFileSystemAPI));
DCHECK_CURRENTLY_ON(BrowserThread::IO);
bindings_.AddBinding(this, std::move(request),
BindingContext(origin, process_id, frame_id));
}
void NativeFileSystemManagerImpl::GetSandboxedFileSystem(
GetSandboxedFileSystemCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
url::Origin origin = bindings_.dispatch_context().origin;
context()->OpenFileSystem(
origin.GetURL(), storage::kFileSystemTypeTemporary,
storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::BindOnce(&NativeFileSystemManagerImpl::DidOpenSandboxedFileSystem,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void NativeFileSystemManagerImpl::ChooseEntries(
blink::mojom::ChooseFileSystemEntryType type,
std::vector<blink::mojom::ChooseFileSystemEntryAcceptsOptionPtr> accepts,
bool include_accepts_all,
ChooseEntriesCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
const BindingContext& context = bindings_.dispatch_context();
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(
&FileSystemChooser::CreateAndShow, context.process_id,
context.frame_id, type, std::move(accepts), include_accepts_all,
base::BindOnce(&NativeFileSystemManagerImpl::DidChooseEntries,
weak_factory_.GetWeakPtr(), type, context.origin,
std::move(callback)),
base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO})));
}
blink::mojom::NativeFileSystemFileHandlePtr
NativeFileSystemManagerImpl::CreateFileHandle(
const storage::FileSystemURL& url) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(url.is_valid());
blink::mojom::NativeFileSystemFileHandlePtr result;
file_bindings_.AddBinding(
std::make_unique<NativeFileSystemFileHandleImpl>(this, url),
mojo::MakeRequest(&result));
return result;
}
blink::mojom::NativeFileSystemDirectoryHandlePtr
NativeFileSystemManagerImpl::CreateDirectoryHandle(
const storage::FileSystemURL& url) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(url.is_valid());
blink::mojom::NativeFileSystemDirectoryHandlePtr result;
directory_bindings_.AddBinding(
std::make_unique<NativeFileSystemDirectoryHandleImpl>(this, url),
mojo::MakeRequest(&result));
return result;
}
void NativeFileSystemManagerImpl::CreateTransferToken(
const NativeFileSystemFileHandleImpl& file,
blink::mojom::NativeFileSystemTransferTokenRequest request) {
return CreateTransferTokenImpl(file.url(),
/*is_directory=*/false, std::move(request));
}
void NativeFileSystemManagerImpl::CreateTransferToken(
const NativeFileSystemDirectoryHandleImpl& directory,
blink::mojom::NativeFileSystemTransferTokenRequest request) {
return CreateTransferTokenImpl(directory.url(),
/*is_directory=*/true, std::move(request));
}
void NativeFileSystemManagerImpl::ResolveTransferToken(
blink::mojom::NativeFileSystemTransferTokenPtr token,
ResolvedTokenCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto* raw_token = token.get();
raw_token->GetInternalID(mojo::WrapCallbackWithDefaultInvokeIfNotRun(
base::BindOnce(&NativeFileSystemManagerImpl::DoResolveTransferToken,
weak_factory_.GetWeakPtr(), std::move(token),
std::move(callback)),
base::UnguessableToken()));
}
storage::FileSystemOperationRunner*
NativeFileSystemManagerImpl::operation_runner() {
if (!operation_runner_)
operation_runner_ = context()->CreateFileSystemOperationRunner();
return operation_runner_.get();
}
void NativeFileSystemManagerImpl::DidOpenSandboxedFileSystem(
GetSandboxedFileSystemCallback callback,
const GURL& root,
const std::string& filesystem_name,
base::File::Error result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (result != base::File::FILE_OK) {
std::move(callback).Run(NativeFileSystemError::New(result), nullptr);
return;
}
std::move(callback).Run(NativeFileSystemError::New(base::File::FILE_OK),
CreateDirectoryHandle(context()->CrackURL(root)));
}
void NativeFileSystemManagerImpl::DidChooseEntries(
blink::mojom::ChooseFileSystemEntryType type,
const url::Origin& origin,
ChooseEntriesCallback callback,
blink::mojom::NativeFileSystemErrorPtr result,
std::vector<FileSystemChooser::IsolatedFileSystemEntry> entries) {
std::vector<blink::mojom::NativeFileSystemEntryPtr> result_entries;
if (result->error_code != base::File::FILE_OK) {
std::move(callback).Run(std::move(result), std::move(result_entries));
return;
}
result_entries.reserve(entries.size());
for (const auto& entry : entries) {
auto url = context()->CreateCrackedFileSystemURL(
origin.GetURL(), storage::kFileSystemTypeIsolated,
entry.isolated_file_path);
std::string name = storage::FilePathToString(
storage::VirtualPath::BaseName(entry.isolated_file_path));
// TODO(https://crbug.com/955185): Pass file system ID to the handle
// implementations so they can properly ref and unref the filesystem.
// Right now the isolated file system will just be leaked and never freed.
if (type == blink::mojom::ChooseFileSystemEntryType::kOpenDirectory) {
result_entries.push_back(blink::mojom::NativeFileSystemEntry::New(
blink::mojom::NativeFileSystemHandle::NewDirectory(
CreateDirectoryHandle(url).PassInterface()),
name));
} else {
result_entries.push_back(blink::mojom::NativeFileSystemEntry::New(
blink::mojom::NativeFileSystemHandle::NewFile(
CreateFileHandle(url).PassInterface()),
name));
}
}
std::move(callback).Run(std::move(result), std::move(result_entries));
}
void NativeFileSystemManagerImpl::CreateTransferTokenImpl(
const storage::FileSystemURL& url,
bool is_directory,
blink::mojom::NativeFileSystemTransferTokenRequest request) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto token_impl = std::make_unique<NativeFileSystemTransferTokenImpl>(
url, is_directory
? NativeFileSystemTransferTokenImpl::HandleType::kDirectory
: NativeFileSystemTransferTokenImpl::HandleType::kFile);
auto token = token_impl->token();
blink::mojom::NativeFileSystemTransferTokenPtr result;
auto emplace_result = transfer_tokens_.emplace(
std::piecewise_construct, std::forward_as_tuple(token),
std::forward_as_tuple(std::move(token_impl), std::move(request)));
DCHECK(emplace_result.second);
emplace_result.first->second.set_connection_error_handler(base::BindOnce(
&NativeFileSystemManagerImpl::TransferTokenConnectionErrorHandler,
base::Unretained(this), token));
}
void NativeFileSystemManagerImpl::TransferTokenConnectionErrorHandler(
const base::UnguessableToken& token) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
size_t count_removed = transfer_tokens_.erase(token);
DCHECK_EQ(1u, count_removed);
}
void NativeFileSystemManagerImpl::DoResolveTransferToken(
blink::mojom::NativeFileSystemTransferTokenPtr,
ResolvedTokenCallback callback,
const base::UnguessableToken& token) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto it = transfer_tokens_.find(token);
if (it == transfer_tokens_.end()) {
std::move(callback).Run(nullptr);
} else {
std::move(callback).Run(
static_cast<NativeFileSystemTransferTokenImpl*>(it->second.impl()));
}
}
} // namespace content