mirror of https://github.com/kiwix/libkiwix.git
Introduced /content endpoint
Book content is now served under /content/book/... The old access to book content via a top-level URL /book/... is so far preserved for backward compatibility. Redirects were changed to use the new URL scheme. Links in the search results still use the old scheme.
This commit is contained in:
parent
a4b18893aa
commit
1b1c1e352e
|
@ -545,6 +545,9 @@ std::unique_ptr<Response> InternalServer::handle_request(const RequestContext& r
|
|||
if (startsWith(request.get_url(), "/skin/"))
|
||||
return handle_skin(request);
|
||||
|
||||
if (startsWith(request.get_url(), "/content/"))
|
||||
return handle_content(request);
|
||||
|
||||
if (startsWith(request.get_url(), "/catalog/"))
|
||||
return handle_catalog(request);
|
||||
|
||||
|
@ -922,15 +925,6 @@ InternalServer::search_catalog(const RequestContext& request,
|
|||
namespace
|
||||
{
|
||||
|
||||
std::string get_book_name(const RequestContext& request)
|
||||
{
|
||||
try {
|
||||
return request.get_url_part(0);
|
||||
} catch (const std::out_of_range& e) {
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
ParameterizedMessage suggestSearchMsg(const std::string& searchURL, const std::string& pattern)
|
||||
{
|
||||
return ParameterizedMessage("suggest-search",
|
||||
|
@ -945,7 +939,8 @@ ParameterizedMessage suggestSearchMsg(const std::string& searchURL, const std::s
|
|||
std::unique_ptr<Response>
|
||||
InternalServer::build_redirect(const std::string& bookName, const zim::Item& item) const
|
||||
{
|
||||
auto redirectUrl = m_root + "/" + bookName + "/" + kiwix::urlEncode(item.getPath());
|
||||
const auto path = kiwix::urlEncode(item.getPath());
|
||||
const auto redirectUrl = m_root + "/content/" + bookName + "/" + path;
|
||||
return Response::build_redirect(*this, redirectUrl);
|
||||
}
|
||||
|
||||
|
@ -957,7 +952,10 @@ std::unique_ptr<Response> InternalServer::handle_content(const RequestContext& r
|
|||
printf("** running handle_content\n");
|
||||
}
|
||||
|
||||
const std::string bookName = get_book_name(request);
|
||||
const std::string contentPrefix = "/content/";
|
||||
const bool isContentPrefixedUrl = startsWith(url, contentPrefix);
|
||||
const size_t prefixLength = isContentPrefixedUrl ? contentPrefix.size() : 1;
|
||||
const std::string bookName = request.get_url_part(isContentPrefixedUrl);
|
||||
|
||||
std::shared_ptr<zim::Archive> archive;
|
||||
try {
|
||||
|
@ -973,7 +971,7 @@ std::unique_ptr<Response> InternalServer::handle_content(const RequestContext& r
|
|||
+ TaskbarInfo(bookName);
|
||||
}
|
||||
|
||||
auto urlStr = request.get_url().substr(bookName.size()+1);
|
||||
auto urlStr = url.substr(prefixLength + bookName.size());
|
||||
if (urlStr[0] == '/') {
|
||||
urlStr = urlStr.substr(1);
|
||||
}
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
/ text/html ./test/welcome.html
|
||||
/skin/index.css application/json ./test/helloworld.txt
|
||||
/zimfile/A/Ray_Charles ray/charles ./test/welcome.html
|
||||
/content/zimfile/A/Ray_Charles charles/ray ./test/welcome.html
|
||||
/search text/html ./test/helloworld.txt
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#define SERVER_PORT 8001
|
||||
#include "server_testing_tools.h"
|
||||
|
||||
#include "../src/tools/stringTools.h"
|
||||
|
||||
|
||||
bool is_valid_etag(const std::string& etag)
|
||||
{
|
||||
|
@ -56,6 +58,9 @@ const ResourceCollection resources200Compressible{
|
|||
{ WITH_ETAG, "/ROOT/zimfile/A/index" },
|
||||
{ WITH_ETAG, "/ROOT/zimfile/A/Ray_Charles" },
|
||||
|
||||
{ WITH_ETAG, "/ROOT/content/zimfile/A/index" },
|
||||
{ WITH_ETAG, "/ROOT/content/zimfile/A/Ray_Charles" },
|
||||
|
||||
{ WITH_ETAG, "/ROOT/raw/zimfile/content/A/index" },
|
||||
{ WITH_ETAG, "/ROOT/raw/zimfile/content/A/Ray_Charles" },
|
||||
};
|
||||
|
@ -75,11 +80,17 @@ const ResourceCollection resources200Uncompressible{
|
|||
{ NO_ETAG, "/ROOT/catalog/v2/illustration/6f1d19d0-633f-087b-fb55-7ac324ff9baf?size=48" },
|
||||
|
||||
{ WITH_ETAG, "/ROOT/zimfile/I/m/Ray_Charles_classic_piano_pose.jpg" },
|
||||
{ WITH_ETAG, "/ROOT/content/zimfile/I/m/Ray_Charles_classic_piano_pose.jpg" },
|
||||
|
||||
{ WITH_ETAG, "/ROOT/corner_cases/A/empty.html" },
|
||||
{ WITH_ETAG, "/ROOT/corner_cases/-/empty.css" },
|
||||
{ WITH_ETAG, "/ROOT/corner_cases/-/empty.js" },
|
||||
|
||||
{ WITH_ETAG, "/ROOT/content/corner_cases/A/empty.html" },
|
||||
{ WITH_ETAG, "/ROOT/content/corner_cases/-/empty.css" },
|
||||
{ WITH_ETAG, "/ROOT/content/corner_cases/-/empty.js" },
|
||||
|
||||
|
||||
// The following url's responses are too small to be compressed
|
||||
{ NO_ETAG, "/ROOT/catalog/root.xml" },
|
||||
{ NO_ETAG, "/ROOT/catalog/searchdescription.xml" },
|
||||
|
@ -197,6 +208,15 @@ R"EXPECTEDRESULT( <img src="../skin/download.png?
|
|||
R"EXPECTEDRESULT(<link type="root" href="/ROOT"><link type="text/css" href="/ROOT/skin/taskbar.css?cacheid=26082885" rel="Stylesheet" />
|
||||
<link type="text/css" href="/ROOT/skin/css/autoComplete.css?cacheid=08951e06" rel="Stylesheet" />
|
||||
<script type="text/javascript" src="/ROOT/skin/taskbar.js?cacheid=1aec4a68" defer></script>
|
||||
<script type="text/javascript" src="/ROOT/skin/autoComplete.min.js?cacheid=1191aaaf"></script>
|
||||
<label for="kiwix_button_show_toggle"><img src="/ROOT/skin/caret.png?cacheid=22b942b4" alt=""></label>
|
||||
)EXPECTEDRESULT"
|
||||
},
|
||||
{
|
||||
/* url */ "/ROOT/content/zimfile/A/index",
|
||||
R"EXPECTEDRESULT(<link type="root" href="/ROOT"><link type="text/css" href="/ROOT/skin/taskbar.css?cacheid=26082885" rel="Stylesheet" />
|
||||
<link type="text/css" href="/ROOT/skin/css/autoComplete.css?cacheid=08951e06" rel="Stylesheet" />
|
||||
<script type="text/javascript" src="/ROOT/skin/taskbar.js?cacheid=1aec4a68" defer></script>
|
||||
<script type="text/javascript" src="/ROOT/skin/autoComplete.min.js?cacheid=1191aaaf"></script>
|
||||
<label for="kiwix_button_show_toggle"><img src="/ROOT/skin/caret.png?cacheid=22b942b4" alt=""></label>
|
||||
)EXPECTEDRESULT"
|
||||
|
@ -265,6 +285,7 @@ const char* urls404[] = {
|
|||
"/ROOT/suggest?content=non-existent-book&term=abcd",
|
||||
"/ROOT/catch/external",
|
||||
"/ROOT/zimfile/A/non-existent-article",
|
||||
"/ROOT/content/zimfile/A/non-existent-article",
|
||||
|
||||
"/ROOT/raw/non-existent-book/meta/Title",
|
||||
"/ROOT/raw/zimfile/wrong-kind/Foo",
|
||||
|
@ -335,6 +356,13 @@ TEST_F(CustomizedServerTest, ContentOfAnyServableUrlCanBeOverriden)
|
|||
EXPECT_EQ(r->body, "<html><head></head><body>Welcome</body></html>\n");
|
||||
}
|
||||
|
||||
{
|
||||
const auto r = zfs1_->GET("/ROOT/content/zimfile/A/Ray_Charles");
|
||||
EXPECT_EQ(r->status, 200);
|
||||
EXPECT_EQ(getHeaderValue(r->headers, "Content-Type"), "charles/ray");
|
||||
EXPECT_EQ(r->body, "<html><head></head><body>Welcome</body></html>\n");
|
||||
}
|
||||
|
||||
{
|
||||
const auto r = zfs1_->GET("/ROOT/search?pattern=la+femme");
|
||||
EXPECT_EQ(r->status, 200);
|
||||
|
@ -685,6 +713,19 @@ TEST_F(ServerTest, Http404HtmlError)
|
|||
</p>
|
||||
)" },
|
||||
|
||||
{ /* url */ "/ROOT/content/zimfile/invalid-article",
|
||||
book_name=="zimfile" &&
|
||||
book_title=="Ray Charles" &&
|
||||
expected_body==R"(
|
||||
<h1>Not Found</h1>
|
||||
<p>
|
||||
The requested URL "/ROOT/content/zimfile/invalid-article" was not found on this server.
|
||||
</p>
|
||||
<p>
|
||||
Make a full text search for <a href="/ROOT/search?content=zimfile&pattern=invalid-article">invalid-article</a>
|
||||
</p>
|
||||
)" },
|
||||
|
||||
{ /* url */ R"(/ROOT/"><svg onload=alert(1)>)",
|
||||
expected_body==R"(
|
||||
<h1>Not Found</h1>
|
||||
|
@ -709,6 +750,19 @@ TEST_F(ServerTest, Http404HtmlError)
|
|||
</p>
|
||||
)" },
|
||||
|
||||
{ /* url */ R"(/ROOT/content/zimfile/"><svg onload=alert(1)>)",
|
||||
book_name=="zimfile" &&
|
||||
book_title=="Ray Charles" &&
|
||||
expected_body==R"(
|
||||
<h1>Not Found</h1>
|
||||
<p>
|
||||
The requested URL "/ROOT/content/zimfile/"><svg onload=alert(1)>" was not found on this server.
|
||||
</p>
|
||||
<p>
|
||||
Make a full text search for <a href="/ROOT/search?content=zimfile&pattern=%22%3E%3Csvg%20onload%3Dalert(1)%3E">"><svg onload=alert(1)></a>
|
||||
</p>
|
||||
)" },
|
||||
|
||||
{ /* url */ "/ROOT/zimfile/invalid-article?userlang=hy",
|
||||
expected_page_title=="Սխալ հասցե" &&
|
||||
book_name=="zimfile" &&
|
||||
|
@ -723,6 +777,20 @@ TEST_F(ServerTest, Http404HtmlError)
|
|||
</p>
|
||||
)" },
|
||||
|
||||
{ /* url */ "/ROOT/content/zimfile/invalid-article?userlang=hy",
|
||||
expected_page_title=="Սխալ հասցե" &&
|
||||
book_name=="zimfile" &&
|
||||
book_title=="Ray Charles" &&
|
||||
expected_body==R"(
|
||||
<h1>Սխալ հասցե</h1>
|
||||
<p>
|
||||
Սխալ հասցե՝ /ROOT/content/zimfile/invalid-article
|
||||
</p>
|
||||
<p>
|
||||
Որոնել <a href="/ROOT/search?content=zimfile&pattern=invalid-article">invalid-article</a>
|
||||
</p>
|
||||
)" },
|
||||
|
||||
{ /* url */ "/ROOT/raw/no-such-book/meta/Title",
|
||||
expected_body==R"(
|
||||
<h1>Not Found</h1>
|
||||
|
@ -964,11 +1032,19 @@ TEST_F(ServerTest, 500)
|
|||
</html>
|
||||
)";
|
||||
|
||||
{
|
||||
const auto r = zfs1_->GET("/ROOT/poor/A/redirect_loop.html");
|
||||
EXPECT_EQ(r->status, 500);
|
||||
EXPECT_EQ(r->body, expectedBody);
|
||||
}
|
||||
|
||||
{
|
||||
const auto r = zfs1_->GET("/ROOT/content/poor/A/redirect_loop.html");
|
||||
EXPECT_EQ(r->status, 500);
|
||||
EXPECT_EQ(r->body, expectedBody);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, UserLanguageControl)
|
||||
{
|
||||
struct TestData
|
||||
|
@ -1047,15 +1123,24 @@ 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(g->get_header_value("Location").find("/zimfile/A/") != std::string::npos);
|
||||
ASSERT_TRUE(kiwix::startsWith(g->get_header_value("Location"), "/ROOT/content/zimfile/A/"));
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, BookMainPageIsRedirectedToArticleIndex)
|
||||
{
|
||||
{
|
||||
auto g = zfs1_->GET("/ROOT/zimfile");
|
||||
ASSERT_EQ(302, g->status);
|
||||
ASSERT_TRUE(g->has_header("Location"));
|
||||
ASSERT_EQ("/ROOT/zimfile/A/index", g->get_header_value("Location"));
|
||||
ASSERT_EQ("/ROOT/content/zimfile/A/index", g->get_header_value("Location"));
|
||||
}
|
||||
|
||||
{
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1082,6 +1167,12 @@ TEST_F(ServerTest, RawEntry)
|
|||
EXPECT_EQ(200, p->status);
|
||||
EXPECT_NE(std::string(p->body), std::string(entry.getItem(true).getData()));
|
||||
EXPECT_TRUE(p->body.find("taskbar") != std::string::npos);
|
||||
|
||||
// ... but the "normal" content is not
|
||||
p = zfs1_->GET("/ROOT/content/zimfile/A/Ray_Charles");
|
||||
EXPECT_EQ(200, p->status);
|
||||
EXPECT_NE(std::string(p->body), std::string(entry.getItem(true).getData()));
|
||||
EXPECT_TRUE(p->body.find("taskbar") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, HeadMethodIsSupported)
|
||||
|
|
Loading…
Reference in New Issue