diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index 8548d4245..b50c6e650 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -94,6 +94,17 @@ inline std::string normalizeRootUrl(std::string rootUrl) return rootUrl.empty() ? rootUrl : "/" + rootUrl; } +std::string +fullURL2LocalURL(const std::string& fullUrl, const std::string& rootLocation) +{ + assert(rootLocation.size() > 0 && rootLocation.back() == '/'); + if ( kiwix::startsWith(fullUrl, rootLocation) ) { + return fullUrl.substr(rootLocation.size() - 1); + } else { + return ""; + } +} + Filter get_search_filter(const RequestContext& request, const std::string& prefix="") { auto filter = kiwix::Filter().valid(true).local(true); @@ -404,6 +415,7 @@ InternalServer::InternalServer(Library* library, m_addr(addr), m_port(port), m_root(normalizeRootUrl(root)), + m_rootPrefixOfDecodedURL(m_root + "/"), m_nbThreads(nbThreads), m_multizimSearchLimit(multizimSearchLimit), m_verbose(verbose), @@ -418,7 +430,9 @@ InternalServer::InternalServer(Library* library, searchCache(getEnvVar("KIWIX_SEARCH_CACHE_SIZE", DEFAULT_CACHE_SIZE)), suggestionSearcherCache(getEnvVar("KIWIX_SUGGESTION_SEARCHER_CACHE_SIZE", std::max((unsigned int) (mp_library->getBookCount(true, true)*0.1), 1U))), m_customizedResources(new CustomizedResources) -{} +{ + m_root = urlEncode(m_root); +} InternalServer::~InternalServer() = default; @@ -494,7 +508,7 @@ static MHD_Result staticHandlerCallback(void* cls, } MHD_Result InternalServer::handlerCallback(struct MHD_Connection* connection, - const char* url, + const char* fullUrl, const char* method, const char* version, const char* upload_data, @@ -505,8 +519,10 @@ MHD_Result InternalServer::handlerCallback(struct MHD_Connection* connection, if (m_verbose.load() ) { printf("======================\n"); printf("Requesting : \n"); - printf("full_url : %s\n", url); + printf("full_url : %s\n", fullUrl); } + + const auto url = fullURL2LocalURL(fullUrl, m_rootPrefixOfDecodedURL); RequestContext request(connection, m_root, url, method, version); if (m_verbose.load() ) { @@ -527,7 +543,7 @@ MHD_Result InternalServer::handlerCallback(struct MHD_Connection* connection, printf("========== INTERNAL ERROR !! ============\n"); if (!m_verbose.load()) { printf("Requesting : \n"); - printf("full_url : %s\n", url); + printf("full_url : %s\n", fullUrl); request.print_debug_info(); } } @@ -607,7 +623,7 @@ std::unique_ptr InternalServer::handle_request(const RequestContext& r if (isEndpointUrl(url, "catch")) return handle_catch(request); - std::string contentUrl = m_root + "/content" + url; + std::string contentUrl = m_root + "/content" + urlEncode(url); const std::string query = request.get_query(); if ( ! query.empty() ) contentUrl += "?" + query; @@ -1030,9 +1046,9 @@ ParameterizedMessage suggestSearchMsg(const std::string& searchURL, const std::s std::unique_ptr InternalServer::build_redirect(const std::string& bookName, const zim::Item& item) const { - const auto path = kiwix::urlEncode(item.getPath()); - const auto redirectUrl = m_root + "/content/" + bookName + "/" + path; - return Response::build_redirect(*this, redirectUrl); + const auto contentPath = "/content/" + bookName + "/" + item.getPath(); + const auto url = m_root + kiwix::urlEncode(contentPath); + return Response::build_redirect(*this, url); } std::unique_ptr InternalServer::handle_content(const RequestContext& request) diff --git a/src/server/internalServer.h b/src/server/internalServer.h index c3990c44d..b852afa52 100644 --- a/src/server/internalServer.h +++ b/src/server/internalServer.h @@ -163,7 +163,8 @@ class InternalServer { private: // data std::string m_addr; int m_port; - std::string m_root; + std::string m_root; // URI-encoded + std::string m_rootPrefixOfDecodedURL; // URI-decoded int m_nbThreads; unsigned int m_multizimSearchLimit; std::atomic_bool m_verbose; diff --git a/src/server/request_context.cpp b/src/server/request_context.cpp index d418d75af..017521666 100644 --- a/src/server/request_context.cpp +++ b/src/server/request_context.cpp @@ -49,32 +49,15 @@ RequestMethod str2RequestMethod(const std::string& method) { else return RequestMethod::OTHER; } -std::string -fullURL2LocalURL(const std::string& full_url, const std::string& rootLocation) -{ - if (rootLocation.empty()) { - // nothing special to handle. - return full_url; - } else if (full_url == rootLocation) { - return "/"; - } else if (full_url.size() > rootLocation.size() && - full_url.substr(0, rootLocation.size()+1) == rootLocation + "/") { - return full_url.substr(rootLocation.size()); - } else { - return ""; - } -} - } // unnamed namespace RequestContext::RequestContext(struct MHD_Connection* connection, - std::string _rootLocation, - const std::string& _url, + const std::string& _rootLocation, // URI-encoded + const std::string& unrootedUrl, // URI-decoded const std::string& _method, const std::string& version) : rootLocation(_rootLocation), - full_url(_url), - url(fullURL2LocalURL(_url, _rootLocation)), + url(unrootedUrl), method(str2RequestMethod(_method)), version(version), requestIndex(s_requestIndex++), @@ -153,7 +136,6 @@ void RequestContext::print_debug_info() const { printf("\n"); } printf("Parsed : \n"); - printf("full_url: %s\n", full_url.c_str()); printf("url : %s\n", url.c_str()); printf("acceptEncodingGzip : %d\n", acceptEncodingGzip); printf("has_range : %d\n", byteRange_.kind() != ByteRange::NONE); @@ -191,7 +173,7 @@ std::string RequestContext::get_url_part(int number) const { } std::string RequestContext::get_full_url() const { - return full_url; + return rootLocation + urlEncode(url); } std::string RequestContext::get_root_path() const { diff --git a/src/server/request_context.h b/src/server/request_context.h index 9017a6b28..081b699b9 100644 --- a/src/server/request_context.h +++ b/src/server/request_context.h @@ -57,8 +57,8 @@ class IndexError: public std::runtime_error {}; class RequestContext { public: // functions RequestContext(struct MHD_Connection* connection, - std::string rootLocation, - const std::string& url, + const std::string& rootLocation, // URI-encoded + const std::string& unrootedUrl, // URI-decoded const std::string& method, const std::string& version); ~RequestContext(); @@ -138,7 +138,6 @@ class RequestContext { private: // data std::string rootLocation; - std::string full_url; std::string url; RequestMethod method; std::string version; diff --git a/src/server/response.cpp b/src/server/response.cpp index 3ec50b8ca..db20a2fb4 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -200,7 +200,7 @@ HTTP404Response::HTTP404Response(const InternalServer& server, HTTPErrorResponse& HTTP404Response::operator+(UrlNotFoundMsg /*unused*/) { - const std::string requestUrl = m_request.get_full_url(); + const std::string requestUrl = urlDecode(m_request.get_full_url(), false); return *this + ParameterizedMessage("url-not-found", {{"url", requestUrl}}); } @@ -234,7 +234,7 @@ HTTP400Response::HTTP400Response(const InternalServer& server, HTTPErrorResponse& HTTP400Response::operator+(InvalidUrlMsg /*unused*/) { - std::string requestUrl = m_request.get_full_url(); + std::string requestUrl = urlDecode(m_request.get_full_url(), false); const auto query = m_request.get_query(); if (!query.empty()) { requestUrl += "?" + encodeDiples(query); diff --git a/test/data/corner_cases.zim b/test/data/corner_cases#&.zim similarity index 100% rename from test/data/corner_cases.zim rename to test/data/corner_cases#&.zim diff --git a/test/data/create_corner_cases_zim_file b/test/data/create_corner_cases_zim_file index 5f11096a2..32615cad9 100755 --- a/test/data/create_corner_cases_zim_file +++ b/test/data/create_corner_cases_zim_file @@ -1,7 +1,24 @@ #!/usr/bin/env bash cd "$(dirname "$0")" -rm -f corner_cases.zim + +# The following symbols (that would be nice to include in testing) are not +# allowed under NTFS and/or FAT32 filesystems, and would result in the +# impossibility to git clone (or rather checkout) the libkiwix repository under +# Windows: +# +# ? +# = +# + (that's a pity, since the + symbol in a ZIM filename is replaced with the +# text 'plus' when the ZIM file is added to kiwix-serve's library and it +# would be nice to test that functionality) +# +# Assuming that tests are NOT run under Windows, above symbols can be included +# in testing if the file is renamed while copying to the build directory (see +# test/meson.build), though that would make maintenance slightly more confusing. +zimfilename='corner_cases#&.zim' + +rm -f "$zimfilename" zimwriterfs --withoutFTIndex --dont-check-arguments \ -w empty.html \ -I empty.png \ @@ -11,6 +28,6 @@ zimwriterfs --withoutFTIndex --dont-check-arguments \ -c "" \ -p "" \ corner_cases \ - corner_cases.zim \ -&& echo 'corner_cases.zim was successfully created' \ -|| echo '!!! Failed to create corner_cases.zim !!!' >&2 + "$zimfilename" \ +&& echo "$zimfilename was successfully created" \ +|| echo '!!! Failed to create' "$zimfilename" '!!!' >&2 diff --git a/test/library_server.cpp b/test/library_server.cpp index a8f349ef0..5c0d65b1f 100644 --- a/test/library_server.cpp +++ b/test/library_server.cpp @@ -73,7 +73,7 @@ std::string maskVariableOPDSFeedData(std::string s) " \n" \ " \n" + " href=\"/ROOT%23%3F/catalog/searchdescription.xml\" />\n" #define CATALOG_ENTRY(UUID, TITLE, SUMMARY, LANG, NAME, CATEGORY, TAGS, EXTRA_LINK, CONTENT_NAME, FILE_NAME, LENGTH) \ " \n" \ @@ -88,7 +88,7 @@ std::string maskVariableOPDSFeedData(std::string s) " " TAGS "\n" \ " 284\n" \ " 2\n" \ - " " EXTRA_LINK "\n" \ + " " EXTRA_LINK "\n" \ " \n" \ " Wikipedia\n" \ " \n" \ @@ -126,7 +126,7 @@ std::string maskVariableOPDSFeedData(std::string s) "wikipedia",\ "public_tag_without_a_value;_private_tag_without_a_value;wikipedia;_category:wikipedia;_pictures:no;_videos:no;_details:no;_ftindex:yes",\ "\n ", \ CONTENT_NAME, \ "zimfile", \ @@ -152,7 +152,7 @@ std::string maskVariableOPDSFeedData(std::string s) TEST_F(LibraryServerTest, catalog_root_xml) { - const auto r = zfs1_->GET("/ROOT/catalog/root.xml"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/root.xml"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -170,7 +170,7 @@ TEST_F(LibraryServerTest, catalog_root_xml) TEST_F(LibraryServerTest, catalog_searchdescription_xml) { - const auto r = zfs1_->GET("/ROOT/catalog/searchdescription.xml"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/searchdescription.xml"); EXPECT_EQ(r->status, 200); EXPECT_EQ(r->body, "\n" @@ -181,14 +181,14 @@ TEST_F(LibraryServerTest, catalog_searchdescription_xml) " xmlns:atom=\"http://www.w3.org/2005/Atom\"\n" " xmlns:k=\"http://kiwix.org/opensearchextension/1.0\"\n" " indexOffset=\"0\"\n" - " template=\"/ROOT/catalog/search?q={searchTerms?}&lang={language?}&name={k:name?}&tag={k:tag?}¬ag={k:notag?}&maxsize={k:maxsize?}&count={count?}&start={startIndex?}\"/>\n" + " template=\"/ROOT%23%3F/catalog/search?q={searchTerms?}&lang={language?}&name={k:name?}&tag={k:tag?}¬ag={k:notag?}&maxsize={k:maxsize?}&count={count?}&start={startIndex?}\"/>\n" "\n" ); } TEST_F(LibraryServerTest, catalog_search_by_phrase) { - const auto r = zfs1_->GET("/ROOT/catalog/search?q=\"ray%20charles\""); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?q=\"ray%20charles\""); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -207,7 +207,7 @@ TEST_F(LibraryServerTest, catalog_search_by_phrase) TEST_F(LibraryServerTest, catalog_search_by_words) { - const auto r = zfs1_->GET("/ROOT/catalog/search?q=ray%20charles"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?q=ray%20charles"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -228,7 +228,7 @@ TEST_F(LibraryServerTest, catalog_search_by_words) TEST_F(LibraryServerTest, catalog_prefix_search) { { - const auto r = zfs1_->GET("/ROOT/catalog/search?q=description:ray%20description:charles"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?q=description:ray%20description:charles"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -245,7 +245,7 @@ TEST_F(LibraryServerTest, catalog_prefix_search) ); } { - const auto r = zfs1_->GET("/ROOT/catalog/search?q=title:\"ray%20charles\""); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?q=title:\"ray%20charles\""); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -264,7 +264,7 @@ TEST_F(LibraryServerTest, catalog_prefix_search) TEST_F(LibraryServerTest, catalog_search_with_word_exclusion) { - const auto r = zfs1_->GET("/ROOT/catalog/search?q=ray%20-uncategorized"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?q=ray%20-uncategorized"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -283,7 +283,7 @@ TEST_F(LibraryServerTest, catalog_search_with_word_exclusion) TEST_F(LibraryServerTest, catalog_search_by_tag) { - const auto r = zfs1_->GET("/ROOT/catalog/search?tag=_category:jazz"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?tag=_category:jazz"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -301,7 +301,7 @@ TEST_F(LibraryServerTest, catalog_search_by_tag) TEST_F(LibraryServerTest, catalog_search_by_category) { - const auto r = zfs1_->GET("/ROOT/catalog/search?category=jazz"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?category=jazz"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -320,7 +320,7 @@ TEST_F(LibraryServerTest, catalog_search_by_category) TEST_F(LibraryServerTest, catalog_search_by_language) { { - const auto r = zfs1_->GET("/ROOT/catalog/search?lang=eng"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?lang=eng"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -337,7 +337,7 @@ TEST_F(LibraryServerTest, catalog_search_by_language) } { - const auto r = zfs1_->GET("/ROOT/catalog/search?lang=eng,fra"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?lang=eng,fra"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -358,7 +358,7 @@ TEST_F(LibraryServerTest, catalog_search_by_language) TEST_F(LibraryServerTest, catalog_search_results_pagination) { { - const auto r = zfs1_->GET("/ROOT/catalog/search?count=0"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?count=0"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -376,7 +376,7 @@ TEST_F(LibraryServerTest, catalog_search_results_pagination) ); } { - const auto r = zfs1_->GET("/ROOT/catalog/search?count=1"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?count=1"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -392,7 +392,7 @@ TEST_F(LibraryServerTest, catalog_search_results_pagination) ); } { - const auto r = zfs1_->GET("/ROOT/catalog/search?start=1&count=1"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?start=1&count=1"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -408,7 +408,7 @@ TEST_F(LibraryServerTest, catalog_search_results_pagination) ); } { - const auto r = zfs1_->GET("/ROOT/catalog/search?start=100&count=10"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?start=100&count=10"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -426,20 +426,20 @@ TEST_F(LibraryServerTest, catalog_search_results_pagination) TEST_F(LibraryServerTest, catalog_v2_root) { - const auto r = zfs1_->GET("/ROOT/catalog/v2/root.xml"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/root.xml"); EXPECT_EQ(r->status, 200); const char expected_output[] = R"( 12345678-90ab-cdef-1234-567890abcdef OPDS Catalog Root YYYY-MM-DDThh:mm:ssZ @@ -447,7 +447,7 @@ TEST_F(LibraryServerTest, catalog_v2_root) All entries YYYY-MM-DDThh:mm:ssZ 12345678-90ab-cdef-1234-567890abcdef @@ -456,7 +456,7 @@ TEST_F(LibraryServerTest, catalog_v2_root) All entries (partial) YYYY-MM-DDThh:mm:ssZ 12345678-90ab-cdef-1234-567890abcdef @@ -465,7 +465,7 @@ TEST_F(LibraryServerTest, catalog_v2_root) List of categories YYYY-MM-DDThh:mm:ssZ 12345678-90ab-cdef-1234-567890abcdef @@ -474,7 +474,7 @@ TEST_F(LibraryServerTest, catalog_v2_root) List of languages YYYY-MM-DDThh:mm:ssZ 12345678-90ab-cdef-1234-567890abcdef @@ -487,7 +487,7 @@ TEST_F(LibraryServerTest, catalog_v2_root) TEST_F(LibraryServerTest, catalog_v2_searchdescription_xml) { - const auto r = zfs1_->GET("/ROOT/catalog/v2/searchdescription.xml"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/searchdescription.xml"); EXPECT_EQ(r->status, 200); EXPECT_EQ(r->body, "\n" @@ -498,24 +498,24 @@ TEST_F(LibraryServerTest, catalog_v2_searchdescription_xml) " xmlns:atom=\"http://www.w3.org/2005/Atom\"\n" " xmlns:k=\"http://kiwix.org/opensearchextension/1.0\"\n" " indexOffset=\"0\"\n" - " template=\"/ROOT/catalog/v2/entries?q={searchTerms?}&lang={language?}&name={k:name?}&tag={k:tag?}&maxsize={k:maxsize?}&count={count?}&start={startIndex?}\"/>\n" + " template=\"/ROOT%23%3F/catalog/v2/entries?q={searchTerms?}&lang={language?}&name={k:name?}&tag={k:tag?}&maxsize={k:maxsize?}&count={count?}&start={startIndex?}\"/>\n" "\n" ); } TEST_F(LibraryServerTest, catalog_v2_categories) { - const auto r = zfs1_->GET("/ROOT/catalog/v2/categories"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/categories"); EXPECT_EQ(r->status, 200); const char expected_output[] = R"( 12345678-90ab-cdef-1234-567890abcdef List of categories YYYY-MM-DDThh:mm:ssZ @@ -523,7 +523,7 @@ TEST_F(LibraryServerTest, catalog_v2_categories) jazz YYYY-MM-DDThh:mm:ssZ 12345678-90ab-cdef-1234-567890abcdef @@ -532,7 +532,7 @@ TEST_F(LibraryServerTest, catalog_v2_categories) wikipedia YYYY-MM-DDThh:mm:ssZ 12345678-90ab-cdef-1234-567890abcdef @@ -545,7 +545,7 @@ TEST_F(LibraryServerTest, catalog_v2_categories) TEST_F(LibraryServerTest, catalog_v2_languages) { - const auto r = zfs1_->GET("/ROOT/catalog/v2/languages"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/languages"); EXPECT_EQ(r->status, 200); const char expected_output[] = R"( 12345678-90ab-cdef-1234-567890abcdef List of languages YYYY-MM-DDThh:mm:ssZ @@ -567,7 +567,7 @@ TEST_F(LibraryServerTest, catalog_v2_languages) eng 1 YYYY-MM-DDThh:mm:ssZ 12345678-90ab-cdef-1234-567890abcdef @@ -577,7 +577,7 @@ TEST_F(LibraryServerTest, catalog_v2_languages) fra 1 YYYY-MM-DDThh:mm:ssZ 12345678-90ab-cdef-1234-567890abcdef @@ -587,7 +587,7 @@ TEST_F(LibraryServerTest, catalog_v2_languages) rus 1 YYYY-MM-DDThh:mm:ssZ 12345678-90ab-cdef-1234-567890abcdef @@ -606,13 +606,13 @@ TEST_F(LibraryServerTest, catalog_v2_languages) " 12345678-90ab-cdef-1234-567890abcdef\n" \ "\n" \ " \n" \ " \n" \ " \n" \ "\n" \ @@ -624,7 +624,7 @@ TEST_F(LibraryServerTest, catalog_v2_languages) TEST_F(LibraryServerTest, catalog_v2_entries) { - const auto r = zfs1_->GET("/ROOT/catalog/v2/entries"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/entries"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), CATALOG_V2_ENTRIES_PREAMBLE("") @@ -641,7 +641,7 @@ TEST_F(LibraryServerTest, catalog_v2_entries) TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_range) { { - const auto r = zfs1_->GET("/ROOT/catalog/v2/entries?start=1"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/entries?start=1"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), CATALOG_V2_ENTRIES_PREAMBLE("?start=1") @@ -657,7 +657,7 @@ TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_range) } { - const auto r = zfs1_->GET("/ROOT/catalog/v2/entries?count=2"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/entries?count=2"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), CATALOG_V2_ENTRIES_PREAMBLE("?count=2") @@ -673,7 +673,7 @@ TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_range) } { - const auto r = zfs1_->GET("/ROOT/catalog/v2/entries?start=1&count=1"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/entries?start=1&count=1"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), CATALOG_V2_ENTRIES_PREAMBLE("?start=1&count=1") @@ -690,7 +690,7 @@ TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_range) TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_search_terms) { - const auto r = zfs1_->GET("/ROOT/catalog/v2/entries?q=\"ray%20charles\""); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/entries?q=\"ray%20charles\""); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), CATALOG_V2_ENTRIES_PREAMBLE("?q=%22ray%20charles%22") @@ -708,7 +708,7 @@ TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_search_terms) TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_language) { { - const auto r = zfs1_->GET("/ROOT/catalog/v2/entries?lang=eng"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/entries?lang=eng"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), CATALOG_V2_ENTRIES_PREAMBLE("?lang=eng") @@ -723,7 +723,7 @@ TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_language) } { - const auto r = zfs1_->GET("/ROOT/catalog/v2/entries?lang=eng,fra"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/entries?lang=eng,fra"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), CATALOG_V2_ENTRIES_PREAMBLE("?lang=eng%2Cfra") @@ -741,20 +741,20 @@ TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_language) TEST_F(LibraryServerTest, catalog_v2_individual_entry_access) { - const auto r = zfs1_->GET("/ROOT/catalog/v2/entry/raycharles"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/entry/raycharles"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), "\n" RAY_CHARLES_CATALOG_ENTRY ); - const auto r1 = zfs1_->GET("/ROOT/catalog/v2/entry/non-existent-entry"); + const auto r1 = zfs1_->GET("/ROOT%23%3F/catalog/v2/entry/non-existent-entry"); EXPECT_EQ(r1->status, 404); } TEST_F(LibraryServerTest, catalog_v2_partial_entries) { - const auto r = zfs1_->GET("/ROOT/catalog/v2/partial_entries"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/partial_entries"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), CATALOG_V2_PARTIAL_ENTRIES_PREAMBLE("") @@ -766,7 +766,7 @@ TEST_F(LibraryServerTest, catalog_v2_partial_entries) " Charles, Ray\n" " YYYY-MM-DDThh:mm:ssZ\n" " \n" " \n" " \n" @@ -774,7 +774,7 @@ TEST_F(LibraryServerTest, catalog_v2_partial_entries) " Ray Charles\n" " YYYY-MM-DDThh:mm:ssZ\n" " \n" " \n" " \n" @@ -782,7 +782,7 @@ TEST_F(LibraryServerTest, catalog_v2_partial_entries) " Ray (uncategorized) Charles\n" " YYYY-MM-DDThh:mm:ssZ\n" " \n" " \n" "\n" @@ -791,7 +791,7 @@ TEST_F(LibraryServerTest, catalog_v2_partial_entries) #define EXPECT_SEARCH_RESULTS(SEARCH_TERM, RESULT_COUNT, OPDS_ENTRIES) \ { \ - const auto r = zfs1_->GET("/ROOT/catalog/search?q=" SEARCH_TERM); \ + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?q=" SEARCH_TERM); \ EXPECT_EQ(r->status, 200); \ EXPECT_EQ(maskVariableOPDSFeedData(r->body), \ OPDS_FEED_TAG \ @@ -860,7 +860,7 @@ TEST_F(LibraryServerTest, catalog_search_excludes_hidden_tags) TEST_F(LibraryServerTest, no_name_mapper_returned_catalog_use_uuid_in_link) { resetServer(ZimFileServer::NO_NAME_MAPPER); - const auto r = zfs1_->GET("/ROOT/catalog/search?tag=_category:jazz"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?tag=_category:jazz"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), OPDS_FEED_TAG @@ -880,14 +880,14 @@ TEST_F(LibraryServerTest, no_name_mapper_returned_catalog_use_uuid_in_link) TEST_F(LibraryServerTest, no_name_mapper_catalog_v2_individual_entry_access) { resetServer(ZimFileServer::NO_NAME_MAPPER); - const auto r = zfs1_->GET("/ROOT/catalog/v2/entry/raycharles"); + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/entry/raycharles"); EXPECT_EQ(r->status, 200); EXPECT_EQ(maskVariableOPDSFeedData(r->body), "\n" RAY_CHARLES_CATALOG_ENTRY_NO_MAPPER ); - const auto r1 = zfs1_->GET("/ROOT/catalog/v2/entry/non-existent-entry"); + const auto r1 = zfs1_->GET("/ROOT%23%3F/catalog/v2/entry/non-existent-entry"); EXPECT_EQ(r1->status, 404); } diff --git a/test/meson.build b/test/meson.build index 772afda18..f7ed51f5d 100644 --- a/test/meson.build +++ b/test/meson.build @@ -34,7 +34,7 @@ if gtest_dep.found() and not meson.is_cross_build() 'example.zim', 'zimfile.zim', 'zimfile&other.zim', - 'corner_cases.zim', + 'corner_cases#&.zim', 'poor.zim', 'library.xml', 'lib_for_server_search_test.xml', diff --git a/test/server.cpp b/test/server.cpp index 5a224343a..c99e960e9 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -47,136 +47,136 @@ std::ostream& operator<<(std::ostream& out, const Resource& r) typedef std::vector ResourceCollection; const ResourceCollection resources200Compressible{ - { DYNAMIC_CONTENT, "/ROOT/" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/" }, - { DYNAMIC_CONTENT, "/ROOT/viewer" }, - { DYNAMIC_CONTENT, "/ROOT/viewer?cacheid=whatever" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/viewer" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/viewer?cacheid=whatever" }, - { DYNAMIC_CONTENT, "/ROOT/skin/autoComplete.min.js" }, - { STATIC_CONTENT, "/ROOT/skin/autoComplete.min.js?cacheid=1191aaaf" }, - { DYNAMIC_CONTENT, "/ROOT/skin/css/autoComplete.css" }, - { STATIC_CONTENT, "/ROOT/skin/css/autoComplete.css?cacheid=08951e06" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/favicon.ico" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/favicon.ico?cacheid=fba03a27" }, - { DYNAMIC_CONTENT, "/ROOT/skin/i18n.js" }, - { STATIC_CONTENT, "/ROOT/skin/i18n.js?cacheid=6da2bca0" }, - { DYNAMIC_CONTENT, "/ROOT/skin/index.css" }, - { STATIC_CONTENT, "/ROOT/skin/index.css?cacheid=0f9ba34e" }, - { DYNAMIC_CONTENT, "/ROOT/skin/index.js" }, - { STATIC_CONTENT, "/ROOT/skin/index.js?cacheid=2f5a81ac" }, - { DYNAMIC_CONTENT, "/ROOT/skin/iso6391To3.js" }, - { STATIC_CONTENT, "/ROOT/skin/iso6391To3.js?cacheid=ecde2bb3" }, - { DYNAMIC_CONTENT, "/ROOT/skin/isotope.pkgd.min.js" }, - { STATIC_CONTENT, "/ROOT/skin/isotope.pkgd.min.js?cacheid=2e48d392" }, - { DYNAMIC_CONTENT, "/ROOT/skin/mustache.min.js" }, - { STATIC_CONTENT, "/ROOT/skin/mustache.min.js?cacheid=bd23c4fb" }, - { DYNAMIC_CONTENT, "/ROOT/skin/taskbar.css" }, - { STATIC_CONTENT, "/ROOT/skin/taskbar.css?cacheid=eb3bec90" }, - { DYNAMIC_CONTENT, "/ROOT/skin/viewer.js" }, - { STATIC_CONTENT, "/ROOT/skin/viewer.js?cacheid=03fd97ee" }, - { DYNAMIC_CONTENT, "/ROOT/skin/fonts/Poppins.ttf" }, - { STATIC_CONTENT, "/ROOT/skin/fonts/Poppins.ttf?cacheid=af705837" }, - { DYNAMIC_CONTENT, "/ROOT/skin/fonts/Roboto.ttf" }, - { STATIC_CONTENT, "/ROOT/skin/fonts/Roboto.ttf?cacheid=84d10248" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/autoComplete.min.js" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/autoComplete.min.js?cacheid=1191aaaf" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/css/autoComplete.css" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/css/autoComplete.css?cacheid=08951e06" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/favicon.ico" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/favicon.ico?cacheid=fba03a27" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/i18n.js" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/i18n.js?cacheid=6da2bca0" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/index.css" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/index.css?cacheid=0f9ba34e" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/index.js" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/index.js?cacheid=2f5a81ac" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/iso6391To3.js" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/iso6391To3.js?cacheid=ecde2bb3" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/isotope.pkgd.min.js" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/isotope.pkgd.min.js?cacheid=2e48d392" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/mustache.min.js" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/mustache.min.js?cacheid=bd23c4fb" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/taskbar.css" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/taskbar.css?cacheid=eb3bec90" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/viewer.js" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/viewer.js?cacheid=03fd97ee" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/fonts/Poppins.ttf" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/fonts/Poppins.ttf?cacheid=af705837" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/fonts/Roboto.ttf" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/fonts/Roboto.ttf?cacheid=84d10248" }, - { DYNAMIC_CONTENT, "/ROOT/catalog/search" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catalog/search" }, - { DYNAMIC_CONTENT, "/ROOT/catalog/v2/root.xml" }, - { DYNAMIC_CONTENT, "/ROOT/catalog/v2/entries" }, - { DYNAMIC_CONTENT, "/ROOT/catalog/v2/partial_entries" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catalog/v2/root.xml" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catalog/v2/entries" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catalog/v2/partial_entries" }, - { DYNAMIC_CONTENT, "/ROOT/search?content=zimfile&pattern=a" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/search?content=zimfile&pattern=a" }, - { DYNAMIC_CONTENT, "/ROOT/suggest?content=zimfile&term=ray" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/suggest?content=zimfile&term=ray" }, - { ZIM_CONTENT, "/ROOT/content/zimfile/A/index" }, - { ZIM_CONTENT, "/ROOT/content/zimfile/A/Ray_Charles" }, + { ZIM_CONTENT, "/ROOT%23%3F/content/zimfile/A/index" }, + { ZIM_CONTENT, "/ROOT%23%3F/content/zimfile/A/Ray_Charles" }, - { ZIM_CONTENT, "/ROOT/raw/zimfile/content/A/index" }, - { ZIM_CONTENT, "/ROOT/raw/zimfile/content/A/Ray_Charles" }, + { ZIM_CONTENT, "/ROOT%23%3F/raw/zimfile/content/A/index" }, + { ZIM_CONTENT, "/ROOT%23%3F/raw/zimfile/content/A/Ray_Charles" }, }; const ResourceCollection resources200Uncompressible{ - { DYNAMIC_CONTENT, "/ROOT/skin/bittorrent.png" }, - { STATIC_CONTENT, "/ROOT/skin/bittorrent.png?cacheid=4f5c6882" }, - { DYNAMIC_CONTENT, "/ROOT/skin/blank.html" }, - { STATIC_CONTENT, "/ROOT/skin/blank.html?cacheid=6b1fa032" }, - { DYNAMIC_CONTENT, "/ROOT/skin/caret.png" }, - { STATIC_CONTENT, "/ROOT/skin/caret.png?cacheid=22b942b4" }, - { DYNAMIC_CONTENT, "/ROOT/skin/download.png" }, - { STATIC_CONTENT, "/ROOT/skin/download.png?cacheid=a39aa502" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/android-chrome-192x192.png" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/android-chrome-192x192.png?cacheid=bfac158b" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/android-chrome-512x512.png" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/android-chrome-512x512.png?cacheid=380c3653" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/apple-touch-icon.png" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/apple-touch-icon.png?cacheid=f86f8df3" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/browserconfig.xml" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/browserconfig.xml?cacheid=f29a7c4a" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/favicon-16x16.png" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/favicon-16x16.png?cacheid=a986fedc" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/favicon-32x32.png" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/favicon-32x32.png?cacheid=79ded625" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/mstile-144x144.png" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/mstile-144x144.png?cacheid=c25a7641" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/mstile-150x150.png" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/mstile-150x150.png?cacheid=6fa6f467" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/mstile-310x150.png" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/mstile-310x150.png?cacheid=e0ed9032" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/mstile-310x310.png" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/mstile-310x310.png?cacheid=26b20530" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/mstile-70x70.png" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/mstile-70x70.png?cacheid=64ffd9dc" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/safari-pinned-tab.svg" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/safari-pinned-tab.svg?cacheid=8d487e95" }, - { DYNAMIC_CONTENT, "/ROOT/skin/favicon/site.webmanifest" }, - { STATIC_CONTENT, "/ROOT/skin/favicon/site.webmanifest?cacheid=bc396efb" }, - { DYNAMIC_CONTENT, "/ROOT/skin/hash.png" }, - { STATIC_CONTENT, "/ROOT/skin/hash.png?cacheid=f836e872" }, - { DYNAMIC_CONTENT, "/ROOT/skin/magnet.png" }, - { STATIC_CONTENT, "/ROOT/skin/magnet.png?cacheid=73b6bddf" }, - { DYNAMIC_CONTENT, "/ROOT/skin/search-icon.svg" }, - { STATIC_CONTENT, "/ROOT/skin/search-icon.svg?cacheid=b10ae7ed" }, - { DYNAMIC_CONTENT, "/ROOT/skin/search_results.css" }, - { STATIC_CONTENT, "/ROOT/skin/search_results.css?cacheid=76d39c84" }, - { DYNAMIC_CONTENT, "/ROOT/skin/i18n/test.json" }, + { 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" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/blank.html?cacheid=6b1fa032" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/caret.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/caret.png?cacheid=22b942b4" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/download.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/download.png?cacheid=a39aa502" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/android-chrome-192x192.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/android-chrome-192x192.png?cacheid=bfac158b" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/android-chrome-512x512.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/android-chrome-512x512.png?cacheid=380c3653" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/apple-touch-icon.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/apple-touch-icon.png?cacheid=f86f8df3" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/browserconfig.xml" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/browserconfig.xml?cacheid=f29a7c4a" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/favicon-16x16.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/favicon-16x16.png?cacheid=a986fedc" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/favicon-32x32.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/favicon-32x32.png?cacheid=79ded625" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/mstile-144x144.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/mstile-144x144.png?cacheid=c25a7641" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/mstile-150x150.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/mstile-150x150.png?cacheid=6fa6f467" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/mstile-310x150.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/mstile-310x150.png?cacheid=e0ed9032" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/mstile-310x310.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/mstile-310x310.png?cacheid=26b20530" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/mstile-70x70.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/mstile-70x70.png?cacheid=64ffd9dc" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/safari-pinned-tab.svg" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/safari-pinned-tab.svg?cacheid=8d487e95" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/favicon/site.webmanifest" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/favicon/site.webmanifest?cacheid=bc396efb" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/hash.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/hash.png?cacheid=f836e872" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/magnet.png" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/magnet.png?cacheid=73b6bddf" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/search-icon.svg" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/search-icon.svg?cacheid=b10ae7ed" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/search_results.css" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/search_results.css?cacheid=76d39c84" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/i18n/test.json" }, // TODO: implement cache management of i18n resources - //{ STATIC_CONTENT, "/ROOT/skin/i18n/test.json?cacheid=unknown" }, - { DYNAMIC_CONTENT, "/ROOT/skin/languages.js" }, - { STATIC_CONTENT, "/ROOT/skin/languages.js?cacheid=fe100348" }, + //{ STATIC_CONTENT, "/ROOT%23%3F/skin/i18n/test.json?cacheid=unknown" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/languages.js" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/languages.js?cacheid=fe100348" }, - { ZIM_CONTENT, "/ROOT/raw/zimfile/meta/Title" }, - { ZIM_CONTENT, "/ROOT/raw/zimfile/meta/Description" }, - { ZIM_CONTENT, "/ROOT/raw/zimfile/meta/Language" }, - { ZIM_CONTENT, "/ROOT/raw/zimfile/meta/Name" }, - { ZIM_CONTENT, "/ROOT/raw/zimfile/meta/Tags" }, - { ZIM_CONTENT, "/ROOT/raw/zimfile/meta/Date" }, - { ZIM_CONTENT, "/ROOT/raw/zimfile/meta/Creator" }, - { ZIM_CONTENT, "/ROOT/raw/zimfile/meta/Publisher" }, + { ZIM_CONTENT, "/ROOT%23%3F/raw/zimfile/meta/Title" }, + { ZIM_CONTENT, "/ROOT%23%3F/raw/zimfile/meta/Description" }, + { ZIM_CONTENT, "/ROOT%23%3F/raw/zimfile/meta/Language" }, + { ZIM_CONTENT, "/ROOT%23%3F/raw/zimfile/meta/Name" }, + { ZIM_CONTENT, "/ROOT%23%3F/raw/zimfile/meta/Tags" }, + { ZIM_CONTENT, "/ROOT%23%3F/raw/zimfile/meta/Date" }, + { ZIM_CONTENT, "/ROOT%23%3F/raw/zimfile/meta/Creator" }, + { ZIM_CONTENT, "/ROOT%23%3F/raw/zimfile/meta/Publisher" }, - { DYNAMIC_CONTENT, "/ROOT/catalog/root.xml" }, - { DYNAMIC_CONTENT, "/ROOT/catalog/searchdescription.xml" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catalog/root.xml" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catalog/searchdescription.xml" }, - { DYNAMIC_CONTENT, "/ROOT/catalog/v2/categories" }, - { DYNAMIC_CONTENT, "/ROOT/catalog/v2/languages" }, - { DYNAMIC_CONTENT, "/ROOT/catalog/v2/searchdescription.xml" }, - { DYNAMIC_CONTENT, "/ROOT/catalog/v2/illustration/6f1d19d0-633f-087b-fb55-7ac324ff9baf?size=48" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catalog/v2/categories" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catalog/v2/languages" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catalog/v2/searchdescription.xml" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catalog/v2/illustration/6f1d19d0-633f-087b-fb55-7ac324ff9baf?size=48" }, - { DYNAMIC_CONTENT, "/ROOT/catch/external?source=www.example.com" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catch/external?source=www.example.com" }, - { ZIM_CONTENT, "/ROOT/content/zimfile/I/m/Ray_Charles_classic_piano_pose.jpg" }, + { ZIM_CONTENT, "/ROOT%23%3F/content/zimfile/I/m/Ray_Charles_classic_piano_pose.jpg" }, - { ZIM_CONTENT, "/ROOT/content/corner_cases/empty.html" }, - { ZIM_CONTENT, "/ROOT/content/corner_cases/empty.css" }, - { ZIM_CONTENT, "/ROOT/content/corner_cases/empty.js" }, + { ZIM_CONTENT, "/ROOT%23%3F/content/corner_cases%23%26/empty.html" }, + { ZIM_CONTENT, "/ROOT%23%3F/content/corner_cases%23%26/empty.css" }, + { ZIM_CONTENT, "/ROOT%23%3F/content/corner_cases%23%26/empty.js" }, // The following url's responses are too small to be compressed - { DYNAMIC_CONTENT, "/ROOT/catalog/root.xml" }, - { DYNAMIC_CONTENT, "/ROOT/catalog/searchdescription.xml" }, - { DYNAMIC_CONTENT, "/ROOT/suggest?content=zimfile" }, - { ZIM_CONTENT, "/ROOT/raw/zimfile/meta/Creator" }, - { ZIM_CONTENT, "/ROOT/raw/zimfile/meta/Title" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catalog/root.xml" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/catalog/searchdescription.xml" }, + { DYNAMIC_CONTENT, "/ROOT%23%3F/suggest?content=zimfile" }, + { ZIM_CONTENT, "/ROOT%23%3F/raw/zimfile/meta/Creator" }, + { ZIM_CONTENT, "/ROOT%23%3F/raw/zimfile/meta/Title" }, }; ResourceCollection all200Resources() @@ -188,18 +188,18 @@ TEST(indexTemplateStringTest, emptyIndexTemplate) { const int PORT = 8001; const ZimFileServer::FilePathCollection ZIMFILES { "./test/zimfile.zim", - "./test/corner_cases.zim" + "./test/corner_cases#&.zim" }; ZimFileServer zfs(PORT, ZimFileServer::DEFAULT_OPTIONS, ZIMFILES, ""); - EXPECT_EQ(200, zfs.GET("/ROOT/")->status); + EXPECT_EQ(200, zfs.GET("/ROOT%23%3F/")->status); } TEST(indexTemplateStringTest, indexTemplateCheck) { const int PORT = 8001; const ZimFileServer::FilePathCollection ZIMFILES { "./test/zimfile.zim", - "./test/corner_cases.zim" + "./test/corner_cases#&.zim" }; ZimFileServer zfs(PORT, ZimFileServer::DEFAULT_OPTIONS, ZIMFILES, "" @@ -209,7 +209,7 @@ TEST(indexTemplateStringTest, indexTemplateCheck) { EXPECT_EQ("" "Welcome to kiwix library" "" - "", zfs.GET("/ROOT/")->body); + "", zfs.GET("/ROOT%23%3F/")->body); } TEST_F(ServerTest, 200) @@ -220,11 +220,11 @@ TEST_F(ServerTest, 200) TEST_F(ServerTest, 200_IdNameMapper) { - EXPECT_EQ(404, zfs1_->GET("/ROOT/content/6f1d19d0-633f-087b-fb55-7ac324ff9baf/A/index")->status); - EXPECT_EQ(200, zfs1_->GET("/ROOT/content/zimfile/A/index")->status); + EXPECT_EQ(404, zfs1_->GET("/ROOT%23%3F/content/6f1d19d0-633f-087b-fb55-7ac324ff9baf/A/index")->status); + EXPECT_EQ(200, zfs1_->GET("/ROOT%23%3F/content/zimfile/A/index")->status); resetServer(ZimFileServer::NO_NAME_MAPPER); - EXPECT_EQ(200, zfs1_->GET("/ROOT/content/6f1d19d0-633f-087b-fb55-7ac324ff9baf/A/index")->status); - EXPECT_EQ(404, zfs1_->GET("/ROOT/content/zimfile/A/index")->status); + EXPECT_EQ(200, zfs1_->GET("/ROOT%23%3F/content/6f1d19d0-633f-087b-fb55-7ac324ff9baf/A/index")->status); + EXPECT_EQ(404, zfs1_->GET("/ROOT%23%3F/content/zimfile/A/index")->status); } TEST_F(ServerTest, CompressibleContentIsCompressedIfAcceptable) @@ -267,29 +267,29 @@ TEST_F(ServerTest, CacheIdsOfStaticResources) typedef std::pair UrlAndExpectedResult; const std::vector testData{ { - /* url */ "/ROOT/", -R"EXPECTEDRESULT( href="/ROOT/skin/index.css?cacheid=0f9ba34e" - - - - - - - - src: url("/ROOT/skin/fonts/Poppins.ttf?cacheid=af705837") format("truetype"); - src: url("/ROOT/skin/fonts/Roboto.ttf?cacheid=84d10248") format("truetype"); - - - + /* url */ "/ROOT%23%3F/", +R"EXPECTEDRESULT( href="/ROOT%23%3F/skin/index.css?cacheid=0f9ba34e" + + + + + + + + src: url("/ROOT%23%3F/skin/fonts/Poppins.ttf?cacheid=af705837") format("truetype"); + src: url("/ROOT%23%3F/skin/fonts/Roboto.ttf?cacheid=84d10248") format("truetype"); + + + )EXPECTEDRESULT" }, { - /* url */ "/ROOT/skin/index.css", + /* url */ "/ROOT%23%3F/skin/index.css", R"EXPECTEDRESULT( background-image: url('../skin/search-icon.svg?cacheid=b10ae7ed'); )EXPECTEDRESULT" }, { - /* url */ "/ROOT/skin/index.js", + /* url */ "/ROOT%23%3F/skin/index.js", R"EXPECTEDRESULT( direct download download hash download magnet @@ -297,7 +297,7 @@ R"EXPECTEDRESULT( @@ -310,14 +310,14 @@ R"EXPECTEDRESULT( + /* url */ "/ROOT%23%3F/search?content=poor&pattern=whatever", +R"EXPECTEDRESULT( )EXPECTEDRESULT" }, }; @@ -333,15 +333,15 @@ R"EXPECTEDRESULT( GET("/ROOT/non-existent-item"); + // ServerTest.404 verifies that "/ROOT%23%3F/non-existent-item" doesn't exist + const auto r = zfs1_->GET("/ROOT%23%3F/non-existent-item"); EXPECT_EQ(r->status, 200); EXPECT_EQ(getHeaderValue(r->headers, "Content-Type"), "text/plain"); EXPECT_EQ(r->body, "Hello world!\n"); @@ -432,35 +432,35 @@ TEST_F(CustomizedServerTest, NewResourcesCanBeAdded) TEST_F(CustomizedServerTest, ContentOfAnyServableUrlCanBeOverriden) { { - const auto r = zfs1_->GET("/ROOT/"); + const auto r = zfs1_->GET("/ROOT%23%3F/"); EXPECT_EQ(r->status, 200); EXPECT_EQ(getHeaderValue(r->headers, "Content-Type"), "text/html"); EXPECT_EQ(r->body, "Welcome\n"); } { - const auto r = zfs1_->GET("/ROOT/skin/index.css"); + const auto r = zfs1_->GET("/ROOT%23%3F/skin/index.css"); EXPECT_EQ(r->status, 200); EXPECT_EQ(getHeaderValue(r->headers, "Content-Type"), "application/json"); EXPECT_EQ(r->body, "Hello world!\n"); } { - const auto r = zfs1_->GET("/ROOT/zimfile/A/Ray_Charles"); + const auto r = zfs1_->GET("/ROOT%23%3F/zimfile/A/Ray_Charles"); EXPECT_EQ(r->status, 200); EXPECT_EQ(getHeaderValue(r->headers, "Content-Type"), "ray/charles"); EXPECT_EQ(r->body, "Welcome\n"); } { - const auto r = zfs1_->GET("/ROOT/content/zimfile/A/Ray_Charles"); + const auto r = zfs1_->GET("/ROOT%23%3F/content/zimfile/A/Ray_Charles"); EXPECT_EQ(r->status, 200); EXPECT_EQ(getHeaderValue(r->headers, "Content-Type"), "charles/ray"); EXPECT_EQ(r->body, "Welcome\n"); } { - const auto r = zfs1_->GET("/ROOT/search?pattern=la+femme"); + const auto r = zfs1_->GET("/ROOT%23%3F/search?pattern=la+femme"); EXPECT_EQ(r->status, 200); EXPECT_EQ(getHeaderValue(r->headers, "Content-Type"), "text/html"); EXPECT_EQ(r->body, "Hello world!\n"); @@ -614,7 +614,7 @@ TEST_F(ServerTest, Http404HtmlError) { using namespace TestingOfHtmlResponses; const std::vector testData{ - { /* url */ "/ROOT/random?content=non-existent-book", + { /* url */ "/ROOT%23%3F/random?content=non-existent-book", expected_body==R"(

Not Found

@@ -622,7 +622,7 @@ TEST_F(ServerTest, Http404HtmlError)

)" }, - { /* url */ "/ROOT/random?content=non-existent-book&userlang=test", + { /* url */ "/ROOT%23%3F/random?content=non-existent-book&userlang=test", expected_page_title=="[I18N TESTING] Not Found - Try Again" && expected_body==R"(

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

@@ -631,7 +631,7 @@ TEST_F(ServerTest, Http404HtmlError)

)" }, - { /* url */ "/ROOT/suggest?content=no-such-book&term=whatever", + { /* url */ "/ROOT%23%3F/suggest?content=no-such-book&term=whatever", expected_body==R"(

Not Found

@@ -639,149 +639,149 @@ TEST_F(ServerTest, Http404HtmlError)

)" }, - { /* url */ "/ROOT/catalog/", + { /* url */ "/ROOT%23%3F/catalog/", expected_body==R"(

Not Found

- The requested URL "/ROOT/catalog/" was not found on this server. + The requested URL "/ROOT%23%3F/catalog/" was not found on this server.

)" }, - { /* url */ "/ROOT/catalog/?userlang=test", + { /* url */ "/ROOT%23%3F/catalog/?userlang=test", expected_page_title=="[I18N TESTING] Not Found - Try Again" && expected_body==R"(

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

- [I18N TESTING] URL not found: /ROOT/catalog/ + [I18N TESTING] URL not found: /ROOT%23%3F/catalog/

)" }, - { /* url */ "/ROOT/catalog/invalid_endpoint", + { /* url */ "/ROOT%23%3F/catalog/invalid_endpoint", expected_body==R"(

Not Found

- The requested URL "/ROOT/catalog/invalid_endpoint" was not found on this server. + The requested URL "/ROOT%23%3F/catalog/invalid_endpoint" was not found on this server.

)" }, - { /* url */ "/ROOT/catalog/invalid_endpoint?userlang=test", + { /* url */ "/ROOT%23%3F/catalog/invalid_endpoint?userlang=test", expected_page_title=="[I18N TESTING] Not Found - Try Again" && expected_body==R"(

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

- [I18N TESTING] URL not found: /ROOT/catalog/invalid_endpoint + [I18N TESTING] URL not found: /ROOT%23%3F/catalog/invalid_endpoint

)" }, - { /* url */ "/ROOT/content/invalid-book/whatever", + { /* url */ "/ROOT%23%3F/content/invalid-book/whatever", expected_body==R"(

Not Found

- The requested URL "/ROOT/content/invalid-book/whatever" was not found on this server. + The requested URL "/ROOT%23%3F/content/invalid-book/whatever" was not found on this server.

- Make a full text search for whatever + Make a full text search for whatever

)" }, - { /* url */ "/ROOT/content/zimfile/invalid-article", + { /* url */ "/ROOT%23%3F/content/zimfile/invalid-article", book_name=="zimfile" && book_title=="Ray Charles" && expected_body==R"(

Not Found

- The requested URL "/ROOT/content/zimfile/invalid-article" was not found on this server. + The requested URL "/ROOT%23%3F/content/zimfile/invalid-article" was not found on this server.

- Make a full text search for invalid-article + Make a full text search for invalid-article

)" }, - { /* url */ R"(/ROOT/content/">)", + { /* url */ R"(/ROOT%23%3F/content/">)", expected_body==R"(

Not Found

- The requested URL "/ROOT/content/"><svg onload=alert(1)>" was not found on this server. + The requested URL "/ROOT%23%3F/content/"><svg onload%3Dalert(1)>" was not found on this server.

- Make a full text search for "><svg onload=alert(1)> + Make a full text search for "><svg onload=alert(1)>

)" }, - { /* url */ R"(/ROOT/content/zimfile/">)", + { /* url */ R"(/ROOT%23%3F/content/zimfile/">)", book_name=="zimfile" && book_title=="Ray Charles" && expected_body==R"(

Not Found

- The requested URL "/ROOT/content/zimfile/"><svg onload=alert(1)>" was not found on this server. + The requested URL "/ROOT%23%3F/content/zimfile/"><svg onload%3Dalert(1)>" was not found on this server.

- Make a full text search for "><svg onload=alert(1)> + Make a full text search for "><svg onload=alert(1)>

)" }, - { /* url */ "/ROOT/content/zimfile/invalid-article?userlang=test", + { /* url */ "/ROOT%23%3F/content/zimfile/invalid-article?userlang=test", expected_page_title=="[I18N TESTING] Not Found - Try Again" && book_name=="zimfile" && book_title=="Ray Charles" && expected_body==R"(

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

- [I18N TESTING] URL not found: /ROOT/content/zimfile/invalid-article + [I18N TESTING] URL not found: /ROOT%23%3F/content/zimfile/invalid-article

- [I18N TESTING] Make a full text search for invalid-article + [I18N TESTING] Make a full text search for invalid-article

)" }, - { /* url */ "/ROOT/raw/no-such-book/meta/Title", + { /* url */ "/ROOT%23%3F/raw/no-such-book/meta/Title", expected_body==R"(

Not Found

- The requested URL "/ROOT/raw/no-such-book/meta/Title" was not found on this server. + The requested URL "/ROOT%23%3F/raw/no-such-book/meta/Title" was not found on this server.

No such book: no-such-book

)" }, - { /* url */ "/ROOT/raw/zimfile/XYZ", + { /* url */ "/ROOT%23%3F/raw/zimfile/XYZ", expected_body==R"(

Not Found

- The requested URL "/ROOT/raw/zimfile/XYZ" was not found on this server. + The requested URL "/ROOT%23%3F/raw/zimfile/XYZ" was not found on this server.

XYZ is not a valid request for raw content.

)" }, - { /* url */ "/ROOT/raw/zimfile/meta/invalid-metadata", + { /* url */ "/ROOT%23%3F/raw/zimfile/meta/invalid-metadata", expected_body==R"(

Not Found

- The requested URL "/ROOT/raw/zimfile/meta/invalid-metadata" was not found on this server. + The requested URL "/ROOT%23%3F/raw/zimfile/meta/invalid-metadata" was not found on this server.

Cannot find meta entry invalid-metadata

)" }, - { /* url */ "/ROOT/raw/zimfile/content/invalid-article", + { /* url */ "/ROOT%23%3F/raw/zimfile/content/invalid-article", expected_body==R"(

Not Found

- The requested URL "/ROOT/raw/zimfile/content/invalid-article" was not found on this server. + The requested URL "/ROOT%23%3F/raw/zimfile/content/invalid-article" was not found on this server.

Cannot find content entry invalid-article

)" }, - { /* url */ "/ROOT/search?content=poor&pattern=whatever", + { /* url */ "/ROOT%23%3F/search?content=poor&pattern=whatever", expected_page_title=="Fulltext search unavailable" && - expected_css_url=="/ROOT/skin/search_results.css?cacheid=76d39c84" && + expected_css_url=="/ROOT%23%3F/skin/search_results.css?cacheid=76d39c84" && book_name=="poor" && book_title=="poor" && expected_body==R"( @@ -804,41 +804,41 @@ TEST_F(ServerTest, Http400HtmlError) { using namespace TestingOfHtmlResponses; const std::vector testData{ - { /* url */ "/ROOT/search", + { /* url */ "/ROOT%23%3F/search", expected_body== R"(

Invalid request

- The requested URL "/ROOT/search" is not a valid request. + The requested URL "/ROOT%23%3F/search" is not a valid request.

Too many books requested (4) where limit is 3

)" }, - { /* url */ "/ROOT/search?content=zimfile", + { /* url */ "/ROOT%23%3F/search?content=zimfile", expected_body==R"(

Invalid request

- The requested URL "/ROOT/search?content=zimfile" is not a valid request. + The requested URL "/ROOT%23%3F/search?content=zimfile" is not a valid request.

No query provided.

)" }, - { /* url */ "/ROOT/search?content=non-existing-book&pattern=asdfqwerty", + { /* url */ "/ROOT%23%3F/search?content=non-existing-book&pattern=asdfqwerty", expected_body==R"(

Invalid request

- The requested URL "/ROOT/search?content=non-existing-book&pattern=asdfqwerty" is not a valid request. + The requested URL "/ROOT%23%3F/search?content=non-existing-book&pattern=asdfqwerty" is not a valid request.

No such book: non-existing-book

)" }, - { /* url */ "/ROOT/search?content=non-existing-book&pattern=a\"