diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index dd4c766b5..0edb367fc 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -1030,7 +1030,7 @@ 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 path = kiwix::urlEncode(item.getPath(), true); const auto redirectUrl = m_root + "/content/" + bookName + "/" + path; return Response::build_redirect(*this, redirectUrl); } diff --git a/test/data/corner_cases.zim b/test/data/corner_cases.zim index 650c1d962..024d34d92 100644 Binary files a/test/data/corner_cases.zim and b/test/data/corner_cases.zim differ diff --git a/test/data/corner_cases/wtf.html b/test/data/corner_cases/wtf.html new file mode 120000 index 000000000..2a9593de8 --- /dev/null +++ b/test/data/corner_cases/wtf.html @@ -0,0 +1 @@ +wtf?.html \ No newline at end of file diff --git a/test/data/corner_cases/wtf? b/test/data/corner_cases/wtf? new file mode 120000 index 000000000..2a9593de8 --- /dev/null +++ b/test/data/corner_cases/wtf? @@ -0,0 +1 @@ +wtf?.html \ No newline at end of file diff --git a/test/data/corner_cases/wtf?.html b/test/data/corner_cases/wtf?.html new file mode 100644 index 000000000..75b47246a --- /dev/null +++ b/test/data/corner_cases/wtf?.html @@ -0,0 +1,11 @@ + + + + + WTF? + + +

WTF? is an acronym coined by cryptography and security researcher Walter + Thomas Freiwald. It stands for "Will They Factorize?"

+ + diff --git a/test/data/create_corner_cases_zim_file b/test/data/create_corner_cases_zim_file index 9462a63ea..5f11096a2 100755 --- a/test/data/create_corner_cases_zim_file +++ b/test/data/create_corner_cases_zim_file @@ -2,13 +2,14 @@ cd "$(dirname "$0")" rm -f corner_cases.zim -zimwriterfs -w empty.html \ - -f empty.png \ - -l=en \ - -t="ZIM corner cases" \ - -d="" \ - -c="" \ - -p="" \ +zimwriterfs --withoutFTIndex --dont-check-arguments \ + -w empty.html \ + -I empty.png \ + -l en \ + -t "ZIM corner cases" \ + -d "" \ + -c "" \ + -p "" \ corner_cases \ corner_cases.zim \ && echo 'corner_cases.zim was successfully created' \ diff --git a/test/server.cpp b/test/server.cpp index 0780a3949..9d955bc2a 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -78,7 +78,6 @@ const ResourceCollection resources200Compressible{ { DYNAMIC_CONTENT, "/ROOT/catalog/search" }, { DYNAMIC_CONTENT, "/ROOT/catalog/v2/root.xml" }, - { DYNAMIC_CONTENT, "/ROOT/catalog/v2/languages" }, { DYNAMIC_CONTENT, "/ROOT/catalog/v2/entries" }, { DYNAMIC_CONTENT, "/ROOT/catalog/v2/partial_entries" }, @@ -150,6 +149,7 @@ const ResourceCollection resources200Uncompressible{ { DYNAMIC_CONTENT, "/ROOT/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" }, @@ -157,9 +157,9 @@ const ResourceCollection resources200Uncompressible{ { ZIM_CONTENT, "/ROOT/content/zimfile/I/m/Ray_Charles_classic_piano_pose.jpg" }, - { ZIM_CONTENT, "/ROOT/content/corner_cases/A/empty.html" }, - { ZIM_CONTENT, "/ROOT/content/corner_cases/-/empty.css" }, - { ZIM_CONTENT, "/ROOT/content/corner_cases/-/empty.js" }, + { ZIM_CONTENT, "/ROOT/content/corner_cases/empty.html" }, + { ZIM_CONTENT, "/ROOT/content/corner_cases/empty.css" }, + { ZIM_CONTENT, "/ROOT/content/corner_cases/empty.js" }, // The following url's responses are too small to be compressed @@ -1145,7 +1145,7 @@ TEST_F(ServerTest, RandomPageRedirectsToAnExistingArticle) auto g = zfs1_->GET("/ROOT/random?content=zimfile"); ASSERT_EQ(302, g->status); ASSERT_TRUE(g->has_header("Location")); - ASSERT_TRUE(kiwix::startsWith(g->get_header_value("Location"), "/ROOT/content/zimfile/A/")); + ASSERT_TRUE(kiwix::startsWith(g->get_header_value("Location"), "/ROOT/content/zimfile/A%2F")); ASSERT_EQ(getCacheControlHeader(*g), "max-age=0, must-revalidate"); ASSERT_FALSE(g->has_header("ETag")); } @@ -1196,13 +1196,24 @@ TEST_F(ServerTest, NonEndpointUrlsAreRedirectedToContentUrls) } } +TEST_F(ServerTest, RedirectionsToURLsWithSpecialSymbols) +{ + auto g = zfs1_->GET("/ROOT/content/corner_cases/wtf.html"); + ASSERT_EQ(302, g->status); + ASSERT_TRUE(g->has_header("Location")); + ASSERT_EQ(g->get_header_value("Location"), "/ROOT/content/corner_cases/wtf%3F.html"); + ASSERT_EQ(getCacheControlHeader(*g), "max-age=0, must-revalidate"); + ASSERT_FALSE(g->has_header("ETag")); +} + + TEST_F(ServerTest, BookMainPageIsRedirectedToArticleIndex) { { auto g = zfs1_->GET("/ROOT/content/zimfile"); ASSERT_EQ(302, g->status); ASSERT_TRUE(g->has_header("Location")); - ASSERT_EQ("/ROOT/content/zimfile/A/index", g->get_header_value("Location")); + ASSERT_EQ("/ROOT/content/zimfile/A%2Findex", g->get_header_value("Location")); } } @@ -1507,7 +1518,7 @@ TEST_F(ServerTest, InvalidAndMultiRangeByteRangeRequestsResultIn416Responses) TEST_F(ServerTest, ValidByteRangeRequestsOfZeroSizedEntriesResultIn416Responses) { - const char url[] = "/ROOT/content/corner_cases/-/empty.js"; + const char url[] = "/ROOT/content/corner_cases/empty.js"; const char* ranges[] = { "bytes=0-",