diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index 611f36fc..d1d4f2a0 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -1121,15 +1121,6 @@ InternalServer::search_catalog(const RequestContext& request, namespace { -ParameterizedMessage suggestSearchMsg(const std::string& searchURL, const std::string& pattern) -{ - return ParameterizedMessage("suggest-search", - { - { "PATTERN", pattern }, - { "SEARCH_URL", searchURL } - }); -} - /////////////////////////////////////////////////////////////////////////////// // The content security policy below is set on responses to the /content // endpoint in order to prevent the ZIM content from interfering with the @@ -1183,9 +1174,7 @@ std::unique_ptr InternalServer::handle_content(const RequestContext& r } catch (const std::out_of_range& e) {} if (archive == nullptr) { - const std::string searchURL = m_root + "/search?pattern=" + kiwix::urlEncode(pattern); - return UrlNotFoundResponse(request) - + suggestSearchMsg(searchURL, kiwix::urlDecode(pattern)); + return NewHTTP404Response(request, m_root, m_root + url); } const std::string archiveUuid(archive->getUuid()); @@ -1230,9 +1219,7 @@ 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); - return UrlNotFoundResponse(request) - + suggestSearchMsg(searchURL, kiwix::urlDecode(pattern)); + return NewHTTP404Response(request, m_root, m_root + url); } } diff --git a/src/server/response.cpp b/src/server/response.cpp index 7520ab1c..87de940c 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -368,6 +368,21 @@ std::unique_ptr ContentResponseBlueprint::generateResponseObjec return r; } +NewHTTP404Response::NewHTTP404Response(const RequestContext& request, + const std::string& root, + const std::string& urlPath) + : ContentResponseBlueprint(&request, + MHD_HTTP_NOT_FOUND, + "text/html; charset=utf-8", + RESOURCE::templates::sexy404_html, + /*includeKiwixResponseData=*/false) +{ + *this->m_data = Data(Data::Object{ + {"root", root }, + {"url_path", urlPath} + }); +} + HTTPErrorResponse::HTTPErrorResponse(const RequestContext& request, int httpStatusCode, const std::string& pageTitleMsgId, diff --git a/src/server/response.h b/src/server/response.h index b4c9925f..47fb5851 100644 --- a/src/server/response.h +++ b/src/server/response.h @@ -145,6 +145,13 @@ protected: //data std::unique_ptr m_data; }; +struct NewHTTP404Response : ContentResponseBlueprint +{ + NewHTTP404Response(const RequestContext& request, + const std::string& root, + const std::string& urlPath); +}; + struct HTTPErrorResponse : ContentResponseBlueprint { HTTPErrorResponse(const RequestContext& request, diff --git a/static/resources_list.txt b/static/resources_list.txt index faa53cb3..702918fc 100644 --- a/static/resources_list.txt +++ b/static/resources_list.txt @@ -1,6 +1,7 @@ skin/caret.png skin/bittorrent.png skin/magnet.png +skin/404.svg skin/feed.svg skin/langSelector.svg skin/download.png @@ -11,9 +12,11 @@ skin/iso6391To3.js skin/isotope.pkgd.min.js skin/index.js skin/autoComplete/autoComplete.min.js +skin/error.css skin/kiwix.css skin/taskbar.css skin/index.css +skin/fonts/DMSans-Regular.ttf skin/fonts/Poppins.ttf skin/fonts/Roboto.ttf skin/search_results.css @@ -42,6 +45,7 @@ templates/url_of_search_results_css.tmpl templates/viewer_settings.js templates/no_js_library_page.html templates/no_js_download.html +templates/sexy404.html opensearchdescription.xml ft_opensearchdescription.xml catalog_v2_searchdescription.xml diff --git a/static/skin/404.svg b/static/skin/404.svg new file mode 100644 index 00000000..bd9ea641 --- /dev/null +++ b/static/skin/404.svg @@ -0,0 +1 @@ + diff --git a/static/skin/error.css b/static/skin/error.css new file mode 100644 index 00000000..8db79f71 --- /dev/null +++ b/static/skin/error.css @@ -0,0 +1,153 @@ +@font-face { + font-family:"DM Sans"; + font-style: normal; + font-weight: 400; + src : url('../skin/fonts/DMSans-Regular.ttf?KIWIXCACHEID'); +} +@font-face { + font-family:"DM Sans Bold"; + font-style: normal; + font-weight: 700; + src : url('../skin/fonts/DMSans-Regular.ttf?KIWIXCACHEID'); +} + +body { + background: linear-gradient(to bottom right, #ffffff, #e6e6e6); + background-repeat: no-repeat; + background-attachment: fixed; +} + +header { + width: 100%; + margin: auto; + text-align: center; + + margin-top: 15%; + margin-bottom: 15%; +} + +header img { + width: 60%; + min-width: 200px; + max-width: 500px; + max-height: 300px; +} + +section { + display: flex; + flex-direction: column; + align-items: center; +} + +header, .intro { + font-family: "DM Sans"; +} + +.intro { + font-size: 1em; + padding: 0 10%; + line-height: 1.2em; + text-align: center; +} + +.intro h1 { + line-height: 1.1em; + font-family: "DM Sans Bold"; + font-size: 1.2em; +} + +.intro code { + font-family: monospace; + font-size: 1.1em; + word-break: break-all; +} + +.advice { + width: 80%; + margin: auto; + margin-bottom: 15%; + margin-top: 5em; + + background-color: #ffffff; + border-radius: 1rem; + border: 1px solid #b7b7b7; + + padding: 2em; + + font-family: "DM Sans"; + font-size: .9em; + box-sizing: border-box; + + align-items: normal; +} + +.advice p { + margin-bottom: 1em; +} + +.advice p:first-child { + margin-top: 0; +} + +.advice p.list-intro { + margin: 0; +} + +.advice ul { + list-style-type: square; + margin: 0; + padding: 0 1em; +} + +.advice ul li { + line-height: 2em; +} + +.advice p:last-child { + margin-bottom: 0; +} + + +/* sm: 640px+ */ +@media (width >= 40rem) { + header { + margin-bottom: 1em; + margin-top: 5em; + } + + header img { + width: 50%; + } + + .intro h1 { + font-size: 2em; + } + + .advice { + width: 50%; + } +} + +/* xl: 1280px+ */ +@media (width >= 80rem) { + .intro h1 { + font-size: 3.4em; + } +} + +/* 2xl: 1536px+ */ +@media (width >= 96rem) { + header img { + width: 25%; + min-width: 200px; + max-width: 500px; + max-height: 300px; + } + + .advice { + width: 25%; + min-width: 200px; + min-width: 300px; + max-width: 500px; + } +} diff --git a/static/skin/fonts/DMSans-Regular.ttf b/static/skin/fonts/DMSans-Regular.ttf new file mode 100644 index 00000000..c672f980 Binary files /dev/null and b/static/skin/fonts/DMSans-Regular.ttf differ diff --git a/static/templates/sexy404.html b/static/templates/sexy404.html new file mode 100644 index 00000000..17be51ec --- /dev/null +++ b/static/templates/sexy404.html @@ -0,0 +1,31 @@ + + + + + + Page not found + + + +
+ Not found! +
+
+

Oops. Page not found.

+

The requested path was not found:

+

{{url_path}}

+
+
+

The content you're looking for may still be available, but it might be located at a different place within the ZIM file.

+

Please:

+
    +
  • Try using the search function to find the content you want
  • +
  • Look for keywords or titles related to the information you're seeking
  • +
+

This approach should help you locate the desired content, even if the original link isn't working properly.

+
+ + diff --git a/test/server.cpp b/test/server.cpp index e5c85a20..3966e36f 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -58,6 +58,8 @@ const ResourceCollection resources200Compressible{ { STATIC_CONTENT, "/ROOT%23%3F/skin/autoComplete/autoComplete.min.js?cacheid=1191aaaf" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/autoComplete/css/autoComplete.css" }, { STATIC_CONTENT, "/ROOT%23%3F/skin/autoComplete/css/autoComplete.css?cacheid=f2d376c4" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/error.css" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/error.css?cacheid=c49d1586" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/i18n.js" }, { STATIC_CONTENT, "/ROOT%23%3F/skin/i18n.js?cacheid=071abc9a" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/index.css" }, @@ -106,6 +108,8 @@ const ResourceCollection resources200Compressible{ }; const ResourceCollection resources200Uncompressible{ + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/404.svg" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/404.svg?cacheid=b6d648af" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/bittorrent.png" }, { STATIC_CONTENT, "/ROOT%23%3F/skin/bittorrent.png?cacheid=4f5c6882" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/blank.html" }, @@ -339,6 +343,12 @@ R"EXPECTEDRESULT( +