#include "common.hh" #include "files_finder.hh" #include "hasher.hh" #include "mime_types.hh" #include "send_file.hh" #include "static_files.hh" #include "weak_ptr.hh" #include namespace { class StaticFilesImpl : public StaticFiles, public FilesFinder::Delegate { public: StaticFilesImpl( std::shared_ptr logger, std::shared_ptr runner, std::shared_ptr send_file, std::filesystem::path path, size_t threads) : root_(std::move(path)), send_file_(std::move(send_file)), weak_ptr_owner_(this) { finder_ = FilesFinder::create(logger, runner, root_, this, threads); hasher_ = Hasher::create(logger, runner, threads); } std::unique_ptr request( Transport* transport, std::string_view path) override { auto it = files_.find(std::string(path)); if (it == files_.end()) return nullptr; auto resp = send_file_->create_ok_file(transport, it->second.path_, it->first, it->second.etag_, it->second.size_); if (!it->second.mime_type_.empty()) resp->add_header("Content-Type", it->second.mime_type_); return resp; } void file(std::filesystem::path path) override { std::string name("/"); name.append(path.filename()); auto parent = path.parent_path(); while (true) { if (parent == root_ || !parent.has_parent_path()) break; name.insert(0, parent.filename()); name.insert(0, "/"); parent = parent.parent_path(); } files_[name].path_ = path; if (path.has_extension()) files_[name].mime_type_ = mime_types::from_extension( std::string(path.extension()).substr(1)); hasher_->hash(path, std::bind(&StaticFilesImpl::weak_hashed, weak_ptr_owner_.get(), name, std::placeholders::_1, std::placeholders::_2)); } void done() override { finder_.reset(); } private: struct File { std::filesystem::path path_; std::string mime_type_; std::string etag_; std::optional size_; }; static void weak_hashed(std::shared_ptr> weak_ptr, std::string const& name, std::string hash, uint64_t size) { auto* ptr = weak_ptr->get(); if (ptr) ptr->hashed(name, std::move(hash), size); } void hashed(std::string const& name, std::string hash, uint64_t size) { if (hash.empty()) return; hash.insert(0, "\""); hash.push_back('"'); files_[name].etag_ = std::move(hash); files_[name].size_ = size; } std::filesystem::path root_; std::shared_ptr send_file_; std::unordered_map files_; std::unique_ptr finder_; std::unique_ptr hasher_; WeakPtrOwner weak_ptr_owner_; }; } // namespace std::unique_ptr StaticFiles::create( std::shared_ptr logger, std::shared_ptr runner, std::shared_ptr send_file, std::filesystem::path path, size_t threads) { return std::make_unique( std::move(logger), std::move(runner), std::move(send_file), std::move(path), threads); }