From b151a2a480a664866ddc5eaf75087b364ca28468 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Tue, 9 Jan 2024 21:59:53 +0400 Subject: [PATCH] Added KIWIX_RESPONSE_DATA to error response Now the data used to generate an error response can be made to be embedded in the response as a JS object KIWIX_RESPONSE_DATA. --- src/server/response.cpp | 50 ++++++++++++++++++++++++++++++++++--- src/server/response.h | 7 ++++-- static/templates/error.html | 4 ++- test/response.cpp | 12 +++++++-- 4 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/server/response.cpp b/src/server/response.cpp index 53584349b..efb72a9c9 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -195,6 +195,9 @@ public: }; } + std::string asJSON() const; + void dumpJSON(std::ostream& os) const; + private: bool isString() const { return std::holds_alternative(data); } bool isList() const { return std::holds_alternative(data); } @@ -248,15 +251,51 @@ MustacheData ContentResponseBlueprint::Data::toMustache(const std::string& lang) } } +void ContentResponseBlueprint::Data::dumpJSON(std::ostream& os) const +{ + if ( this->isString() ) { + os << '"' << escapeForJSON(this->stringValue()) << '"'; + } else if ( this->isList() ) { + const char * sep = " "; + os << "["; + + for ( const auto& x : this->listValue() ) { + os << sep; + x.dumpJSON(os); + sep = ", "; + } + os << " ]"; + } else if ( this->isObject() ) { + const char * sep = " "; + os << "{"; + for ( const auto& kv : this->objectValue() ) { + os << sep << '"' << kv.first << "\" : "; + kv.second.dumpJSON(os); + sep = ", "; + } + os << " }"; + } else { + os << (this->boolValue() ? "true" : "false"); + } +} + +std::string ContentResponseBlueprint::Data::asJSON() const +{ + std::ostringstream oss; + this->dumpJSON(oss); + return oss.str(); +} ContentResponseBlueprint::ContentResponseBlueprint(const RequestContext* request, int httpStatusCode, const std::string& mimeType, - const std::string& templateStr) + const std::string& templateStr, + bool includeKiwixResponseData) : m_request(*request) , m_httpStatusCode(httpStatusCode) , m_mimeType(mimeType) , m_template(templateStr) + , m_includeKiwixResponseData(includeKiwixResponseData) , m_data(new Data) {} @@ -265,6 +304,9 @@ ContentResponseBlueprint::~ContentResponseBlueprint() = default; std::unique_ptr ContentResponseBlueprint::generateResponseObject() const { kainjow::mustache::data d = m_data->toMustache(m_request.get_user_language()); + if ( m_includeKiwixResponseData ) { + d.set("KIWIX_RESPONSE_DATA", m_data->asJSON()); + } auto r = ContentResponse::build(m_template, d, m_mimeType); r->set_code(m_httpStatusCode); return r; @@ -274,11 +316,13 @@ HTTPErrorResponse::HTTPErrorResponse(const RequestContext& request, int httpStatusCode, const std::string& pageTitleMsgId, const std::string& headingMsgId, - const std::string& cssUrl) + const std::string& cssUrl, + bool includeKiwixResponseData) : ContentResponseBlueprint(&request, httpStatusCode, request.get_requested_format() == "html" ? "text/html; charset=utf-8" : "application/xml; charset=utf-8", - request.get_requested_format() == "html" ? RESOURCE::templates::error_html : RESOURCE::templates::error_xml) + request.get_requested_format() == "html" ? RESOURCE::templates::error_html : RESOURCE::templates::error_xml, + includeKiwixResponseData) { Data::List emptyList; *this->m_data = Data(Data::Object{ diff --git a/src/server/response.h b/src/server/response.h index e239173df..11808f0da 100644 --- a/src/server/response.h +++ b/src/server/response.h @@ -121,7 +121,8 @@ public: // functions ContentResponseBlueprint(const RequestContext* request, int httpStatusCode, const std::string& mimeType, - const std::string& templateStr); + const std::string& templateStr, + bool includeKiwixResponseData = false); ~ContentResponseBlueprint(); @@ -140,6 +141,7 @@ protected: //data const int m_httpStatusCode; const std::string m_mimeType; const std::string m_template; + const bool m_includeKiwixResponseData; std::unique_ptr m_data; }; @@ -149,7 +151,8 @@ struct HTTPErrorResponse : ContentResponseBlueprint int httpStatusCode, const std::string& pageTitleMsgId, const std::string& headingMsgId, - const std::string& cssUrl = ""); + const std::string& cssUrl = "", + bool includeKiwixResponseData = false); HTTPErrorResponse& operator+(const ParameterizedMessage& errorDetails); HTTPErrorResponse& operator+=(const ParameterizedMessage& errorDetails); diff --git a/static/templates/error.html b/static/templates/error.html index 711082096..717e56b27 100644 --- a/static/templates/error.html +++ b/static/templates/error.html @@ -5,7 +5,9 @@ {{PAGE_TITLE}} {{#CSS_URL}} -{{/CSS_URL}} +{{/CSS_URL}}{{#KIWIX_RESPONSE_DATA}} {{/KIWIX_RESPONSE_DATA}}

{{PAGE_HEADING}}

diff --git a/test/response.cpp b/test/response.cpp index cbfbfd3d7..5b9d8c92a 100644 --- a/test/response.cpp +++ b/test/response.cpp @@ -29,7 +29,8 @@ TEST(HTTPErrorResponse, shouldBeInEnglishByDefault) { HTTPErrorResponse errResp(req, MHD_HTTP_NOT_FOUND, "404-page-title", "404-page-heading", - "/css/error.css"); + "/css/error.css", + /*includeKiwixResponseData=*/true); EXPECT_EQ(getResponseContent(errResp), R"( @@ -38,6 +39,9 @@ R"( Content not found +

Not Found

@@ -56,7 +60,8 @@ TEST(HTTPErrorResponse, shouldBeTranslatable) { HTTPErrorResponse errResp(req, MHD_HTTP_NOT_FOUND, "404-page-title", "404-page-heading", - "/css/error.css"); + "/css/error.css", + /*includeKiwixResponseData=*/true); EXPECT_EQ(getResponseContent(errResp), R"( @@ -65,6 +70,9 @@ R"( [I18N TESTING] Not Found - Try Again +

[I18N TESTING] Content not found, but at least the server is alive