From 27564e9aa4c2314b1fede68470ad2e165734bd58 Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Mon, 9 Sep 2024 09:45:08 +0800 Subject: [PATCH] Server::respond_with_static_file() for better control over static files Can now handle static file requests the same as any Get() request, meaning the handler's priority can be controlled by the developer. ie svr.Get("/something", [](auto req, auto res) { dont return the file "something"; instead, return something else; }); svr.GET("/(.*)", [](auto req, auto res) { // chance to further filter or adjust request to suit auto result = svr.respond_with_static_file( req, res, req.matches[1], "base_dir"); // optional chance to override response from the default switch (result) { SFR_DirRedirect: break; SFR_File: break; // chance to set additional headers SFR_CouldNotOpen: break; // chance to respond nicely SFR_NotFound: break; // chance to respond nicely } }); --- httplib.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/httplib.h b/httplib.h index d56475a..cfac9c4 100644 --- a/httplib.h +++ b/httplib.h @@ -1007,6 +1007,10 @@ public: void stop(); void decommission(); + // helpers, member functions to get access to mime file map and other things + enum StaticFileResponse { SFR_DirRedirect, SFR_File, SFR_CouldNotOpen, SFR_NotFound }; + inline StaticFileResponse respond_with_static_file(const Request &req, Response &res, std::string sub_path, std::string disk_base_dir) const; + std::function new_task_queue; protected: @@ -6558,6 +6562,42 @@ Server::read_content_core(Stream &strm, Request &req, Response &res, return true; } + +inline Server::StaticFileResponse Server::respond_with_static_file(const Request &req, Response &res, std::string sub_path, std::string disk_base_dir) const { + if (detail::is_valid_path(sub_path)) { + auto path = disk_base_dir + '/' + sub_path; + if (path.back() == '/') { path += "index.html"; } + + else if (detail::is_dir(path)) { + res.set_redirect(sub_path + "/"); + return SFR_DirRedirect; + } + + if (detail::is_file(path)) { + auto mm = std::make_shared(path.c_str()); + if (!mm->is_open()) { return SFR_CouldNotOpen; } + + res.set_content_provider( + mm->size(), + detail::find_content_type(path, file_extension_and_mimetype_map_, + default_file_mimetype_), + [mm](size_t offset, size_t length, DataSink &sink) -> bool { + sink.write(mm->data() + offset, length); + return true; + }); + + bool head = req.method == "HEAD"; + if (!head && file_request_handler_) { + file_request_handler_(req, res); + } + + return SFR_File; + } + } + res.status = StatusCode::NotFound_404; + return SFR_NotFound; +} + inline bool Server::handle_file_request(const Request &req, Response &res, bool head) { for (const auto &entry : base_dirs_) {