From 8551b7e98ecaa4ea543755ef6d585f9e8f79dde6 Mon Sep 17 00:00:00 2001 From: Matthieu Gautier Date: Wed, 8 Dec 2021 16:15:39 +0100 Subject: [PATCH] Add `raw` endpoint. As the name suggests it, this endpoint is not smart : It returns the content as it is and only if it is present (no compatibility or whatever). The only "smart" thing is to return a redirect if the entry is a redirect. --- src/server/internalServer.cpp | 57 +++++++++++++++++++++++++++++++++++ src/server/internalServer.h | 1 + test/server.cpp | 29 ++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index 6ff949380..06cfa3c58 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -283,6 +283,9 @@ std::unique_ptr InternalServer::handle_request(const RequestContext& r if (startsWith(request.get_url(), "/catalog/")) return handle_catalog(request); + if (startsWith(request.get_url(), "/raw/")) + return handle_raw(request); + if (request.get_url() == "/meta") return handle_meta(request); @@ -891,4 +894,58 @@ std::unique_ptr InternalServer::handle_content(const RequestContext& r } } + +std::unique_ptr InternalServer::handle_raw(const RequestContext& request) +{ + if (m_verbose.load()) { + printf("** running handle_raw\n"); + } + + std::string bookName; + std::string kind; + try { + bookName = request.get_url_part(1); + kind = request.get_url_part(2); + } catch (const std::out_of_range& e) { + return Response::build_404(*this, request, bookName, "", ""); + } + + if (kind != "meta" && kind!= "content") { + return Response::build_404(*this, request, bookName, "", ""); + } + + std::shared_ptr archive; + try { + const std::string bookId = mp_nameMapper->getIdForName(bookName); + archive = mp_library->getArchiveById(bookId); + } catch (const std::out_of_range& e) {} + + if (archive == nullptr) { + return Response::build_404(*this, request, bookName, "", ""); + } + + auto itemPath = request.get_url().substr(bookName.size()+kind.size()+6); + if (itemPath[0] == '/') { + itemPath = itemPath.substr(1); + } + + try { + if (kind == "meta") { + auto item = archive->getMetadataItem(itemPath); + return ItemResponse::build(*this, request, item, true); + } else { + auto entry = archive->getEntryByPath(itemPath); + if (entry.isRedirect()) { + return build_redirect(bookName, entry.getItem(true)); + } + return ItemResponse::build(*this, request, entry.getItem(), true); + } + } catch (zim::EntryNotFound& e ) { + if (m_verbose.load()) { + printf("Failed to find %s\n", itemPath.c_str()); + } + return Response::build_404(*this, request, bookName, getArchiveTitle(*archive), ""); + } +} + } diff --git a/src/server/internalServer.h b/src/server/internalServer.h index 7b935a126..658fe5eae 100644 --- a/src/server/internalServer.h +++ b/src/server/internalServer.h @@ -86,6 +86,7 @@ class InternalServer { std::unique_ptr handle_random(const RequestContext& request); std::unique_ptr handle_captured_external(const RequestContext& request); std::unique_ptr handle_content(const RequestContext& request); + std::unique_ptr handle_raw(const RequestContext& request); std::vector search_catalog(const RequestContext& request, kiwix::OPDSDumper& opdsDumper); diff --git a/test/server.cpp b/test/server.cpp index afffee224..d71f1cb99 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -185,6 +185,9 @@ const ResourceCollection resources200Compressible{ { WITH_ETAG, "/zimfile/A/index" }, { WITH_ETAG, "/zimfile/A/Ray_Charles" }, + + { WITH_ETAG, "/raw/zimfile/content/A/index" }, + { WITH_ETAG, "/raw/zimfile/content/A/Ray_Charles" }, }; const ResourceCollection resources200Uncompressible{ @@ -207,6 +210,10 @@ const ResourceCollection resources200Uncompressible{ { WITH_ETAG, "/corner_cases/A/empty.html" }, { WITH_ETAG, "/corner_cases/-/empty.css" }, { WITH_ETAG, "/corner_cases/-/empty.js" }, + + // The title and creator are too small to be compressed + { WITH_ETAG, "/raw/zimfile/meta/Creator" }, + { WITH_ETAG, "/raw/zimfile/meta/Title" }, }; ResourceCollection all200Resources() @@ -310,6 +317,28 @@ TEST_F(ServerTest, BookMainPageIsRedirectedToArticleIndex) ASSERT_EQ("/zimfile/A/index", g->get_header_value("Location")); } + +TEST_F(ServerTest, RawEntry) +{ + auto p = zfs1_->GET("/raw/zimfile/meta/Title"); + EXPECT_EQ(200, p->status); + EXPECT_EQ(p->body, std::string("Ray Charles")); + + p = zfs1_->GET("/raw/zimfile/meta/Creator"); + EXPECT_EQ(200, p->status); + EXPECT_EQ(p->body, std::string("Wikipedia")); + + // The raw content of Ray_Charles doesn't contain a taskbar... + p = zfs1_->GET("/raw/zimfile/content/A/Ray_Charles"); + EXPECT_EQ(200, p->status); + EXPECT_TRUE(p->body.find("taskbar") == std::string::npos); + + // ... but the "normal" content does. + p = zfs1_->GET("/zimfile/A/Ray_Charles"); + EXPECT_EQ(200, p->status); + EXPECT_TRUE(p->body.find("taskbar") != std::string::npos); +} + TEST_F(ServerTest, HeadMethodIsSupported) { for ( const Resource& res : all200Resources() )