2022-09-19 06:06:23 -03:00
|
|
|
/*
|
2024-10-04 08:19:50 -03:00
|
|
|
* Copyright (c) 2022, Andreas Kling <andreas@ladybird.org>
|
2023-08-05 13:42:26 -03:00
|
|
|
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
|
2022-09-19 06:06:23 -03:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
|
*/
|
|
|
|
|
|
2026-03-24 09:43:26 -03:00
|
|
|
#include <AK/JsonObject.h>
|
|
|
|
|
#include <AK/JsonValue.h>
|
2022-10-05 10:23:41 -03:00
|
|
|
#include <AK/LexicalPath.h>
|
|
|
|
|
#include <AK/Platform.h>
|
2024-07-15 16:50:51 -03:00
|
|
|
#include <LibCore/Directory.h>
|
2024-01-30 13:16:17 -03:00
|
|
|
#include <LibCore/Environment.h>
|
2026-03-24 09:43:26 -03:00
|
|
|
#include <LibCore/File.h>
|
2025-06-10 20:20:46 -03:00
|
|
|
#include <LibCore/Process.h>
|
2024-07-15 16:50:51 -03:00
|
|
|
#include <LibCore/Resource.h>
|
2023-10-03 18:40:24 -03:00
|
|
|
#include <LibCore/ResourceImplementationFile.h>
|
2023-08-05 13:42:26 -03:00
|
|
|
#include <LibCore/System.h>
|
2023-03-21 12:35:30 -03:00
|
|
|
#include <LibFileSystem/FileSystem.h>
|
2026-05-20 13:37:49 -03:00
|
|
|
#include <LibWeb/HTML/SelectedFile.h>
|
2024-11-10 12:26:07 -03:00
|
|
|
#include <LibWebView/Utilities.h>
|
2022-10-05 10:23:41 -03:00
|
|
|
|
2024-02-23 21:02:17 -03:00
|
|
|
#define TOKENCAT(x, y) x##y
|
|
|
|
|
#define STRINGIFY(x) TOKENCAT(x, sv)
|
|
|
|
|
|
2024-11-10 12:26:07 -03:00
|
|
|
namespace WebView {
|
|
|
|
|
|
2024-02-23 21:02:17 -03:00
|
|
|
// This is expected to be set from the build scripts, if a packager desires
|
|
|
|
|
#if defined(LADYBIRD_LIBEXECDIR)
|
2024-11-10 12:26:07 -03:00
|
|
|
static constexpr auto libexec_path = STRINGIFY(LADYBIRD_LIBEXECDIR);
|
2024-02-23 21:02:17 -03:00
|
|
|
#else
|
2024-11-10 12:26:07 -03:00
|
|
|
static constexpr auto libexec_path = "libexec"sv;
|
2024-02-23 21:02:17 -03:00
|
|
|
#endif
|
|
|
|
|
|
2026-06-04 05:40:32 -03:00
|
|
|
ByteString& s_ladybird_resource_root = *new ByteString;
|
|
|
|
|
static auto& s_ladybird_binary_path = *new Optional<ByteString>;
|
2022-09-19 06:06:23 -03:00
|
|
|
|
2026-06-04 05:40:32 -03:00
|
|
|
Optional<ByteString>& s_mach_server_name = *new Optional<ByteString>;
|
2024-04-22 13:56:02 -03:00
|
|
|
|
|
|
|
|
Optional<ByteString const&> mach_server_name()
|
2024-04-04 17:13:14 -03:00
|
|
|
{
|
2024-04-22 13:56:02 -03:00
|
|
|
if (s_mach_server_name.has_value())
|
|
|
|
|
return *s_mach_server_name;
|
|
|
|
|
return {};
|
2024-04-04 17:13:14 -03:00
|
|
|
}
|
2024-04-22 13:56:02 -03:00
|
|
|
|
2024-04-04 17:13:14 -03:00
|
|
|
void set_mach_server_name(ByteString name)
|
|
|
|
|
{
|
|
|
|
|
s_mach_server_name = move(name);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-22 15:59:08 -03:00
|
|
|
ByteString mach_server_name_for_process(StringView process_name, pid_t pid)
|
|
|
|
|
{
|
|
|
|
|
return ByteString::formatted("org.ladybird.{}.helper.{}", process_name, pid);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-06 21:11:13 -03:00
|
|
|
static ErrorOr<ByteString> application_directory()
|
2022-09-19 06:06:23 -03:00
|
|
|
{
|
2025-06-06 21:11:13 -03:00
|
|
|
if (s_ladybird_binary_path.has_value())
|
|
|
|
|
return *s_ladybird_binary_path;
|
|
|
|
|
|
2023-08-05 13:42:26 -03:00
|
|
|
auto current_executable_path = TRY(Core::System::current_executable_path());
|
2024-02-21 22:27:05 -03:00
|
|
|
return LexicalPath::dirname(current_executable_path);
|
2023-03-13 18:30:31 -03:00
|
|
|
}
|
|
|
|
|
|
2024-02-23 21:02:17 -03:00
|
|
|
[[gnu::used]] static LexicalPath find_prefix(LexicalPath const& application_directory);
|
|
|
|
|
static LexicalPath find_prefix(LexicalPath const& application_directory)
|
|
|
|
|
{
|
|
|
|
|
if (application_directory.string().ends_with(libexec_path)) {
|
|
|
|
|
// Strip libexec_path if it's there
|
|
|
|
|
return LexicalPath(application_directory.string().substring_view(0, application_directory.string().length() - libexec_path.length()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise, we are in $prefix/bin
|
|
|
|
|
return application_directory.parent();
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-06 21:11:13 -03:00
|
|
|
void platform_init(Optional<ByteString> ladybird_binary_path)
|
2022-10-05 10:23:41 -03:00
|
|
|
{
|
2025-06-06 21:11:13 -03:00
|
|
|
s_ladybird_binary_path = move(ladybird_binary_path);
|
|
|
|
|
|
2024-07-21 11:50:14 -03:00
|
|
|
s_ladybird_resource_root = [] {
|
2024-01-30 13:16:17 -03:00
|
|
|
auto home = Core::Environment::get("XDG_CONFIG_HOME"sv)
|
|
|
|
|
.value_or_lazy_evaluated_optional([]() { return Core::Environment::get("HOME"sv); });
|
|
|
|
|
if (home.has_value()) {
|
2024-02-23 21:02:17 -03:00
|
|
|
auto home_lagom = ByteString::formatted("{}/.lagom", home);
|
|
|
|
|
if (FileSystem::is_directory(home_lagom))
|
|
|
|
|
return home_lagom;
|
|
|
|
|
}
|
2024-02-21 22:27:05 -03:00
|
|
|
auto app_dir = MUST(application_directory());
|
2023-09-02 12:30:21 -03:00
|
|
|
#ifdef AK_OS_MACOS
|
2023-03-26 12:53:32 -03:00
|
|
|
return LexicalPath(app_dir).parent().append("Resources"sv).string();
|
2023-09-02 12:30:21 -03:00
|
|
|
#else
|
2024-02-23 21:02:17 -03:00
|
|
|
return find_prefix(LexicalPath(app_dir)).append("share/Lagom"sv).string();
|
2022-10-05 10:23:41 -03:00
|
|
|
#endif
|
2023-09-02 12:30:21 -03:00
|
|
|
}();
|
2025-06-06 21:11:13 -03:00
|
|
|
|
2024-07-21 11:50:14 -03:00
|
|
|
Core::ResourceImplementation::install(make<Core::ResourceImplementationFile>(MUST(String::from_byte_string(s_ladybird_resource_root))));
|
2022-10-05 10:23:41 -03:00
|
|
|
}
|
2023-08-01 14:56:10 -03:00
|
|
|
|
2024-07-15 16:50:51 -03:00
|
|
|
void copy_default_config_files(StringView config_path)
|
|
|
|
|
{
|
|
|
|
|
MUST(Core::Directory::create(config_path, Core::Directory::CreateDirectories::Yes));
|
|
|
|
|
|
|
|
|
|
auto config_resources = MUST(Core::Resource::load_from_uri("resource://ladybird/default-config"sv));
|
|
|
|
|
|
|
|
|
|
config_resources->for_each_descendant_file([config_path](Core::Resource const& resource) -> IterationDecision {
|
|
|
|
|
auto file_path = ByteString::formatted("{}/{}", config_path, resource.filename());
|
|
|
|
|
|
|
|
|
|
if (Core::System::stat(file_path).is_error()) {
|
|
|
|
|
auto file = MUST(Core::File::open(file_path, Core::File::OpenMode::Write));
|
|
|
|
|
MUST(file->write_until_depleted(resource.data()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IterationDecision::Continue;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-21 22:27:05 -03:00
|
|
|
ErrorOr<Vector<ByteString>> get_paths_for_helper_process(StringView process_name)
|
2023-08-01 14:56:10 -03:00
|
|
|
{
|
2023-08-05 13:42:26 -03:00
|
|
|
auto application_path = TRY(application_directory());
|
2024-02-21 22:27:05 -03:00
|
|
|
Vector<ByteString> paths;
|
2023-08-01 14:56:10 -03:00
|
|
|
|
2024-12-21 08:19:39 -03:00
|
|
|
#if !defined(AK_OS_MACOS) && !defined(AK_OS_WINDOWS)
|
2024-02-23 21:02:17 -03:00
|
|
|
auto prefix = find_prefix(LexicalPath(application_path));
|
|
|
|
|
TRY(paths.try_append(LexicalPath::join(prefix.string(), libexec_path, process_name).string()));
|
|
|
|
|
TRY(paths.try_append(LexicalPath::join(prefix.string(), "bin"sv, process_name).string()));
|
|
|
|
|
#endif
|
2024-02-21 22:27:05 -03:00
|
|
|
TRY(paths.try_append(ByteString::formatted("{}/{}", application_path, process_name)));
|
|
|
|
|
TRY(paths.try_append(ByteString::formatted("./{}", process_name)));
|
2023-08-01 14:56:10 -03:00
|
|
|
// NOTE: Add platform-specific paths here
|
|
|
|
|
return paths;
|
|
|
|
|
}
|
2024-11-10 12:26:07 -03:00
|
|
|
|
2025-06-10 20:20:46 -03:00
|
|
|
ErrorOr<void> handle_attached_debugger()
|
|
|
|
|
{
|
|
|
|
|
#if defined(AK_OS_LINUX)
|
|
|
|
|
// Let's ignore SIGINT if we're being debugged because GDB incorrectly forwards the signal to us even when it's set
|
|
|
|
|
// to "nopass". See https://sourceware.org/bugzilla/show_bug.cgi?id=9425 for details.
|
|
|
|
|
if (TRY(Core::Process::is_being_debugged())) {
|
|
|
|
|
dbgln("Debugger is attached, ignoring SIGINT");
|
|
|
|
|
TRY(Core::System::signal(SIGINT, SIG_IGN));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-20 13:37:49 -03:00
|
|
|
ErrorOr<Web::HTML::SelectedFile> create_selected_file(ByteString const& file_path)
|
|
|
|
|
{
|
2026-05-20 13:39:37 -03:00
|
|
|
// FIXME: Implement the File and Directory Entries API.
|
|
|
|
|
// https://wicg.github.io/entries-api/
|
|
|
|
|
if (FileSystem::is_directory(file_path))
|
|
|
|
|
return Error::from_string_literal("Only files may currently be selected");
|
|
|
|
|
|
2026-05-20 13:37:49 -03:00
|
|
|
// 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 Web::HTML::SelectedFile { move(name), IPC::File::adopt_file(move(file)) };
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-24 09:43:26 -03:00
|
|
|
ErrorOr<JsonObject> read_json_file(ByteString const& path)
|
|
|
|
|
{
|
|
|
|
|
auto file = Core::File::open(path, Core::File::OpenMode::Read);
|
|
|
|
|
if (file.is_error()) {
|
|
|
|
|
if (file.error().is_errno() && file.error().code() == ENOENT)
|
|
|
|
|
return JsonObject {};
|
|
|
|
|
return file.release_error();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto contents = TRY(file.value()->read_until_eof());
|
|
|
|
|
auto json = TRY(JsonValue::from_string(contents));
|
|
|
|
|
|
|
|
|
|
if (!json.is_object())
|
|
|
|
|
return Error::from_string_literal("Expected parsed JSON value to be an object");
|
|
|
|
|
return move(json.as_object());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorOr<void> write_json_file(ByteString const& path, JsonValue const& value)
|
|
|
|
|
{
|
|
|
|
|
auto directory = LexicalPath { path }.parent();
|
|
|
|
|
TRY(Core::Directory::create(directory, Core::Directory::CreateDirectories::Yes));
|
|
|
|
|
|
|
|
|
|
auto file = TRY(Core::File::open(path, Core::File::OpenMode::Write));
|
|
|
|
|
TRY(file->write_until_depleted(value.serialized()));
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-10 12:26:07 -03:00
|
|
|
}
|