diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2021-10-04 16:56:02 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2021-10-04 16:56:02 +0200 |
commit | f0f4b8a4d139a855ad15f9d79190edf6320eba51 (patch) | |
tree | 4ba361738f08bf44769e3454832d765ba8d7f2c1 | |
parent | 5ff3d7a51be30a0052b12f9330fdf54f3c104739 (diff) |
Static file cache content module.
* remove EVHTTP headers
* magic/mime type support for virtual Filesystem
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/ContentManager.cpp | 2 | ||||
-rw-r--r-- | src/ContentManager.hpp | 3 | ||||
-rw-r--r-- | src/EventManager.cpp | 18 | ||||
-rw-r--r-- | src/EventManager.hpp | 1 | ||||
-rw-r--r-- | src/Filesystem.cpp | 44 | ||||
-rw-r--r-- | src/Filesystem.hpp | 17 | ||||
-rw-r--r-- | src/RequestResponse.cpp | 40 | ||||
-rw-r--r-- | src/RequestResponse.hpp | 19 | ||||
-rw-r--r-- | src/TemplateManager.cpp | 2 | ||||
-rw-r--r-- | src/TemplateManager.hpp | 2 | ||||
-rw-r--r-- | src/content/static/Static.cpp | 31 | ||||
-rw-r--r-- | src/content/static/Static.hpp | 7 | ||||
-rw-r--r-- | src/main.cpp | 9 |
14 files changed, 138 insertions, 59 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 9972193..ecc3b2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,4 +19,4 @@ add_executable(cpp-web ${SOURCES}) if(CMAKE_BUILD_TYPE MATCHES Release) set_target_properties(cpp-web PROPERTIES LINK_FLAGS "-no-pie -flto -Wl,--gc-sections -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none") endif() -target_link_libraries(cpp-web stdc++fs pthread event) +target_link_libraries(cpp-web stdc++fs pthread event magic) diff --git a/src/ContentManager.cpp b/src/ContentManager.cpp index ace325e..8bff717 100644 --- a/src/ContentManager.cpp +++ b/src/ContentManager.cpp @@ -1,6 +1,6 @@ #include "ContentManager.hpp" -void ContentManager::SetTemplateSystem(std::shared_ptr<TemplateManager> & tmgr) +void ContentManager::SetTemplateSystem(std::shared_ptr<TemplateManager> const & tmgr) { m_TemplateManager = tmgr; } diff --git a/src/ContentManager.hpp b/src/ContentManager.hpp index 9ae7271..674a5d0 100644 --- a/src/ContentManager.hpp +++ b/src/ContentManager.hpp @@ -21,8 +21,7 @@ public: ShutdownAll(); } - void SetStaticFilesystem(std::shared_ptr<Filesystem> & static_fs); - void SetTemplateSystem(std::shared_ptr<TemplateManager> & tmgr); + void SetTemplateSystem(std::shared_ptr<TemplateManager> const & tmgr); bool RegisterModule(std::shared_ptr<Content> ctnt); bool InitAll(void); void ShutdownAll(void); diff --git a/src/EventManager.cpp b/src/EventManager.cpp index bc4b5cb..6c735a8 100644 --- a/src/EventManager.cpp +++ b/src/EventManager.cpp @@ -10,8 +10,18 @@ extern "C" { + struct chunk_req_state + { + struct event_base * base; + struct evhttp_request * req; + struct event * timer; + + off_t out_offset; + }; + static void GenerateInternalErrorPage(struct evhttp_request * const req, std::string text) { + evhttp_clear_headers(evhttp_request_get_output_headers(req)); evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/html"); struct evbuffer * const output = evbuffer_new(); @@ -55,7 +65,7 @@ extern "C" } std::shared_ptr<ContentManager> const cmgr = *(std::shared_ptr<ContentManager> const *)ev_c_callback; - RequestResponse rr(req); + RequestResponse rr(path, req); std::string out; if (cmgr->Render(path, rr, out) == false) @@ -66,8 +76,6 @@ extern "C" } else { - evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/html"); - struct evbuffer * const output = evbuffer_new(); if (output != nullptr) { @@ -213,3 +221,7 @@ void EventManager::AddCallback(std::string url, EvFunction fn, EvUserData dat) { m_UrlCallbacks.push_back(EvUrlCallback(url, {fn, dat})); } + +void EventManager::AddChunkedCallback(std::string url, EvFunction fn, EvUserData dat, struct timeval chunk_timer) +{ +} diff --git a/src/EventManager.hpp b/src/EventManager.hpp index cf09e14..5d74602 100644 --- a/src/EventManager.hpp +++ b/src/EventManager.hpp @@ -32,6 +32,7 @@ public: bool Init(std::string = "127.0.0.1", uint16_t port = 9000); void SetDefaultCallback(EvFunction fn, EvUserData dat); void AddCallback(std::string url, EvFunction fn, EvUserData dat); + void AddChunkedCallback(std::string url, EvFunction fn, EvUserData dat, struct timeval chunk_timer); private: std::shared_ptr<ContentManager> m_ContentManager; diff --git a/src/Filesystem.cpp b/src/Filesystem.cpp index 09e5146..04dbb1b 100644 --- a/src/Filesystem.cpp +++ b/src/Filesystem.cpp @@ -10,8 +10,18 @@ static std::string make_path_relative(std::string & path, std::string & root) return std::filesystem::relative(path, root); } +static bool is_directory(std::string & path) +{ + return std::filesystem::is_directory(path); +} + bool Filesystem::AddSingleFile(std::string path, std::string root) { + if (is_directory(path) == true) + { + return true; + } + std::ifstream ifs(path, std::ios::binary | std::ios::ate); if (!ifs) @@ -29,9 +39,9 @@ bool Filesystem::AddSingleFile(std::string path, std::string root) return false; } - auto size = std::size_t(end - ifs.tellg()); + auto size = end - ifs.tellg(); - if (size == 0) + if (size <= 0) { return false; } @@ -62,6 +72,7 @@ bool Filesystem::AddSingleFile(std::string path, std::string root) std::cout << "Adding file: " << path << " (" << size << " bytes) as " << relpath << " to " << this << std::endl; } + fd.mime = magic_file(m_Magic, path.c_str()); m_Files[relpath] = fd; return true; @@ -69,24 +80,14 @@ bool Filesystem::AddSingleFile(std::string path, std::string root) bool Filesystem::Scan(std::string root) { - bool retval = true; - - for (const auto & entry : std::filesystem::directory_iterator(root)) - { - if (AddSingleFile(entry.path(), root) == false) - { - retval = true; - } - } - - return retval; + return Scan(root, {}, true); } bool Filesystem::Scan(std::string root, std::vector<std::string> extensions, bool exclude_extensions) { bool retval = true; - for (const auto & entry : std::filesystem::directory_iterator(root)) + for (const auto & entry : std::filesystem::recursive_directory_iterator(root)) { std::string ext = std::filesystem::path(entry).extension(); bool found_extension = false; @@ -119,7 +120,20 @@ bool Filesystem::Scan(std::string root, std::vector<std::string> extensions, boo return retval; } -const std::unordered_map<std::string, struct file_data> & Filesystem::GetFiles() const +FilesDict & Filesystem::GetFiles() { return m_Files; } + +void Filesystem::MagicInit() +{ + m_Magic = magic_open(MAGIC_MIME_TYPE); + + magic_load(m_Magic, NULL); + magic_compile(m_Magic, NULL); +} + +void Filesystem::MagicClose() +{ + magic_close(m_Magic); +} diff --git a/src/Filesystem.hpp b/src/Filesystem.hpp index 13733c9..02150fb 100644 --- a/src/Filesystem.hpp +++ b/src/Filesystem.hpp @@ -1,13 +1,18 @@ #ifndef FILESYSTEM_H #define FILESYSTEM_H 1 +#include <magic.h> + #include <inja/inja.hpp> #include <string> #include <unordered_map> #include <vector> +using FilesDict = std::unordered_map<std::string, struct file_data>; + struct file_data { + std::string mime; std::vector<unsigned char> data; }; @@ -16,18 +21,24 @@ class Filesystem public: Filesystem() { + MagicInit(); } ~Filesystem() { + MagicClose(); } - bool AddSingleFile(std::string path, std::string root); bool Scan(std::string root = "./wwwroot"); bool Scan(std::string root, std::vector<std::string> extensions, bool exclude_extensions = false); - const std::unordered_map<std::string, struct file_data> & GetFiles() const; + FilesDict & GetFiles(); private: - std::unordered_map<std::string, struct file_data> m_Files; + bool AddSingleFile(std::string path, std::string root); + void MagicInit(); + void MagicClose(); + + FilesDict m_Files; + magic_t m_Magic; }; #endif diff --git a/src/RequestResponse.cpp b/src/RequestResponse.cpp index 2567253..803b432 100644 --- a/src/RequestResponse.cpp +++ b/src/RequestResponse.cpp @@ -1,6 +1,7 @@ #include "RequestResponse.hpp" -RequestResponse::RequestResponse(struct evhttp_request * const req) : m_Request(req) +RequestResponse::RequestResponse(char const * const uri_path, struct evhttp_request * const req) + : m_UriPath(uri_path), m_Request(req) { } @@ -18,18 +19,43 @@ void RequestResponse::UseOutputHeader() m_OutputHeader = evhttp_request_get_output_headers(m_Request); } -bool RequestResponse::AddOutputHeaderByRef(std::string & key, std::string & value) +bool RequestResponse::AddOutputHeaderByRef(std::string const & key, std::string const & value) { - return evhttp_add_header(m_OutputHeader, key.c_str(), value.c_str()); + if (m_OutputHeader == nullptr) + { + return false; + } + + return evhttp_add_header(m_OutputHeader, key.c_str(), value.c_str()) == 0; } -bool RequestResponse::AddOutputHeader(std::string key, std::string value) +bool RequestResponse::AddOutputHeader(std::string const key, std::string const value) { return AddOutputHeaderByRef(key, value); } -bool RequestResponse::GetInputHeaderByRef(std::string & key, std::string & value) +bool RequestResponse::RemoveOutputHeaderByRef(std::string const & key) +{ + if (m_OutputHeader == nullptr) + { + return false; + } + + return evhttp_remove_header(m_OutputHeader, key.c_str()) == 0; +} + +bool RequestResponse::RemoveOutputHeader(std::string const key) +{ + return RemoveOutputHeaderByRef(key); +} + +bool RequestResponse::GetInputHeaderByRef(std::string const & key, std::string & value) { + if (m_InputHeader == nullptr) + { + return false; + } + char const * const v = evhttp_find_header(m_InputHeader, key.c_str()); if (v == nullptr) @@ -41,7 +67,7 @@ bool RequestResponse::GetInputHeaderByRef(std::string & key, std::string & value return true; } -bool RequestResponse::GetInputHeader(std::string key, std::string value) +bool RequestResponse::GetInputHeader(std::string const key, std::string value) { - return GetInputHeader(key, value); + return GetInputHeaderByRef(key, value); } diff --git a/src/RequestResponse.hpp b/src/RequestResponse.hpp index 8a7e1d3..da2a27d 100644 --- a/src/RequestResponse.hpp +++ b/src/RequestResponse.hpp @@ -8,19 +8,28 @@ class RequestResponse { public: - RequestResponse(struct evhttp_request * const req); + RequestResponse(char const * const uri_path, struct evhttp_request * const req); ~RequestResponse(); + char const * GetUriPath() const + { + return m_UriPath; + } + void UseInputHeader(); void UseOutputHeader(); - bool AddOutputHeaderByRef(std::string & key, std::string & value); - bool AddOutputHeader(std::string key, std::string value); + bool AddOutputHeaderByRef(std::string const & key, std::string const & value); + bool AddOutputHeader(std::string const key, std::string const value); + + bool RemoveOutputHeaderByRef(std::string const & key); + bool RemoveOutputHeader(std::string const key); - bool GetInputHeaderByRef(std::string & key, std::string & value); - bool GetInputHeader(std::string key, std::string value); + bool GetInputHeaderByRef(std::string const & key, std::string & value); + bool GetInputHeader(std::string const key, std::string value); private: + char const * const m_UriPath; struct evhttp_request * const m_Request; struct evkeyvalq * m_InputHeader; struct evkeyvalq * m_OutputHeader; diff --git a/src/TemplateManager.cpp b/src/TemplateManager.cpp index 06771ea..a751116 100644 --- a/src/TemplateManager.cpp +++ b/src/TemplateManager.cpp @@ -14,7 +14,7 @@ TemplateManager::TemplateManager() }); } -void TemplateManager::ParseTemplates(Filesystem const & fs) +void TemplateManager::ParseTemplates(Filesystem & fs) { for (auto & tpl : fs.GetFiles()) { diff --git a/src/TemplateManager.hpp b/src/TemplateManager.hpp index 7b89d71..1d98c50 100644 --- a/src/TemplateManager.hpp +++ b/src/TemplateManager.hpp @@ -14,7 +14,7 @@ public: { } - void ParseTemplates(Filesystem const & fs); + void ParseTemplates(Filesystem & fs); void AddInjaCallback(std::string functionName, std::size_t numberOfArgs, inja::CallbackFunction function); void AddVoidInjaCallback(std::string functionName, std::size_t numberOfArgs, inja::VoidCallbackFunction function); bool TemplateExists(std::string const & templatePath); diff --git a/src/content/static/Static.cpp b/src/content/static/Static.cpp index 5e38b76..b9977a9 100644 --- a/src/content/static/Static.cpp +++ b/src/content/static/Static.cpp @@ -1,20 +1,18 @@ #include "Static.hpp" -Static::Static(std::string uriBasePath, std::string staticFilesPath) - : Content(), m_UriBasePath(uriBasePath), m_MainTemplatePath(""), m_StaticFilesPath(staticFilesPath) +Static::Static(std::string uriBasePath, std::shared_ptr<Filesystem> const & fs) + : Content(), m_UriBasePath(uriBasePath), m_MainTemplatePath(""), m_StaticFiles(fs) { + for (auto const & file : fs->GetFiles()) + { + m_Redirections.push_back(uriBasePath + "/" + file.first); + m_UriToFsMapping[uriBasePath + "/" + file.first] = file.first; + } } bool Static::Init() { - std::cout << "Static files path: " << m_StaticFilesPath << std::endl; - - std::vector<std::string> extensions = {"json"}; - - if (m_StaticFiles.Scan(m_StaticFilesPath, extensions, false) == false) - { - return false; - } + std::cout << "Static files: " << m_StaticFiles->GetFiles().size() << std::endl; return true; } @@ -26,11 +24,18 @@ void Static::Shutdown() bool Static::Render(RequestResponse & rr, RenderData & rd, std::string & out) { - (void)rr; (void)rd; - (void)out; - rd["blah"] = "Yooooh!"; + rr.UseOutputHeader(); + auto & files = m_StaticFiles->GetFiles(); + auto const & path = std::string(rr.GetUriPath()); + + if (rr.AddOutputHeader("Content-Type", files[m_UriToFsMapping[path]].mime) == false) + { + return false; + } + + out = std::string(files[m_UriToFsMapping[path]].data.begin(), files[m_UriToFsMapping[path]].data.end()); return true; } diff --git a/src/content/static/Static.hpp b/src/content/static/Static.hpp index 85ffd8c..8dcf410 100644 --- a/src/content/static/Static.hpp +++ b/src/content/static/Static.hpp @@ -3,12 +3,11 @@ #include "../../Content.hpp" #include "../../Filesystem.hpp" -#include "../markdown/Markdown.hpp" class Static : public Content { public: - explicit Static(std::string uriBasePath, std::string staticFilesPath); + explicit Static(std::string uriBasePath, std::shared_ptr<Filesystem> const & fs); bool Init(); void Shutdown(); @@ -21,9 +20,9 @@ public: private: std::string m_UriBasePath; std::string m_MainTemplatePath; - std::string m_StaticFilesPath; Redirections m_Redirections; - Filesystem m_StaticFiles; + std::shared_ptr<Filesystem> const m_StaticFiles; + std::unordered_map<std::string, std::string> m_UriToFsMapping; }; #endif diff --git a/src/main.cpp b/src/main.cpp index 6d41907..50f0ec5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include "TemplateManager.hpp" #include "content/blog/Blog.hpp" +#include "content/static/Static.hpp" #include <event2/buffer.h> @@ -93,15 +94,17 @@ int main(int argc, char ** argv) ctmgr->SetTemplateSystem(tmgr); { - Filesystem static_fs; + std::shared_ptr<Filesystem> static_fs = std::make_shared<Filesystem>(); if (argc > 3) { - if (static_fs.Scan(argv[3]) != true) + if (static_fs->Scan(argv[3]) != true) { return 1; } } - static_fs.Scan("./wwwroot", {"html", "tmpl"}, true); + static_fs->Scan("./wwwroot", {"html", "tmpl"}, true); + + ctmgr->RegisterModule(std::make_shared<Static>("/static", static_fs)); } { |