ladybird/Userland/Libraries/LibWeb/HTML/SelectedFile.cpp
Andrew Kaster 6d4ba21832 LibIPC+Userland: Make IPC::File always own its file descriptor
Add factory functions to distinguish between when the owner of the File
wants to transfer ownership to the new IPC object (adopt) or to send a
copy of the same fd to the IPC peer (clone).

This behavior is more intuitive than the previous behavior. Previously,
an IPC::File would default to a shallow clone of the file descriptor,
only *actually* calling dup(2) for the fd when encoding or it into an
IPC MessageBuffer. Now the dup(2) for the fd is explicit in the clone_fd
factory function.
2024-04-19 06:34:07 -04:00

71 lines
2.0 KiB
C++

/*
* Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/LexicalPath.h>
#include <LibCore/File.h>
#include <LibIPC/Decoder.h>
#include <LibIPC/Encoder.h>
#include <LibWeb/HTML/SelectedFile.h>
namespace Web::HTML {
ErrorOr<SelectedFile> SelectedFile::from_file_path(ByteString const& file_path)
{
// https://html.spec.whatwg.org/multipage/input.html#file-upload-state-(type=file):concept-input-file-path
// Filenames must not contain path components, even in the case that a user has selected an entire directory
// hierarchy or multiple files with the same name from different directories.
auto name = LexicalPath::basename(file_path);
auto file = TRY(Core::File::open(file_path, Core::File::OpenMode::Read));
return SelectedFile { move(name), IPC::File::adopt_file(move(file)) };
}
SelectedFile::SelectedFile(ByteString name, ByteBuffer contents)
: m_name(move(name))
, m_file_or_contents(move(contents))
{
}
SelectedFile::SelectedFile(ByteString name, IPC::File file)
: m_name(move(name))
, m_file_or_contents(move(file))
{
}
ByteBuffer SelectedFile::take_contents()
{
VERIFY(m_file_or_contents.has<ByteBuffer>());
return move(m_file_or_contents.get<ByteBuffer>());
}
}
template<>
ErrorOr<void> IPC::encode(Encoder& encoder, Web::HTML::SelectedFile const& file)
{
TRY(encoder.encode(file.name()));
TRY(encoder.encode(file.file_or_contents()));
return {};
}
template<>
ErrorOr<Web::HTML::SelectedFile> IPC::decode(Decoder& decoder)
{
auto name = TRY(decoder.decode<ByteString>());
auto file_or_contents = TRY((decoder.decode<Variant<IPC::File, ByteBuffer>>()));
ByteBuffer contents;
if (file_or_contents.has<IPC::File>()) {
auto file = TRY(Core::File::adopt_fd(file_or_contents.get<IPC::File>().take_fd(), Core::File::OpenMode::Read));
contents = TRY(file->read_until_eof());
} else {
contents = move(file_or_contents.get<ByteBuffer>());
}
return Web::HTML::SelectedFile { move(name), move(contents) };
}