Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translation of error pages #1032

Merged
merged 28 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3f0ea08
Moved microhttpd_wrapper.h under server/
veloman-yunkan Dec 5, 2023
96b6f41
Added i18n unit test
veloman-yunkan Jan 7, 2024
8993f99
ParameterizedMessage is actually a class
veloman-yunkan Jan 7, 2024
b9323f1
Introduced testing of HTTP response utils
veloman-yunkan Dec 5, 2023
af228bf
Dropped cookies from RequestContext
veloman-yunkan Dec 5, 2023
aee6c23
Decoupled RequestContext from MHD_Connection
veloman-yunkan Dec 5, 2023
c57b8a0
Testing of HTTPErrorResponse translation
veloman-yunkan Dec 5, 2023
797f4c4
Testing of MIME-type of HTTP 500 response
veloman-yunkan Dec 6, 2023
54191bc
Retired HTTP500Response::generateResponseObject()
veloman-yunkan Dec 6, 2023
0b7cd61
Fixed an encapsulation breach
veloman-yunkan Dec 6, 2023
d39e91f
Moved constructor into .cpp
veloman-yunkan Jan 9, 2024
e72fc23
Enter ContentResponseBlueprint::Data
veloman-yunkan Jan 9, 2024
0b542fe
New implementation of ContentResponseBlueprint::Data
veloman-yunkan Dec 6, 2023
f298acd
Unmustached i18n::Parameters
veloman-yunkan Jan 9, 2024
1553d52
Lazy translation during error response generation
veloman-yunkan Jan 9, 2024
f3d3ab1
Exposed escapeForJSON() in kiwix namespace
veloman-yunkan Jan 9, 2024
8b8a2ee
Slight enhancement of escapeForJSON()
veloman-yunkan Jan 6, 2024
b151a2a
Added KIWIX_RESPONSE_DATA to error response
veloman-yunkan Jan 9, 2024
d2fedf9
Added error details in testing of error responses
veloman-yunkan Jan 5, 2024
e14de69
The page template is embedded in the error response
veloman-yunkan Jan 6, 2024
bceba4d
HTML-template data is HTML-encoded
veloman-yunkan Jan 6, 2024
103a451
Demo of error page translation
veloman-yunkan Jan 6, 2024
e1f067c
Undid the demo of frontend-side error page translation
veloman-yunkan Jan 7, 2024
bb1a730
Workaround for missing support for of std::variant
veloman-yunkan Jan 13, 2024
13a6863
Enabled frontend-side translation of 500 error page
veloman-yunkan Jan 17, 2024
30b3f05
All kiwix-serve errors are now frontend-translatable
veloman-yunkan Jan 17, 2024
1f9026f
"</script>" inside KIWIX_RESPONSE_DATA is bad
veloman-yunkan Jan 25, 2024
dc3960c
Fix against a malicious "</script>" in KIWIX_RESPONSE_DATA
veloman-yunkan Jan 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/server/i18n.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,12 @@ std::string expandParameterizedString(const std::string& lang,
const std::string& key,
const Parameters& params)
{
kainjow::mustache::object mustacheParams;
for( const auto& kv : params ) {
mustacheParams[kv.first] = kv.second;
}
const std::string tmpl = getTranslatedString(lang, key);
return render_template(tmpl, params);
return render_template(tmpl, mustacheParams);
}

} // namespace i18n
Expand Down
10 changes: 7 additions & 3 deletions src/server/i18n.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#ifndef KIWIX_SERVER_I18N
#define KIWIX_SERVER_I18N

#include <map>
#include <string>
#include <mustache.hpp>

