From 800cc5b68a205339dc6f84950a9ae2722e04be4b Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Sun, 23 Jan 2022 22:39:28 +0400 Subject: [PATCH 1/9] Got rid of Response::build_404() --- src/server/internalServer.cpp | 33 +++++++++++++++++++-------------- src/server/response.cpp | 25 ------------------------- src/server/response.h | 10 ---------- 3 files changed, 19 insertions(+), 49 deletions(-) diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index 0c45580ad..91e5d3ab4 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -660,8 +660,9 @@ std::unique_ptr InternalServer::handle_random(const RequestContext& re return build_redirect(bookName, getFinalItem(*archive, entry)); } catch(zim::EntryNotFound& e) { const std::string error_details = "Oops! Failed to pick a random article :("; - auto response = Response::build_404(*this, "", error_details); - return withTaskbarInfo(bookName, archive.get(), std::move(response)); + return HTTP404HtmlResponse(*this, request) + + error_details + + TaskbarInfo(bookName, archive.get()); } } @@ -838,11 +839,11 @@ std::unique_ptr InternalServer::handle_content(const RequestContext& r } catch (const std::out_of_range& e) {} if (archive == nullptr) { - std::string searchURL = m_root + "/search?pattern=" + kiwix::urlEncode(pattern, true); // Make a full search on the entire library. - const std::string details = searchSuggestionHTML(searchURL, kiwix::urlDecode(pattern)); - - auto response = Response::build_404(*this, request.get_full_url(), details); - return withTaskbarInfo(bookName, nullptr, std::move(response)); + const std::string searchURL = m_root + "/search?pattern=" + kiwix::urlEncode(pattern, true); + return HTTP404HtmlResponse(*this, request) + + urlNotFoundMsg + + searchSuggestionHTML(searchURL, kiwix::urlDecode(pattern)) + + TaskbarInfo(bookName); } auto urlStr = request.get_url().substr(bookName.size()+1); @@ -872,11 +873,11 @@ std::unique_ptr InternalServer::handle_content(const RequestContext& r if (m_verbose.load()) printf("Failed to find %s\n", urlStr.c_str()); - std::string searchURL = m_root + "/search?content=" + bookName + "&pattern=" + kiwix::urlEncode(pattern, true); // Make a search on this specific book only. - const std::string details = searchSuggestionHTML(searchURL, kiwix::urlDecode(pattern)); - - auto response = Response::build_404(*this, request.get_full_url(), details); - return withTaskbarInfo(bookName, archive.get(), std::move(response)); + std::string searchURL = m_root + "/search?content=" + bookName + "&pattern=" + kiwix::urlEncode(pattern, true); + return HTTP404HtmlResponse(*this, request) + + urlNotFoundMsg + + searchSuggestionHTML(searchURL, kiwix::urlDecode(pattern)) + + TaskbarInfo(bookName, archive.get()); } } @@ -899,7 +900,9 @@ std::unique_ptr InternalServer::handle_raw(const RequestContext& reque if (kind != "meta" && kind!= "content") { const std::string error_details = kind + " is not a valid request for raw content."; - return Response::build_404(*this, request.get_full_url(), error_details); + return HTTP404HtmlResponse(*this, request) + + urlNotFoundMsg + + error_details; } std::shared_ptr archive; @@ -936,7 +939,9 @@ std::unique_ptr InternalServer::handle_raw(const RequestContext& reque printf("Failed to find %s\n", itemPath.c_str()); } const std::string error_details = "Cannot find " + kind + " entry " + itemPath; - return Response::build_404(*this, request.get_full_url(), error_details); + return HTTP404HtmlResponse(*this, request) + + urlNotFoundMsg + + error_details; } } diff --git a/src/server/response.cpp b/src/server/response.cpp index e851015c3..180c378f3 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -84,31 +84,6 @@ std::unique_ptr Response::build_304(const InternalServer& server, cons return response; } -kainjow::mustache::data make404ResponseData(const std::string& url, const std::string& details) -{ - kainjow::mustache::list pList; - if ( !url.empty() ) { - kainjow::mustache::mustache msgTmpl(R"(The requested URL "{{url}}" was not found on this server.)"); - const auto urlNotFoundMsg = msgTmpl.render({"url", url}); - pList.push_back({"p", urlNotFoundMsg}); - } - pList.push_back({"p", details}); - return {"details", pList}; -} - -std::unique_ptr Response::build_404(const InternalServer& server, const std::string& url, const std::string& details) -{ - return build_404(server, make404ResponseData(url, details)); -} - -std::unique_ptr Response::build_404(const InternalServer& server, const kainjow::mustache::data& data) -{ - auto response = ContentResponse::build(server, RESOURCE::templates::_404_html, data, "text/html"); - response->set_code(MHD_HTTP_NOT_FOUND); - - return response; -} - const UrlNotFoundMsg urlNotFoundMsg; const InvalidUrlMsg invalidUrlMsg; diff --git a/src/server/response.h b/src/server/response.h index d46898923..7536a7af8 100644 --- a/src/server/response.h +++ b/src/server/response.h @@ -42,8 +42,6 @@ namespace kiwix { class InternalServer; class RequestContext; -class ContentResponse; - class Response { public: Response(bool verbose); @@ -51,8 +49,6 @@ class Response { static std::unique_ptr build(const InternalServer& server); static std::unique_ptr build_304(const InternalServer& server, const ETag& etag); - static std::unique_ptr build_404(const InternalServer& server, const kainjow::mustache::data& data); - static std::unique_ptr build_404(const InternalServer& server, const std::string& url, const std::string& details=""); static std::unique_ptr build_416(const InternalServer& server, size_t resourceLength); static std::unique_ptr build_500(const InternalServer& server, const std::string& msg); static std::unique_ptr build_redirect(const InternalServer& server, const std::string& redirectUrl); @@ -161,12 +157,6 @@ public: // functions virtual ~ContentResponseBlueprint() = default; - ContentResponseBlueprint& operator+(kainjow::mustache::data&& data) - { - this->m_data = std::move(data); - return *this; - } - operator std::unique_ptr() const { return generateResponseObject(); From f4059f3faf56b61818cd17c7767532a2a4f644db Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Sun, 30 Jan 2022 19:35:00 +0400 Subject: [PATCH 2/9] Got rid of withTaskbarInfo() --- src/server/internalServer.cpp | 6 ++++-- src/server/response.cpp | 16 ++++------------ src/server/response.h | 4 ---- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index 91e5d3ab4..1948f1cfb 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -593,7 +593,8 @@ std::unique_ptr InternalServer::handle_search(const RequestContext& re data.set("pattern", encodeDiples(searchInfo.pattern)); auto response = ContentResponse::build(*this, RESOURCE::templates::no_search_result_html, data, "text/html; charset=utf-8"); response->set_code(MHD_HTTP_NOT_FOUND); - return withTaskbarInfo(searchInfo.bookName, archive.get(), std::move(response)); + response->set_taskbar(searchInfo.bookName, archive.get()); + return response; } @@ -622,7 +623,8 @@ std::unique_ptr InternalServer::handle_search(const RequestContext& re renderer.setSearchProtocolPrefix(m_root + "/search?"); renderer.setPageLength(pageLength); auto response = ContentResponse::build(*this, renderer.getHtml(), "text/html; charset=utf-8"); - return withTaskbarInfo(searchInfo.bookName, archive.get(), std::move(response)); + response->set_taskbar(searchInfo.bookName, archive.get()); + return response; } catch (const std::invalid_argument& e) { return HTTP400HtmlResponse(*this, request) + invalidUrlMsg diff --git a/src/server/response.cpp b/src/server/response.cpp index 180c378f3..60f8caff5 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -91,9 +91,10 @@ std::unique_ptr ContentResponseBlueprint::generateResponseObjec { auto r = ContentResponse::build(m_server, m_template, m_data, m_mimeType); r->set_code(m_httpStatusCode); - return m_taskbarInfo - ? withTaskbarInfo(m_taskbarInfo->bookName, m_taskbarInfo->archive, std::move(r)) - : std::move(r); + if ( m_taskbarInfo ) { + r->set_taskbar(m_taskbarInfo->bookName, m_taskbarInfo->archive); + } + return r; } HTTP404HtmlResponse::HTTP404HtmlResponse(const InternalServer& server, @@ -442,15 +443,6 @@ std::unique_ptr ContentResponse::build( return ContentResponse::build(server, content, mimetype, isHomePage); } -std::unique_ptr withTaskbarInfo( - const std::string& bookName, - const zim::Archive* archive, - std::unique_ptr r) -{ - r->set_taskbar(bookName, archive); - return r; -} - ItemResponse::ItemResponse(bool verbose, const zim::Item& item, const std::string& mimetype, const ByteRange& byterange) : Response(verbose), m_item(item), diff --git a/src/server/response.h b/src/server/response.h index 7536a7af8..160798c96 100644 --- a/src/server/response.h +++ b/src/server/response.h @@ -136,10 +136,6 @@ struct TaskbarInfo {} }; -std::unique_ptr withTaskbarInfo(const std::string& bookName, - const zim::Archive* archive, - std::unique_ptr r); - class ContentResponseBlueprint { public: // functions From d8a60db7396afa09eba860a87af054ce88098ad2 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Sun, 23 Jan 2022 23:01:16 +0400 Subject: [PATCH 3/9] Preparing for a single error page template --- src/server/response.cpp | 6 +++++- static/templates/404.html | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/server/response.cpp b/src/server/response.cpp index 60f8caff5..608d616a1 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -106,7 +106,11 @@ HTTP404HtmlResponse::HTTP404HtmlResponse(const InternalServer& server, RESOURCE::templates::_404_html) { kainjow::mustache::list emptyList; - this->m_data = kainjow::mustache::object{{"details", emptyList}}; + this->m_data = kainjow::mustache::object{ + {"PAGE_TITLE", "Content not found"}, + {"PAGE_HEADING", "Not Found"}, + {"details", emptyList} + }; } HTTP404HtmlResponse& HTTP404HtmlResponse::operator+(UrlNotFoundMsg /*unused*/) diff --git a/static/templates/404.html b/static/templates/404.html index 795e8c9ef..5fcc0ff2c 100644 --- a/static/templates/404.html +++ b/static/templates/404.html @@ -2,10 +2,10 @@ - Content not found + {{PAGE_TITLE}} -

Not Found

+

{{PAGE_HEADING}}

{{#details}}

{{{p}}} From 647118dd5e18cd9e17aa43f3c34edc9c33f868a0 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Sun, 30 Jan 2022 16:40:16 +0400 Subject: [PATCH 4/9] Enter HTTPErrorHtmlResponse In addition to serving as a base class for `HTTP404HtmlResponse`, `HTTPErrorHtmlResponse` is going to be used for a couple of other error pages. --- src/server/response.cpp | 33 ++++++++++++++++++++++++--------- src/server/response.h | 20 ++++++++++++++++---- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/server/response.cpp b/src/server/response.cpp index 608d616a1..74d8ff9fd 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -97,30 +97,45 @@ std::unique_ptr ContentResponseBlueprint::generateResponseObjec return r; } -HTTP404HtmlResponse::HTTP404HtmlResponse(const InternalServer& server, - const RequestContext& request) +HTTPErrorHtmlResponse::HTTPErrorHtmlResponse(const InternalServer& server, + const RequestContext& request, + int httpStatusCode, + const std::string& templateStr, + const std::string& pageTitleMsg, + const std::string& headingMsg) : ContentResponseBlueprint(&server, &request, - MHD_HTTP_NOT_FOUND, - "text/html", - RESOURCE::templates::_404_html) + httpStatusCode, + "text/html; charset=utf-8", + templateStr) { kainjow::mustache::list emptyList; this->m_data = kainjow::mustache::object{ - {"PAGE_TITLE", "Content not found"}, - {"PAGE_HEADING", "Not Found"}, + {"PAGE_TITLE", pageTitleMsg}, + {"PAGE_HEADING", headingMsg}, {"details", emptyList} }; } -HTTP404HtmlResponse& HTTP404HtmlResponse::operator+(UrlNotFoundMsg /*unused*/) +HTTP404HtmlResponse::HTTP404HtmlResponse(const InternalServer& server, + const RequestContext& request) + : HTTPErrorHtmlResponse(server, + request, + MHD_HTTP_NOT_FOUND, + RESOURCE::templates::_404_html, + "Content not found", + "Not Found") +{ +} + +HTTPErrorHtmlResponse& HTTP404HtmlResponse::operator+(UrlNotFoundMsg /*unused*/) { const std::string requestUrl = m_request.get_full_url(); kainjow::mustache::mustache msgTmpl(R"(The requested URL "{{url}}" was not found on this server.)"); return *this + msgTmpl.render({"url", requestUrl}); } -HTTP404HtmlResponse& HTTP404HtmlResponse::operator+(const std::string& msg) +HTTPErrorHtmlResponse& HTTPErrorHtmlResponse::operator+(const std::string& msg) { m_data["details"].push_back({"p", msg}); return *this; diff --git a/src/server/response.h b/src/server/response.h index 160798c96..7481cbddc 100644 --- a/src/server/response.h +++ b/src/server/response.h @@ -179,18 +179,30 @@ public: //data std::unique_ptr m_taskbarInfo; }; +struct HTTPErrorHtmlResponse : ContentResponseBlueprint +{ + HTTPErrorHtmlResponse(const InternalServer& server, + const RequestContext& request, + int httpStatusCode, + const std::string& templateStr, + const std::string& pageTitleMsg, + const std::string& headingMsg); + + using ContentResponseBlueprint::operator+; + HTTPErrorHtmlResponse& operator+(const std::string& msg); +}; + class UrlNotFoundMsg {}; extern const UrlNotFoundMsg urlNotFoundMsg; -struct HTTP404HtmlResponse : ContentResponseBlueprint +struct HTTP404HtmlResponse : HTTPErrorHtmlResponse { HTTP404HtmlResponse(const InternalServer& server, const RequestContext& request); - using ContentResponseBlueprint::operator+; - HTTP404HtmlResponse& operator+(UrlNotFoundMsg /*unused*/); - HTTP404HtmlResponse& operator+(const std::string& errorDetails); + using HTTPErrorHtmlResponse::operator+; + HTTPErrorHtmlResponse& operator+(UrlNotFoundMsg /*unused*/); }; class InvalidUrlMsg {}; From 89dc9afc2887119c657cdcb5641244ece871e8d6 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Sun, 30 Jan 2022 16:49:00 +0400 Subject: [PATCH 5/9] Renamed 404.html to error.html 404.html no longer contains anything specific to the 404 error and will henceforth serve (with some enhancements) as a general purpose error page template. --- src/server/response.cpp | 4 +--- src/server/response.h | 1 - static/resources_list.txt | 2 +- static/templates/{404.html => error.html} | 0 4 files changed, 2 insertions(+), 5 deletions(-) rename static/templates/{404.html => error.html} (100%) diff --git a/src/server/response.cpp b/src/server/response.cpp index 74d8ff9fd..49caed531 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -100,14 +100,13 @@ std::unique_ptr ContentResponseBlueprint::generateResponseObjec HTTPErrorHtmlResponse::HTTPErrorHtmlResponse(const InternalServer& server, const RequestContext& request, int httpStatusCode, - const std::string& templateStr, const std::string& pageTitleMsg, const std::string& headingMsg) : ContentResponseBlueprint(&server, &request, httpStatusCode, "text/html; charset=utf-8", - templateStr) + RESOURCE::templates::error_html) { kainjow::mustache::list emptyList; this->m_data = kainjow::mustache::object{ @@ -122,7 +121,6 @@ HTTP404HtmlResponse::HTTP404HtmlResponse(const InternalServer& server, : HTTPErrorHtmlResponse(server, request, MHD_HTTP_NOT_FOUND, - RESOURCE::templates::_404_html, "Content not found", "Not Found") { diff --git a/src/server/response.h b/src/server/response.h index 7481cbddc..245c1396d 100644 --- a/src/server/response.h +++ b/src/server/response.h @@ -184,7 +184,6 @@ struct HTTPErrorHtmlResponse : ContentResponseBlueprint HTTPErrorHtmlResponse(const InternalServer& server, const RequestContext& request, int httpStatusCode, - const std::string& templateStr, const std::string& pageTitleMsg, const std::string& headingMsg); diff --git a/static/resources_list.txt b/static/resources_list.txt index ab583d7a6..c51f19acd 100644 --- a/static/resources_list.txt +++ b/static/resources_list.txt @@ -35,8 +35,8 @@ skin/block_external.js skin/search_results.css templates/search_result.html templates/no_search_result.html +templates/error.html templates/400.html -templates/404.html templates/500.html templates/index.html templates/suggestion.json diff --git a/static/templates/404.html b/static/templates/error.html similarity index 100% rename from static/templates/404.html rename to static/templates/error.html From 545d4091501263747209bcb7a414edb013e5aff0 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Tue, 29 Mar 2022 22:43:22 +0400 Subject: [PATCH 6/9] Reused HTTPErrorHtmlResponse in HTTP400HtmlResponse --- src/server/response.cpp | 21 ++++++--------------- src/server/response.h | 7 +++---- static/resources_list.txt | 1 - static/templates/400.html | 15 --------------- 4 files changed, 9 insertions(+), 35 deletions(-) delete mode 100644 static/templates/400.html diff --git a/src/server/response.cpp b/src/server/response.cpp index 49caed531..01b8bf97d 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -141,17 +141,15 @@ HTTPErrorHtmlResponse& HTTPErrorHtmlResponse::operator+(const std::string& msg) HTTP400HtmlResponse::HTTP400HtmlResponse(const InternalServer& server, const RequestContext& request) - : ContentResponseBlueprint(&server, - &request, - MHD_HTTP_BAD_REQUEST, - "text/html", - RESOURCE::templates::_400_html) + : HTTPErrorHtmlResponse(server, + request, + MHD_HTTP_BAD_REQUEST, + "Invalid request", + "Invalid request") { - kainjow::mustache::list emptyList; - this->m_data = kainjow::mustache::object{{"details", emptyList}}; } -HTTP400HtmlResponse& HTTP400HtmlResponse::operator+(InvalidUrlMsg /*unused*/) +HTTPErrorHtmlResponse& HTTP400HtmlResponse::operator+(InvalidUrlMsg /*unused*/) { std::string requestUrl = m_request.get_full_url(); const auto query = m_request.get_query(); @@ -162,13 +160,6 @@ HTTP400HtmlResponse& HTTP400HtmlResponse::operator+(InvalidUrlMsg /*unused*/) return *this + msgTmpl.render({"url", requestUrl}); } -HTTP400HtmlResponse& HTTP400HtmlResponse::operator+(const std::string& msg) -{ - m_data["details"].push_back({"p", msg}); - return *this; -} - - ContentResponseBlueprint& ContentResponseBlueprint::operator+(const TaskbarInfo& taskbarInfo) { this->m_taskbarInfo.reset(new TaskbarInfo(taskbarInfo)); diff --git a/src/server/response.h b/src/server/response.h index 245c1396d..f7546f269 100644 --- a/src/server/response.h +++ b/src/server/response.h @@ -208,14 +208,13 @@ class InvalidUrlMsg {}; extern const InvalidUrlMsg invalidUrlMsg; -struct HTTP400HtmlResponse : ContentResponseBlueprint +struct HTTP400HtmlResponse : HTTPErrorHtmlResponse { HTTP400HtmlResponse(const InternalServer& server, const RequestContext& request); - using ContentResponseBlueprint::operator+; - HTTP400HtmlResponse& operator+(InvalidUrlMsg /*unused*/); - HTTP400HtmlResponse& operator+(const std::string& errorDetails); + using HTTPErrorHtmlResponse::operator+; + HTTPErrorHtmlResponse& operator+(InvalidUrlMsg /*unused*/); }; class ItemResponse : public Response { diff --git a/static/resources_list.txt b/static/resources_list.txt index c51f19acd..258553a2a 100644 --- a/static/resources_list.txt +++ b/static/resources_list.txt @@ -36,7 +36,6 @@ skin/search_results.css templates/search_result.html templates/no_search_result.html templates/error.html -templates/400.html templates/500.html templates/index.html templates/suggestion.json diff --git a/static/templates/400.html b/static/templates/400.html deleted file mode 100644 index 5f4ecf42f..000000000 --- a/static/templates/400.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Invalid request - - -

Invalid request

-{{#details}} -

- {{{p}}} -

-{{/details}} - - From 2028bf3a984b7e96e04b26817443cc0e9535ad43 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Tue, 29 Mar 2022 23:18:29 +0400 Subject: [PATCH 7/9] Fixed the CI build failure under android_arm* --- src/server/internalServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index 1948f1cfb..dfa6a2403 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -594,7 +594,7 @@ std::unique_ptr InternalServer::handle_search(const RequestContext& re auto response = ContentResponse::build(*this, RESOURCE::templates::no_search_result_html, data, "text/html; charset=utf-8"); response->set_code(MHD_HTTP_NOT_FOUND); response->set_taskbar(searchInfo.bookName, archive.get()); - return response; + return std::move(response); } @@ -624,7 +624,7 @@ std::unique_ptr InternalServer::handle_search(const RequestContext& re renderer.setPageLength(pageLength); auto response = ContentResponse::build(*this, renderer.getHtml(), "text/html; charset=utf-8"); response->set_taskbar(searchInfo.bookName, archive.get()); - return response; + return std::move(response); } catch (const std::invalid_argument& e) { return HTTP400HtmlResponse(*this, request) + invalidUrlMsg From 2a20e873412f10d12142e41442384298b565f2ca Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Wed, 30 Mar 2022 20:05:37 +0400 Subject: [PATCH 8/9] Got rid of Response::build_500() This change is not tested (mostly due to the difficulties of triggering an internal server error). --- src/server/internalServer.cpp | 9 ++++--- src/server/internalServer.h | 2 -- src/server/response.cpp | 44 +++++++++++++++++++---------------- src/server/response.h | 12 +++++++++- static/resources_list.txt | 1 - static/templates/500.html | 16 ------------- 6 files changed, 41 insertions(+), 43 deletions(-) delete mode 100644 static/templates/500.html diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index dfa6a2403..05c2d559c 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -359,10 +359,12 @@ std::unique_ptr InternalServer::handle_request(const RequestContext& r return handle_content(request); } catch (std::exception& e) { fprintf(stderr, "===== Unhandled error : %s\n", e.what()); - return Response::build_500(*this, e.what()); + return HTTP500HtmlResponse(*this, request) + + e.what(); } catch (...) { fprintf(stderr, "===== Unhandled unknown error\n"); - return Response::build_500(*this, "Unknown error"); + return HTTP500HtmlResponse(*this, request) + + "Unknown error"; } } @@ -631,7 +633,8 @@ std::unique_ptr InternalServer::handle_search(const RequestContext& re + std::string(e.what()); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; - return Response::build_500(*this, e.what()); + return HTTP500HtmlResponse(*this, request) + + e.what(); } } diff --git a/src/server/internalServer.h b/src/server/internalServer.h index eb8dcc5cf..69e8166c4 100644 --- a/src/server/internalServer.h +++ b/src/server/internalServer.h @@ -177,8 +177,6 @@ class InternalServer { friend std::unique_ptr Response::build(const InternalServer& server); friend std::unique_ptr ContentResponse::build(const InternalServer& server, const std::string& content, const std::string& mimetype, bool isHomePage, bool raw); friend std::unique_ptr ItemResponse::build(const InternalServer& server, const RequestContext& request, const zim::Item& item, bool raw); - friend std::unique_ptr Response::build_500(const InternalServer& server, const std::string& msg); - }; } diff --git a/src/server/response.cpp b/src/server/response.cpp index 01b8bf97d..aefa0dc71 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -160,6 +160,30 @@ HTTPErrorHtmlResponse& HTTP400HtmlResponse::operator+(InvalidUrlMsg /*unused*/) return *this + msgTmpl.render({"url", requestUrl}); } +HTTP500HtmlResponse::HTTP500HtmlResponse(const InternalServer& server, + const RequestContext& request) + : HTTPErrorHtmlResponse(server, + request, + MHD_HTTP_INTERNAL_SERVER_ERROR, + "Internal Server Error", + "Internal Server Error") +{ + // operator+() is a state-modifying operator (akin to operator+=) + *this + "An internal server error occured. We are sorry about that :/"; +} + +std::unique_ptr HTTP500HtmlResponse::generateResponseObject() const +{ + // We want a 500 response to be a minimalistic one (so that the server doesn't + // have to provide additional resources required for its proper rendering) + // ";raw=true" in the MIME-type below disables response decoration + // (see ContentResponse::contentDecorationAllowed()) + const std::string mimeType = "text/html;charset=utf-8;raw=true"; + auto r = ContentResponse::build(m_server, m_template, m_data, mimeType); + r->set_code(m_httpStatusCode); + return r; +} + ContentResponseBlueprint& ContentResponseBlueprint::operator+(const TaskbarInfo& taskbarInfo) { this->m_taskbarInfo.reset(new TaskbarInfo(taskbarInfo)); @@ -179,26 +203,6 @@ std::unique_ptr Response::build_416(const InternalServer& server, size return response; } -std::unique_ptr Response::build_500(const InternalServer& server, const std::string& msg) -{ - MustacheData data; - data.set("error", msg); - auto content = render_template(RESOURCE::templates::_500_html, data); - std::unique_ptr response ( - new ContentResponse( - server.m_root, //root - true, //verbose - true, //raw - false, //withTaskbar - false, //withLibraryButton - false, //blockExternalLinks - content, //content - "text/html" //mimetype - )); - response->set_code(MHD_HTTP_INTERNAL_SERVER_ERROR); - return response; -} - std::unique_ptr Response::build_redirect(const InternalServer& server, const std::string& redirectUrl) { diff --git a/src/server/response.h b/src/server/response.h index f7546f269..710e2bc0f 100644 --- a/src/server/response.h +++ b/src/server/response.h @@ -50,7 +50,6 @@ class Response { static std::unique_ptr build(const InternalServer& server); static std::unique_ptr build_304(const InternalServer& server, const ETag& etag); static std::unique_ptr build_416(const InternalServer& server, size_t resourceLength); - static std::unique_ptr build_500(const InternalServer& server, const std::string& msg); static std::unique_ptr build_redirect(const InternalServer& server, const std::string& redirectUrl); MHD_Result send(const RequestContext& request, MHD_Connection* connection); @@ -217,6 +216,17 @@ struct HTTP400HtmlResponse : HTTPErrorHtmlResponse HTTPErrorHtmlResponse& operator+(InvalidUrlMsg /*unused*/); }; +struct HTTP500HtmlResponse : HTTPErrorHtmlResponse +{ + HTTP500HtmlResponse(const InternalServer& server, + const RequestContext& request); + +private: // overrides + // generateResponseObject() is overriden in order to produce a minimal + // response without any need for additional resources from the server + std::unique_ptr generateResponseObject() const override; +}; + class ItemResponse : public Response { public: ItemResponse(bool verbose, const zim::Item& item, const std::string& mimetype, const ByteRange& byterange); diff --git a/static/resources_list.txt b/static/resources_list.txt index 258553a2a..7444c48ae 100644 --- a/static/resources_list.txt +++ b/static/resources_list.txt @@ -36,7 +36,6 @@ skin/search_results.css templates/search_result.html templates/no_search_result.html templates/error.html -templates/500.html templates/index.html templates/suggestion.json templates/head_taskbar.html diff --git a/static/templates/500.html b/static/templates/500.html deleted file mode 100644 index 1b2692d5f..000000000 --- a/static/templates/500.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Internal Server Error - - -

Internal Server Error

-

- An internal server error occured. We are sorry about that :/ -

-

- {{ error }} -

- - From 3f41ce833785eef319638da87ac53e92001d417e Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Sun, 3 Apr 2022 17:29:51 +0400 Subject: [PATCH 9/9] Unit test for HTTP 500 Internal Server Error Currently an internal server error can be triggered by accessing an entry belonging to a redirect loop. The ZIM file (test/data/poor.zim) containing such a loop was copied from openzim/zim-tools repository (test/data/zimfiles/poor.zim). --- test/data/poor.zim | Bin 0 -> 65186 bytes test/meson.build | 1 + test/server.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 test/data/poor.zim diff --git a/test/data/poor.zim b/test/data/poor.zim new file mode 100644 index 0000000000000000000000000000000000000000..b30d77a189ab99ab637b360a10dbf44efa02bf27 GIT binary patch literal 65186 zcmeHw2UrwI*Y1$9Q4v>E42-S;SCOc=n6sdQh^#0kCc?78SFug1Y7` z>WT>?qGDLV956@L9PfLoM_qTn@4Nfl|GD@6|MN6dopUOks(QQXbXE0CPfTc-y@SL? z^4Gu0h_Hn(d@rOFy%zYW4+4)6nB=4NZ@M*JW-w?q3Yl5M>wS5JS!Hf)G8+bHCKiqX-_D2SUPKtYYe`wN$ z{>|FAC^oDv6T4>nT+dc+=_g)ukG|=1KJ4VvO!w65y^K4xeAR<1uj@bTEq6RB&uE!D z%Cz&@v6Owa?gcqN9o9DY@NT

)VCL?7e+`){ABzve(Z@8}Kqb{BF~aM@K(6YO}TO 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 r7ii_(tz2&9=~lkk%9&L{k-c + + + + Internal Server Error + + +

Internal Server Error

+

+ An internal server error occured. We are sorry about that :/ +

+

+ Entry redirect_loop.html is a redirect entry. +

+ + +)"; + + const auto r = zfs1_->GET("/ROOT/poor/A/redirect_loop.html"); + EXPECT_EQ(r->status, 500); + EXPECT_EQ(r->body, expectedBody); +} + TEST_F(ServerTest, RandomPageRedirectsToAnExistingArticle) { auto g = zfs1_->GET("/ROOT/random?content=zimfile");