diff options
author | lns <matzeton@googlemail.com> | 2021-10-21 14:52:26 +0200 |
---|---|---|
committer | lns <matzeton@googlemail.com> | 2021-10-21 14:59:00 +0200 |
commit | 9266070e51422a71566ee5c04db42feec996c485 (patch) | |
tree | 4ff57de8bfce87bde001c80c7ab9fae3080aa248 | |
parent | 384724a00be9dbb8f40d295f99b9c6bcfb48b387 (diff) |
Improved URI handling and redirection/routing.
* parse and process URI query strings
* remove garbage slashes from URI path / sanitize
* more template examples
Signed-off-by: lns <matzeton@googlemail.com>
-rw-r--r-- | blog/my-very-first-blog-entry.md | 6 | ||||
-rw-r--r-- | pages/index.md | 1 | ||||
-rw-r--r-- | src/Content.hpp | 4 | ||||
-rw-r--r-- | src/ContentManager.cpp | 44 | ||||
-rw-r--r-- | src/ContentManager.hpp | 1 | ||||
-rw-r--r-- | src/EventManager.cpp | 9 | ||||
-rw-r--r-- | src/RequestResponse.cpp | 39 | ||||
-rw-r--r-- | src/RequestResponse.hpp | 7 | ||||
-rw-r--r-- | src/content/blog/Blog.cpp | 9 | ||||
-rw-r--r-- | src/content/blog/Blog.hpp | 4 | ||||
-rw-r--r-- | src/content/markdown/Markdown.cpp | 35 | ||||
-rw-r--r-- | src/content/markdown/Markdown.hpp | 4 | ||||
-rw-r--r-- | src/content/static/Static.cpp | 4 | ||||
-rw-r--r-- | src/content/static/Static.hpp | 4 | ||||
-rw-r--r-- | src/main.cpp | 22 | ||||
-rw-r--r-- | wwwroot/blog/index.html | 27 | ||||
-rw-r--r-- | wwwroot/index.html | 27 | ||||
-rw-r--r-- | wwwroot/index.tmpl | 1 |
18 files changed, 177 insertions, 71 deletions
diff --git a/blog/my-very-first-blog-entry.md b/blog/my-very-first-blog-entry.md index 292b1e1..017cbfc 100644 --- a/blog/my-very-first-blog-entry.md +++ b/blog/my-very-first-blog-entry.md @@ -1,2 +1,8 @@ Text ======= + +`test` + +``` +some code... +``` diff --git a/pages/index.md b/pages/index.md new file mode 100644 index 0000000..fbb8dc4 --- /dev/null +++ b/pages/index.md @@ -0,0 +1 @@ +*Just HTML* diff --git a/src/Content.hpp b/src/Content.hpp index 7539e9a..eac3657 100644 --- a/src/Content.hpp +++ b/src/Content.hpp @@ -19,9 +19,9 @@ public: virtual bool Render(RequestResponse & rr, RenderData & rd, std::string & out) = 0; - virtual std::string const & GetUriBasePath() const = 0; + virtual std::string & GetUriBasePath() = 0; virtual std::string const & GetMainTemplate() const = 0; - virtual Redirections const & GetRedirections() const = 0; + virtual Redirections & GetRedirections() = 0; }; #endif diff --git a/src/ContentManager.cpp b/src/ContentManager.cpp index a110e05..da1ab65 100644 --- a/src/ContentManager.cpp +++ b/src/ContentManager.cpp @@ -7,12 +7,16 @@ void ContentManager::SetTemplateSystem(std::shared_ptr<TemplateManager> const & bool ContentManager::RegisterModule(std::shared_ptr<Content> ctnt) { - std::string const & basePath = ctnt->GetUriBasePath(); + std::string & basePath = ctnt->GetUriBasePath(); + ContentManager::RemoveGarbageSlashes(basePath); if (basePath.empty() == true) { return false; } +#if 0 + std::cout << "Base URI: " << basePath << std::endl; +#endif m_ContentModules[basePath] = ctnt; return true; @@ -29,11 +33,32 @@ bool ContentManager::InitAll(void) ret = false; } - Redirections const & rs = content.second->GetRedirections(); + Redirections & rs = content.second->GetRedirections(); for (auto & redirect : rs) { + ContentManager::RemoveGarbageSlashes(redirect); + if (redirect == content.second->GetUriBasePath()) + { + continue; + } + if (m_ContentModulesRoutes.find(redirect) != m_ContentModulesRoutes.end()) + { + std::cerr << "Redirect URI already exists: " << redirect << std::endl; + } + else + { +#if 0 + std::cout << "Redirect URI: " << redirect << std::endl; +#endif + } m_ContentModulesRoutes[redirect] = content.second; } + + std::string & basePath = content.second->GetUriBasePath(); + if (basePath.back() == '/') + { + basePath.pop_back(); + } } return ret; @@ -107,3 +132,18 @@ ContentModules const & ContentManager::GetAllModulesRoutes() const { return m_ContentModulesRoutes; } + +void ContentManager::RemoveGarbageSlashes(std::string & uri_basepath) +{ + size_t start_pos = 0; + static const std::string from = "//"; + static const std::string to = "/"; + + if (from.empty()) + return; + while ((start_pos = uri_basepath.find(from, start_pos)) != std::string::npos) + { + uri_basepath.replace(start_pos, from.length(), to); + start_pos += to.length(); + } +} diff --git a/src/ContentManager.hpp b/src/ContentManager.hpp index 674a5d0..1e45e53 100644 --- a/src/ContentManager.hpp +++ b/src/ContentManager.hpp @@ -28,6 +28,7 @@ public: bool Render(char const * basePath, RequestResponse & rr, std::string & out); ContentModules const & GetAllModules() const; ContentModules const & GetAllModulesRoutes() const; + static void RemoveGarbageSlashes(std::string & uri_basepath); private: std::shared_ptr<TemplateManager> m_TemplateManager; diff --git a/src/EventManager.cpp b/src/EventManager.cpp index d45dcee..2f2da36 100644 --- a/src/EventManager.cpp +++ b/src/EventManager.cpp @@ -63,6 +63,9 @@ extern "C" GenerateInternalErrorPage(req, "EvContentManagerInterceptor: path == nullptr"); return; } +#if 1 + std::cout << "URI Path: " << path << std::endl; +#endif std::shared_ptr<ContentManager> const cmgr = *(std::shared_ptr<ContentManager> const *)ev_c_callback; RequestResponse rr(path, req); @@ -177,21 +180,21 @@ bool EventManager::Init(std::string host, uint16_t port) { if (evhttp_set_cb(m_EvHttp, cm.first.c_str(), EvContentManagerInterceptor, &m_ContentManager) != 0) { - return false; + fprintf(stderr, "Failed to add module callback: %s\n", cm.first.c_str()); } } for (auto & cm : m_ContentManager->GetAllModulesRoutes()) { if (evhttp_set_cb(m_EvHttp, cm.first.c_str(), EvContentManagerInterceptor, &m_ContentManager) != 0) { - return false; + fprintf(stderr, "Failed to add route callback: %s\n", cm.first.c_str()); } } evhttp_set_gencb(m_EvHttp, EvGenericInterceptor, &m_DefaultCallback); if (evhttp_bind_socket(m_EvHttp, host.c_str(), port) != 0) { - fprintf(stderr, "couldn't bind to %s:%d. Exiting.\n", host.c_str(), port); + fprintf(stderr, "Couldn't bind to %s:%d. Exiting.\n", host.c_str(), port); return false; } diff --git a/src/RequestResponse.cpp b/src/RequestResponse.cpp index 803b432..c3247e9 100644 --- a/src/RequestResponse.cpp +++ b/src/RequestResponse.cpp @@ -1,12 +1,13 @@ #include "RequestResponse.hpp" RequestResponse::RequestResponse(char const * const uri_path, struct evhttp_request * const req) - : m_UriPath(uri_path), m_Request(req) + : m_UriPath(uri_path), m_Request(req), m_InputHeader(nullptr), m_OutputHeader(nullptr) { } RequestResponse::~RequestResponse() { + evhttp_clear_headers(&m_Query); } void RequestResponse::UseInputHeader() @@ -19,13 +20,23 @@ void RequestResponse::UseOutputHeader() m_OutputHeader = evhttp_request_get_output_headers(m_Request); } -bool RequestResponse::AddOutputHeaderByRef(std::string const & key, std::string const & value) +bool RequestResponse::UseUri() { - if (m_OutputHeader == nullptr) + struct evhttp_uri const * const uri = evhttp_request_get_evhttp_uri(m_Request); + if (uri == nullptr) + { + return false; + } + char const * const query = evhttp_uri_get_query(uri); + if (query == nullptr) { return false; } + return evhttp_parse_query_str(query, &m_Query) == 0; +} +bool RequestResponse::AddOutputHeaderByRef(std::string const & key, std::string const & value) +{ return evhttp_add_header(m_OutputHeader, key.c_str(), value.c_str()) == 0; } @@ -36,11 +47,6 @@ bool RequestResponse::AddOutputHeader(std::string const key, std::string const v bool RequestResponse::RemoveOutputHeaderByRef(std::string const & key) { - if (m_OutputHeader == nullptr) - { - return false; - } - return evhttp_remove_header(m_OutputHeader, key.c_str()) == 0; } @@ -51,11 +57,6 @@ bool RequestResponse::RemoveOutputHeader(std::string const 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) @@ -71,3 +72,15 @@ bool RequestResponse::GetInputHeader(std::string const key, std::string value) { return GetInputHeaderByRef(key, value); } + +bool RequestResponse::QueryValueEquals(std::string key, std::string value) +{ + char const * const v = evhttp_find_header(&m_Query, key.c_str()); + + if (v == nullptr) + { + return false; + } + + return value == std::string(v); +} diff --git a/src/RequestResponse.hpp b/src/RequestResponse.hpp index da2a27d..3dccd54 100644 --- a/src/RequestResponse.hpp +++ b/src/RequestResponse.hpp @@ -2,13 +2,14 @@ #define REQUEST_RESPONSE_H 1 #include <event2/http.h> +#include <event2/keyvalq_struct.h> #include <string> class RequestResponse { public: - RequestResponse(char const * const uri_path, struct evhttp_request * const req); + explicit RequestResponse(char const * const uri_path, struct evhttp_request * const req); ~RequestResponse(); char const * GetUriPath() const @@ -18,6 +19,7 @@ public: void UseInputHeader(); void UseOutputHeader(); + bool UseUri(); bool AddOutputHeaderByRef(std::string const & key, std::string const & value); bool AddOutputHeader(std::string const key, std::string const value); @@ -28,11 +30,14 @@ public: bool GetInputHeaderByRef(std::string const & key, std::string & value); bool GetInputHeader(std::string const key, std::string value); + bool QueryValueEquals(std::string key, std::string value); + private: char const * const m_UriPath; struct evhttp_request * const m_Request; struct evkeyvalq * m_InputHeader; struct evkeyvalq * m_OutputHeader; + struct evkeyvalq m_Query = {}; }; #endif diff --git a/src/content/blog/Blog.cpp b/src/content/blog/Blog.cpp index ba8638e..47a3292 100644 --- a/src/content/blog/Blog.cpp +++ b/src/content/blog/Blog.cpp @@ -17,7 +17,8 @@ bool Blog::Init() { bool retval = true; - std::cout << "Blog entries path: " << m_BlogPath << std::endl; + std::cout << "Blog entries filesystem path: " << m_BlogPath << std::endl; + std::cout << "Blog entries URI base path: " << m_UriBasePath << std::endl; std::vector<std::string> extensions = {"json"}; Filesystem fs; @@ -39,7 +40,7 @@ bool Blog::Init() } m_BlogEntriesSortedByDate.push_back(be); - m_Redirections.push_back(std::filesystem::path(jfile.first).stem()); + m_Redirections.push_back(m_UriBasePath + "/" + std::string(std::filesystem::path(jfile.first).stem())); } std::sort(m_BlogEntriesSortedByDate.begin(), m_BlogEntriesSortedByDate.end(), @@ -81,7 +82,7 @@ bool Blog::Render(RequestResponse & rr, RenderData & rd, std::string & out) return true; } -std::string const & Blog::GetUriBasePath() const +std::string & Blog::GetUriBasePath() { return m_UriBasePath; } @@ -91,7 +92,7 @@ std::string const & Blog::GetMainTemplate() const return m_MainTemplatePath; } -Redirections const & Blog::GetRedirections() const +Redirections & Blog::GetRedirections() { return m_Redirections; } diff --git a/src/content/blog/Blog.hpp b/src/content/blog/Blog.hpp index d99185a..d58cd72 100644 --- a/src/content/blog/Blog.hpp +++ b/src/content/blog/Blog.hpp @@ -38,9 +38,9 @@ public: void Shutdown(); bool Render(RequestResponse & rr, RenderData & rd, std::string & out); - std::string const & GetUriBasePath() const; + std::string & GetUriBasePath(); std::string const & GetMainTemplate() const; - Redirections const & GetRedirections() const; + Redirections & GetRedirections(); static bool ValidateAndSetMetdadata(BlogMetadata const & blogMetadata, BlogEntry & blogEntry); bool ValidateEntries() const; diff --git a/src/content/markdown/Markdown.cpp b/src/content/markdown/Markdown.cpp index a85f333..903fcec 100644 --- a/src/content/markdown/Markdown.cpp +++ b/src/content/markdown/Markdown.cpp @@ -8,6 +8,11 @@ Markdown::Markdown(std::string uriBasePath, std::string markdownFilesPath, std:: m_MainTemplatePath(mainTemplatePath), m_MarkdownFilesPath(markdownFilesPath) { + if (m_MainTemplatePath.empty() == false) + { + m_Redirections.push_back(uriBasePath + "/"); + m_Redirections.push_back(uriBasePath + "/index.html"); + } } extern "C" void markdown_to_html_conversion(const MD_CHAR * const text, MD_SIZE size, void * const userdata) @@ -20,6 +25,10 @@ extern "C" void markdown_to_html_conversion(const MD_CHAR * const text, MD_SIZE bool Markdown::Init() { std::cout << "Markdown files path: " << m_MarkdownFilesPath << std::endl; + if (m_UriBasePath.empty() == false) + { + std::cout << "Markdown files URI base path: " << m_UriBasePath << std::endl; + } std::vector<std::string> extensions = {"md"}; @@ -68,15 +77,35 @@ bool Markdown::Render(RequestResponse & rr, RenderData & rd, std::string & out) (void)rd; (void)out; + std::string md_file; + if (m_MainTemplatePath.empty() == true) { return false; } - return false; /* TODO: Make markdown module usable as standalone module?! */ + if (rr.GetUriPath() == m_UriBasePath || rr.GetUriPath() == m_UriBasePath + "/" || + rr.GetUriPath() == m_UriBasePath + "/index.html") + { + rr.UseUri(); + if (rr.QueryValueEquals("get", "bla") == true) + { + rd["content"] = "bla"; + } + else + { + rd["content"] = "blubb"; + } + } + else + { + return false; + } + + return true; } -std::string const & Markdown::GetUriBasePath() const +std::string & Markdown::GetUriBasePath() { return m_UriBasePath; } @@ -86,7 +115,7 @@ std::string const & Markdown::GetMainTemplate() const return m_MainTemplatePath; } -Redirections const & Markdown::GetRedirections() const +Redirections & Markdown::GetRedirections() { return m_Redirections; } diff --git a/src/content/markdown/Markdown.hpp b/src/content/markdown/Markdown.hpp index 9c4d3c4..fa14b3a 100644 --- a/src/content/markdown/Markdown.hpp +++ b/src/content/markdown/Markdown.hpp @@ -15,9 +15,9 @@ public: void Shutdown(); bool Render(RequestResponse & rr, RenderData & rd, std::string & out); - std::string const & GetUriBasePath() const; + std::string & GetUriBasePath(); std::string const & GetMainTemplate() const; - Redirections const & GetRedirections() const; + Redirections & GetRedirections(); bool HasMarkdownFile(std::string filePath) const; bool HasMarkdownURI(std::string uriPath) const; diff --git a/src/content/static/Static.cpp b/src/content/static/Static.cpp index 132f0a0..93f9905 100644 --- a/src/content/static/Static.cpp +++ b/src/content/static/Static.cpp @@ -44,7 +44,7 @@ bool Static::Render(RequestResponse & rr, RenderData & rd, std::string & out) return true; } -std::string const & Static::GetUriBasePath() const +std::string & Static::GetUriBasePath() { return m_UriBasePath; } @@ -54,7 +54,7 @@ std::string const & Static::GetMainTemplate() const return m_MainTemplatePath; } -Redirections const & Static::GetRedirections() const +Redirections & Static::GetRedirections() { return m_Redirections; } diff --git a/src/content/static/Static.hpp b/src/content/static/Static.hpp index b9de983..8d702ec 100644 --- a/src/content/static/Static.hpp +++ b/src/content/static/Static.hpp @@ -13,9 +13,9 @@ public: void Shutdown(); bool Render(RequestResponse & rr, RenderData & rd, std::string & out); - std::string const & GetUriBasePath() const; + std::string & GetUriBasePath(); std::string const & GetMainTemplate() const; - Redirections const & GetRedirections() const; + Redirections & GetRedirections(); private: std::string m_UriBasePath; diff --git a/src/main.cpp b/src/main.cpp index 4969d70..dcd24a2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,7 @@ int main(int argc, char ** argv) { + std::string wwwroot = "./wwwroot"; char const * host = "127.0.0.1"; uint16_t port = 9000; @@ -35,8 +36,8 @@ int main(int argc, char ** argv) } std::shared_ptr<TemplateManager> tmgr = std::make_shared<TemplateManager>(); - std::shared_ptr<ContentManager> ctmgr = std::make_shared<ContentManager>(); - ctmgr->SetTemplateSystem(tmgr); + std::shared_ptr<ContentManager> cmgr = std::make_shared<ContentManager>(); + cmgr->SetTemplateSystem(tmgr); { std::shared_ptr<Filesystem> static_fs = std::make_shared<Filesystem>(); @@ -47,9 +48,10 @@ int main(int argc, char ** argv) return 1; } } - static_fs->Scan("./wwwroot", {"html", "tmpl"}, true); + std::cout << "Static fs: " << wwwroot << std::endl; + static_fs->Scan(wwwroot, {"html", "tmpl"}, true); - ctmgr->RegisterModule(std::make_shared<Static>("/static", static_fs)); + cmgr->RegisterModule(std::make_shared<Static>("/static", static_fs)); } { @@ -61,21 +63,23 @@ int main(int argc, char ** argv) return 1; } } - dynamic_fs.Scan("./wwwroot", {"html", "tmpl"}, false); + std::cout << "Dynamic fs: " << wwwroot << std::endl; + dynamic_fs.Scan(wwwroot, {"html", "tmpl"}, false); tmgr->ParseTemplates(dynamic_fs); } - ctmgr->RegisterModule(std::make_shared<Blog>("/blog", "index.html", "./blog")); + cmgr->RegisterModule(std::make_shared<Markdown>("/", "./pages", "index.html")); + cmgr->RegisterModule(std::make_shared<Blog>("/blog", "blog/index.html", "./blog")); - if (ctmgr->InitAll() == false) + if (cmgr->InitAll() == false) { std::cout << "InitAll() failed." << std::endl; return 1; } - EventManager evmgr(ctmgr); + EventManager evmgr(cmgr); evmgr.Init(host, port); - // ctmgr.ShutdownAll(); + // cmgr.ShutdownAll(); } diff --git a/wwwroot/blog/index.html b/wwwroot/blog/index.html new file mode 100644 index 0000000..554a952 --- /dev/null +++ b/wwwroot/blog/index.html @@ -0,0 +1,27 @@ +<html><body> +<p> +<b>blabla</b> +Test fn....: <b>{{ test_fn }}</b><br> +Test RetFN.: <b>{{ test_return_true }}</b><br><br><br> +{% if exists("blog_listing") and length(blog_listing) > 0 %} +<table> +## for entry in blog_listing + <tr> + <td>{{ loop.index1 }}</td> + <td>{{ entry.content_filename }}</td> + <td>{{ entry.title }}</td> + <td>{{ entry.tags }}</td> + <td>{{ entry.author }}</td> + <td>{{ entry.createDate }}</td> + <td>{{ entry.publishDate }}</td> + <td>{{ entry.published }}</td> + <td> + {{ indent(entry.content, 12, false, false) }} + </td> + <td>{% if loop.is_last == false %}more{% else %}eof{% endif %}<br> + </tr> +## endfor +</table> +{% endif %} +</p> +</body></html> diff --git a/wwwroot/index.html b/wwwroot/index.html index 554a952..9b05eee 100644 --- a/wwwroot/index.html +++ b/wwwroot/index.html @@ -1,27 +1,4 @@ <html><body> -<p> -<b>blabla</b> -Test fn....: <b>{{ test_fn }}</b><br> -Test RetFN.: <b>{{ test_return_true }}</b><br><br><br> -{% if exists("blog_listing") and length(blog_listing) > 0 %} -<table> -## for entry in blog_listing - <tr> - <td>{{ loop.index1 }}</td> - <td>{{ entry.content_filename }}</td> - <td>{{ entry.title }}</td> - <td>{{ entry.tags }}</td> - <td>{{ entry.author }}</td> - <td>{{ entry.createDate }}</td> - <td>{{ entry.publishDate }}</td> - <td>{{ entry.published }}</td> - <td> - {{ indent(entry.content, 12, false, false) }} - </td> - <td>{% if loop.is_last == false %}more{% else %}eof{% endif %}<br> - </tr> -## endfor -</table> -{% endif %} -</p> + <b>INDEX TMPL</b> + {{ content }} </body></html> diff --git a/wwwroot/index.tmpl b/wwwroot/index.tmpl deleted file mode 100644 index b42f18c..0000000 --- a/wwwroot/index.tmpl +++ /dev/null @@ -1 +0,0 @@ -<html><body><b>INDEX TMPL</b></body></html> |