Expand All @@ -44,7 +45,7 @@ std::string getTranslatedString(const std::string& lang, const std::string& key)
namespace i18n
{

typedef kainjow::mustache::object Parameters;
typedef std::map<std::string, std::string> Parameters;

std::string expandParameterizedString(const std::string& lang,
const std::string& key,
Expand Down Expand Up @@ -93,10 +94,10 @@ class GetTranslatedStringWithMsgId

} // namespace i18n

struct ParameterizedMessage
class ParameterizedMessage
{
public: // types
typedef kainjow::mustache::object Parameters;
typedef i18n::Parameters Parameters;

public: // functions
ParameterizedMessage(const std::string& msgId, const Parameters& params)
Expand All @@ -106,6 +107,9 @@ struct ParameterizedMessage

std::string getText(const std::string& lang) const;

const std::string& getMsgId() const { return msgId; }
const Parameters& getParams() const { return params; }

private: // data
const std::string msgId;
const Parameters params;
Expand Down
21 changes: 19 additions & 2 deletions src/server/internalServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,19 @@ static MHD_Result staticHandlerCallback(void* cls,
cont_cls);
}

namespace
{

MHD_Result add_name_value_pair(void *nvp, enum MHD_ValueKind kind,
const char *key, const char *value)
{
auto& nameValuePairs = *reinterpret_cast<RequestContext::NameValuePairs*>(nvp);
nameValuePairs.push_back({key, value});
return MHD_YES;
}

} // unnamed namespace

MHD_Result InternalServer::handlerCallback(struct MHD_Connection* connection,
const char* fullUrl,
const char* method,
Expand All @@ -529,7 +542,10 @@ MHD_Result InternalServer::handlerCallback(struct MHD_Connection* connection,
}

const auto url = fullURL2LocalURL(fullUrl, m_rootPrefixOfDecodedURL);
RequestContext request(connection, m_root, url, method, version);
RequestContext::NameValuePairs headers, queryArgs;
MHD_get_connection_values(connection, MHD_HEADER_KIND, add_name_value_pair, &headers);
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, add_name_value_pair, &queryArgs);
RequestContext request(m_root, url, method, version, headers, queryArgs);

if (m_verbose.load() ) {
request.print_debug_info();
Expand Down Expand Up @@ -926,7 +942,8 @@ std::unique_ptr<Response> InternalServer::handle_search_request(const RequestCon
HTTPErrorResponse response(request, MHD_HTTP_NOT_FOUND,
"fulltext-search-unavailable",
"404-page-heading",
cssUrl);
cssUrl,
/*includeKiwixResponseData=*/true);
response += nonParameterizedMessage("no-search-results");
// XXX: Now this has to be handled by the iframe-based viewer which
// XXX: has to resolve if the book selection resulted in a single book.
Expand Down
File renamed without changes.
38 changes: 15 additions & 23 deletions src/server/request_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@ RequestMethod str2RequestMethod(const std::string& method) {

} // unnamed namespace

RequestContext::RequestContext(struct MHD_Connection* connection,
const std::string& _rootLocation, // URI-encoded
RequestContext::RequestContext(const std::string& _rootLocation, // URI-encoded
const std::string& unrootedUrl, // URI-decoded
const std::string& _method,
const std::string& version) :
const std::string& version,
const NameValuePairs& headers,
const NameValuePairs& queryArgs) :
rootLocation(_rootLocation),
url(unrootedUrl),
method(str2RequestMethod(_method)),
Expand All @@ -64,9 +65,13 @@ RequestContext::RequestContext(struct MHD_Connection* connection,
acceptEncodingGzip(false),
byteRange_()
{
MHD_get_connection_values(connection, MHD_HEADER_KIND, &RequestContext::fill_header, this);
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &RequestContext::fill_argument, this);
MHD_get_connection_values(connection, MHD_COOKIE_KIND, &RequestContext::fill_cookie, this);
for ( const auto& kv : headers ) {
add_header(kv.first, kv.second);
}

for ( const auto& kv : queryArgs ) {
add_argument(kv.first, kv.second);
}

try {
acceptEncodingGzip =
Expand All @@ -83,18 +88,14 @@ RequestContext::RequestContext(struct MHD_Connection* connection,
RequestContext::~RequestContext()
{}

MHD_Result RequestContext::fill_header(void *__this, enum MHD_ValueKind kind,
const char *key, const char *value)
void RequestContext::add_header(const char *key, const char *value)
{
RequestContext *_this = static_cast<RequestContext*>(__this);
_this->headers[lcAll(key)] = value;
return MHD_YES;
this->headers[lcAll(key)] = value;
}

MHD_Result RequestContext::fill_argument(void *__this, enum MHD_ValueKind kind,
const char *key, const char* value)
void RequestContext::add_argument(const char *key, const char* value)
{
RequestContext *_this = static_cast<RequestContext*>(__this);
RequestContext *_this = this;
_this->arguments[key].push_back(value == nullptr ? "" : value);
if ( ! _this->queryString.empty() ) {
_this->queryString += "&";
Expand All @@ -104,15 +105,6 @@ MHD_Result RequestContext::fill_argument(void *__this, enum MHD_ValueKind kind,
_this->queryString += "=";
_this->queryString += urlEncode(value);
}
return MHD_YES;
}

MHD_Result RequestContext::fill_cookie(void *__this, enum MHD_ValueKind kind,
const char *key, const char* value)
{
RequestContext *_this = static_cast<RequestContext*>(__this);
_this->cookies[key] = value == nullptr ? "" : value;
return MHD_YES;
}

void RequestContext::print_debug_info() const {
Expand Down
19 changes: 11 additions & 8 deletions src/server/request_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include <stdexcept>

#include "byte_range.h"
#include "tools/stringTools.h"
#include "../tools/stringTools.h"

extern "C" {
#include "microhttpd_wrapper.h"
Expand All @@ -55,12 +55,17 @@ class IndexError: public std::runtime_error {};


class RequestContext {
public: // types
typedef std::vector<std::pair<const char*, const char*>> NameValuePairs;

public: // functions
RequestContext(struct MHD_Connection* connection,
const std::string& rootLocation, // URI-encoded
RequestContext(const std::string& rootLocation, // URI-encoded
const std::string& unrootedUrl, // URI-decoded
const std::string& method,
const std::string& version);
const std::string& version,
const NameValuePairs& headers,
const NameValuePairs& queryArgs);

~RequestContext();

void print_debug_info() const;
Expand Down Expand Up @@ -145,16 +150,14 @@ class RequestContext {
ByteRange byteRange_;
std::map<std::string, std::string> headers;
std::map<std::string, std::vector<std::string>> arguments;
std::map<std::string, std::string> cookies;
std::string queryString;
UserLanguage userlang;

private: // functions
UserLanguage determine_user_language() const;

static MHD_Result fill_header(void *, enum MHD_ValueKind, const char*, const char*);
static MHD_Result fill_cookie(void *, enum MHD_ValueKind, const char*, const char*);
static MHD_Result fill_argument(void *, enum MHD_ValueKind, const char*, const char*);
void add_header(const char* name, const char* value);
void add_argument(const char* name, const char* value);
};

template<> std::string RequestContext::get_argument(const std::string& name) const;
Expand Down
Loading
Loading