From eafdb06d87cb414e1c5071a40ec44914893b8baf Mon Sep 17 00:00:00 2001 From: Bastiaan van der Plaat Date: Sun, 13 Aug 2023 22:35:35 +0200 Subject: [PATCH] LibWeb: Add directory entries page when visiting a local directory --- Base/res/html/directory.html | 51 ++++++++++++++++ Ladybird/WebContent/main.cpp | 1 + .../Userland/Libraries/LibWeb/Loader/BUILD.gn | 1 + Userland/Libraries/LibWeb/CMakeLists.txt | 1 + .../LibWeb/Loader/FileDirectoryLoader.cpp | 59 +++++++++++++++++++ .../LibWeb/Loader/FileDirectoryLoader.h | 15 +++++ .../Libraries/LibWeb/Loader/FrameLoader.cpp | 12 ++++ .../Libraries/LibWeb/Loader/FrameLoader.h | 2 + .../LibWeb/Loader/ResourceLoader.cpp | 21 +++++++ 9 files changed, 163 insertions(+) create mode 100644 Base/res/html/directory.html create mode 100644 Userland/Libraries/LibWeb/Loader/FileDirectoryLoader.cpp create mode 100644 Userland/Libraries/LibWeb/Loader/FileDirectoryLoader.h diff --git a/Base/res/html/directory.html b/Base/res/html/directory.html new file mode 100644 index 00000000000..30f855fa0e0 --- /dev/null +++ b/Base/res/html/directory.html @@ -0,0 +1,51 @@ + + + + + Index of @path@ + + + +
+ +

Index of @path@

+
+

Open Parent Directory

