|
@@ -25,7 +25,9 @@
|
|
|
*/
|
|
|
|
|
|
#include "Client.h"
|
|
|
+#include <AK/Base64.h>
|
|
|
#include <AK/LexicalPath.h>
|
|
|
+#include <AK/MappedFile.h>
|
|
|
#include <AK/StringBuilder.h>
|
|
|
#include <AK/URLParser.h>
|
|
|
#include <LibCore/DateTime.h>
|
|
@@ -156,6 +158,26 @@ void Client::send_redirect(StringView redirect_path, const HTTP::HttpRequest& re
|
|
|
log_response(301, request);
|
|
|
}
|
|
|
|
|
|
+static String folder_image_data()
|
|
|
+{
|
|
|
+ static String cache;
|
|
|
+ if (cache.is_empty()) {
|
|
|
+ MappedFile image("/res/icons/16x16/filetype-folder.png");
|
|
|
+ cache = encode_base64({ image.data(), image.size() });
|
|
|
+ }
|
|
|
+ return cache;
|
|
|
+}
|
|
|
+
|
|
|
+static String file_image_data()
|
|
|
+{
|
|
|
+ static String cache;
|
|
|
+ if (cache.is_empty()) {
|
|
|
+ MappedFile image("/res/icons/16x16/filetype-unknown.png");
|
|
|
+ cache = encode_base64({ image.data(), image.size() });
|
|
|
+ }
|
|
|
+ return cache;
|
|
|
+}
|
|
|
+
|
|
|
void Client::handle_directory_listing(const String& requested_path, const String& real_path, const HTTP::HttpRequest& request)
|
|
|
{
|
|
|
StringBuilder builder;
|
|
@@ -164,22 +186,23 @@ void Client::handle_directory_listing(const String& requested_path, const String
|
|
|
builder.append("<html>\n");
|
|
|
builder.append("<head><title>Index of ");
|
|
|
builder.append(escape_html_entities(requested_path));
|
|
|
- builder.append("</title></head>\n");
|
|
|
- builder.append("<body>\n");
|
|
|
+ builder.append("</title><style>\n");
|
|
|
+ builder.append(".folder { width: 16px; height: 16px; background-image: url('data:image/png;base64,");
|
|
|
+ builder.append(folder_image_data());
|
|
|
+ builder.append("'); }\n");
|
|
|
+ builder.append(".file { width: 16px; height: 16px; background-image: url('data:image/png;base64,");
|
|
|
+ builder.append(file_image_data());
|
|
|
+ builder.append("'); }\n");
|
|
|
+ builder.append("</style></head><body>\n");
|
|
|
builder.append("<h1>Index of ");
|
|
|
builder.append(escape_html_entities(requested_path));
|
|
|
builder.append("</h1>\n");
|
|
|
builder.append("<hr>\n");
|
|
|
- builder.append("<table>\n");
|
|
|
+ builder.append("<code><table>\n");
|
|
|
|
|
|
Core::DirIterator dt(real_path);
|
|
|
while (dt.has_next()) {
|
|
|
auto name = dt.next_path();
|
|
|
- builder.append("<tr><td><a href=\"");
|
|
|
- builder.append(urlencode(name));
|
|
|
- builder.append("\">");
|
|
|
- builder.append(escape_html_entities(name));
|
|
|
- builder.append("</a></td>");
|
|
|
|
|
|
StringBuilder path_builder;
|
|
|
path_builder.append(real_path);
|
|
@@ -191,14 +214,25 @@ void Client::handle_directory_listing(const String& requested_path, const String
|
|
|
if (rc < 0) {
|
|
|
perror("stat");
|
|
|
}
|
|
|
- builder.appendf("<td>%10d</td>", st.st_size);
|
|
|
+
|
|
|
+ bool is_directory = S_ISDIR(st.st_mode) || name.is_one_of(".", "..");
|
|
|
+
|
|
|
+ builder.append("<tr>");
|
|
|
+ builder.appendf("<td><div class=\"%s\"></div></td>", is_directory ? "folder" : "file");
|
|
|
+ builder.append("<td><a href=\"");
|
|
|
+ builder.append(urlencode(name));
|
|
|
+ builder.append("\">");
|
|
|
+ builder.append(escape_html_entities(name));
|
|
|
+ builder.append("</a></td><td> </td>");
|
|
|
+
|
|
|
+ builder.appendf("<td>%10d</td><td> </td>", st.st_size);
|
|
|
builder.append("<td>");
|
|
|
builder.append(Core::DateTime::from_timestamp(st.st_mtime).to_string());
|
|
|
builder.append("</td>");
|
|
|
builder.append("</tr>\n");
|
|
|
}
|
|
|
|
|
|
- builder.append("</table>\n");
|
|
|
+ builder.append("</table></code>\n");
|
|
|
builder.append("<hr>\n");
|
|
|
builder.append("<i>Generated by WebServer (SerenityOS)</i>\n");
|
|
|
builder.append("</body>\n");
|