+
+ @contents@ +
+ + diff --git a/Ladybird/WebContent/main.cpp b/Ladybird/WebContent/main.cpp index 3126963aa51..f62f13fd3fc 100644 --- a/Ladybird/WebContent/main.cpp +++ b/Ladybird/WebContent/main.cpp @@ -100,6 +100,7 @@ ErrorOr serenity_main(Main::Arguments arguments) Web::FrameLoader::set_resource_directory_url(DeprecatedString::formatted("file://{}/res", s_serenity_resource_root)); Web::FrameLoader::set_error_page_url(DeprecatedString::formatted("file://{}/res/html/error.html", s_serenity_resource_root)); + Web::FrameLoader::set_directory_page_url(DeprecatedString::formatted("file://{}/res/html/directory.html", s_serenity_resource_root)); TRY(Web::Bindings::initialize_main_thread_vm()); diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/Loader/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibWeb/Loader/BUILD.gn index 34109d2b9d0..0e7fedcd1e1 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWeb/Loader/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/Loader/BUILD.gn @@ -3,6 +3,7 @@ source_set("Loader") { deps = [ "//Userland/Libraries/LibWeb:all_generated" ] sources = [ "ContentFilter.cpp", + "FileDirectoryLoader.cpp", "FileRequest.cpp", "FrameLoader.cpp", "LoadRequest.cpp", diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 70ad8fba513..d1d755f5f6e 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -444,6 +444,7 @@ set(SOURCES Layout/TreeBuilder.cpp Layout/VideoBox.cpp Loader/ContentFilter.cpp + Loader/FileDirectoryLoader.cpp Loader/FileRequest.cpp Loader/FrameLoader.cpp Loader/LoadRequest.cpp diff --git a/Userland/Libraries/LibWeb/Loader/FileDirectoryLoader.cpp b/Userland/Libraries/LibWeb/Loader/FileDirectoryLoader.cpp new file mode 100644 index 00000000000..e76453e62fb --- /dev/null +++ b/Userland/Libraries/LibWeb/Loader/FileDirectoryLoader.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023, Bastiaan van der Plaat + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace Web { + +ErrorOr load_file_directory_page(LoadRequest const& request) +{ + // Generate HTML contents entries table + auto lexical_path = LexicalPath(request.url().serialize_path()); + Core::DirIterator dt(lexical_path.string(), Core::DirIterator::Flags::SkipParentAndBaseDir); + Vector names; + while (dt.has_next()) + names.append(dt.next_path()); + quick_sort(names); + + StringBuilder contents; + contents.append(""sv); + for (auto& name : names) { + auto path = lexical_path.append(name); + auto maybe_st = Core::System::stat(path.string()); + if (!maybe_st.is_error()) { + auto st = maybe_st.release_value(); + contents.append(""sv); + contents.appendff("", S_ISDIR(st.st_mode) ? "folder" : "file"); + contents.appendff(""sv, path, name); + contents.appendff("", st.st_size); + contents.appendff(""sv, Core::DateTime::from_timestamp(st.st_mtime).to_deprecated_string()); + contents.append("\n"sv); + } + } + contents.append("
{} {:10} {}
"sv); + + // Generate HTML directory page from directory template file + // FIXME: Use an actual templating engine (our own one when it's built, preferably with a way to check these usages at compile time) + auto template_path = AK::URL::create_with_url_or_path(FrameLoader::directory_page_url()).serialize_path(); + auto template_file = TRY(Core::File::open(template_path, Core::File::OpenMode::Read)); + auto template_contents = TRY(template_file->read_until_eof()); + StringBuilder builder; + SourceGenerator generator { builder }; + generator.set("resource_directory_url", FrameLoader::resource_directory_url()); + generator.set("path", escape_html_entities(lexical_path.string())); + generator.set("parent_path", escape_html_entities(lexical_path.parent().string())); + generator.set("contents", contents.to_deprecated_string()); + generator.append(template_contents); + return generator.as_string_view().to_deprecated_string(); +} + +} diff --git a/Userland/Libraries/LibWeb/Loader/FileDirectoryLoader.h b/Userland/Libraries/LibWeb/Loader/FileDirectoryLoader.h new file mode 100644 index 00000000000..e7a22e6fabf --- /dev/null +++ b/Userland/Libraries/LibWeb/Loader/FileDirectoryLoader.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023, Bastiaan van der Plaat + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web { + +ErrorOr load_file_directory_page(LoadRequest const&); + +} diff --git a/Userland/Libraries/LibWeb/Loader/FrameLoader.cpp b/Userland/Libraries/LibWeb/Loader/FrameLoader.cpp index 8fc575d0904..f49a124c7a4 100644 --- a/Userland/Libraries/LibWeb/Loader/FrameLoader.cpp +++ b/Userland/Libraries/LibWeb/Loader/FrameLoader.cpp @@ -193,6 +193,18 @@ void FrameLoader::set_error_page_url(DeprecatedString error_page_url) s_error_page_url = error_page_url; } +static DeprecatedString s_directory_page_url = "file:///res/html/directory.html"; + +DeprecatedString FrameLoader::directory_page_url() +{ + return s_directory_page_url; +} + +void FrameLoader::set_directory_page_url(DeprecatedString directory_page_url) +{ + s_directory_page_url = directory_page_url; +} + // FIXME: Use an actual templating engine (our own one when it's built, preferably // with a way to check these usages at compile time) diff --git a/Userland/Libraries/LibWeb/Loader/FrameLoader.h b/Userland/Libraries/LibWeb/Loader/FrameLoader.h index e941566ded7..4c4ccfa7f3a 100644 --- a/Userland/Libraries/LibWeb/Loader/FrameLoader.h +++ b/Userland/Libraries/LibWeb/Loader/FrameLoader.h @@ -29,6 +29,8 @@ public: static void set_resource_directory_url(DeprecatedString); static DeprecatedString error_page_url(); static void set_error_page_url(DeprecatedString); + static DeprecatedString directory_page_url(); + static void set_directory_page_url(DeprecatedString); explicit FrameLoader(HTML::BrowsingContext&); ~FrameLoader(); diff --git a/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp b/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp index d251851835c..8759fd2add1 100644 --- a/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp +++ b/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp @@ -7,11 +7,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -251,6 +253,25 @@ void ResourceLoader::load(LoadRequest& request, Function response_headers; + response_headers.set("Content-Type"sv, "text/html"sv); + success_callback(maybe_response.release_value().bytes(), response_headers, {}); + return; + } + + // Try to read file normally auto maybe_file = Core::File::adopt_fd(fd, Core::File::OpenMode::Read); if (maybe_file.is_error()) { log_failure(request, maybe_file.error());