diff --git a/include/manager.h b/include/manager.h index d0addad70..91dfca5e9 100644 --- a/include/manager.h +++ b/include/manager.h @@ -37,10 +37,10 @@ namespace kiwix class LibraryManipulator { public: // functions - explicit LibraryManipulator(Library* library); + explicit LibraryManipulator(std::shared_ptr library); virtual ~LibraryManipulator(); - Library& getLibrary() const { return library; } + Library& getLibrary() const { return *library.get(); } bool addBookToLibrary(const Book& book); void addBookmarkToLibrary(const Bookmark& bookmark); @@ -52,7 +52,7 @@ class LibraryManipulator virtual void booksWereRemovedFromLibrary(); private: // data - kiwix::Library& library; + std::shared_ptr library; }; /** @@ -65,7 +65,7 @@ class Manager public: // functions explicit Manager(LibraryManipulator* manipulator); - explicit Manager(Library* library); + explicit Manager(std::shared_ptr library); /** * Read a `library.xml` and add book in the file to the library. diff --git a/include/name_mapper.h b/include/name_mapper.h index 4247c5c3c..13a428133 100644 --- a/include/name_mapper.h +++ b/include/name_mapper.h @@ -50,7 +50,7 @@ class HumanReadableNameMapper : public NameMapper { std::map m_nameToId; public: - HumanReadableNameMapper(kiwix::Library& library, bool withAlias); + HumanReadableNameMapper(const kiwix::Library& library, bool withAlias); virtual ~HumanReadableNameMapper() = default; virtual std::string getNameForId(const std::string& id) const; virtual std::string getIdForName(const std::string& name) const; @@ -59,7 +59,7 @@ class HumanReadableNameMapper : public NameMapper { class UpdatableNameMapper : public NameMapper { typedef std::shared_ptr NameMapperHandle; public: - UpdatableNameMapper(Library& library, bool withAlias); + UpdatableNameMapper(std::shared_ptr library, bool withAlias); virtual std::string getNameForId(const std::string& id) const; virtual std::string getIdForName(const std::string& name) const; @@ -71,7 +71,7 @@ class UpdatableNameMapper : public NameMapper { private: mutable std::mutex mutex; - Library& library; + std::shared_ptr library; NameMapperHandle nameMapper; const bool withAlias; }; diff --git a/include/opds_dumper.h b/include/opds_dumper.h index c824493de..f16678a27 100644 --- a/include/opds_dumper.h +++ b/include/opds_dumper.h @@ -23,10 +23,11 @@ #include #include #include +#include #include -#include "library.h" +#include "server.h" using namespace std; @@ -40,8 +41,7 @@ namespace kiwix class OPDSDumper { public: - OPDSDumper() = default; - OPDSDumper(Library* library); + OPDSDumper(Server::Configuration configuration); ~OPDSDumper(); /** @@ -92,13 +92,6 @@ class OPDSDumper */ void setLibraryId(const std::string& id) { this->libraryId = id;} - /** - * Set the root location used when generating url. - * - * @param rootLocation the root location to use. - */ - void setRootLocation(const std::string& rootLocation) { this->rootLocation = rootLocation; } - /** * Set some informations about the search results. * @@ -109,9 +102,8 @@ class OPDSDumper void setOpenSearchInfo(int totalResult, int startIndex, int count); protected: - kiwix::Library* library; + Server::Configuration m_configuration; std::string libraryId; - std::string rootLocation; int m_totalResults; int m_startIndex; int m_count; diff --git a/include/search_renderer.h b/include/search_renderer.h index 0190ee5f0..bd434517d 100644 --- a/include/search_renderer.h +++ b/include/search_renderer.h @@ -46,7 +46,7 @@ class SearchRenderer * @param start The start offset used for the srs. * @param estimatedResultCount The estimatedResultCount of the whole search */ - SearchRenderer(zim::SearchResultSet srs, NameMapper* mapper, + SearchRenderer(zim::SearchResultSet srs, std::shared_ptr mapper, unsigned int start, unsigned int estimatedResultCount); /** @@ -58,7 +58,7 @@ class SearchRenderer * @param start The start offset used for the srs. * @param estimatedResultCount The estimatedResultCount of the whole search */ - SearchRenderer(zim::SearchResultSet srs, NameMapper* mapper, Library* library, + SearchRenderer(zim::SearchResultSet srs, std::shared_ptr mapper, std::shared_ptr library, unsigned int start, unsigned int estimatedResultCount); ~SearchRenderer(); @@ -106,8 +106,8 @@ class SearchRenderer protected: std::string beautifyInteger(const unsigned int number); zim::SearchResultSet m_srs; - NameMapper* mp_nameMapper; - Library* mp_library; + std::shared_ptr mp_nameMapper; + std::shared_ptr mp_library; std::string searchBookQuery; std::string searchPattern; std::string protocolPrefix; diff --git a/include/server.h b/include/server.h index 0cd579c57..b79c24699 100644 --- a/include/server.h +++ b/include/server.h @@ -29,15 +29,81 @@ namespace kiwix class NameMapper; class InternalServer; + class Server { - public: + public: + class Configuration { + public: + explicit Configuration(std::shared_ptr library, std::shared_ptr nameMapper=nullptr); + + Configuration& setRoot(const std::string& root); + Configuration& setAddress(const std::string& addr) { + m_addr = addr; + return *this; + } + + Configuration& setPort(int port) { + m_port = port; + return *this; + } + + Configuration& setNbThreads(int threads) { + m_nbThreads = threads; + return *this; + } + + Configuration& setMultiZimSearchLimit(unsigned int limit) { + m_multizimSearchLimit = limit; + return *this; + } + + Configuration& setIpConnectionLimit(int limit) { + m_ipConnectionLimit = limit; + return *this; + } + + Configuration& setVerbose(bool verbose) { + m_verbose = verbose; + return *this; + } + + Configuration& setIndexTemplateString(const std::string& indexTemplateString) { + m_indexTemplateString = indexTemplateString; + return *this; + } + + Configuration& setTaskbar(bool withTaskbar, bool withLibraryButton) { + m_withTaskbar = withTaskbar; + m_withLibraryButton = withLibraryButton; + return *this; + } + + Configuration& setBlockExternalLinks(bool blockExternalLinks) { + m_blockExternalLinks = blockExternalLinks; + return *this; + } + + std::shared_ptr mp_library; + std::shared_ptr mp_nameMapper; + std::string m_root = ""; + std::string m_addr = ""; + std::string m_indexTemplateString = ""; + int m_port = 80; + int m_nbThreads = 1; + unsigned int m_multizimSearchLimit = 0; + bool m_verbose = false; + bool m_withTaskbar = true; + bool m_withLibraryButton = true; + bool m_blockExternalLinks = false; + int m_ipConnectionLimit = 0; + }; + /** * The default constructor. * * @param library The library to serve. */ - Server(Library* library, NameMapper* nameMapper=nullptr); - + explicit Server(const Configuration& configuration); virtual ~Server(); /** @@ -50,35 +116,22 @@ namespace kiwix */ void stop(); - void setRoot(const std::string& root); - void setAddress(const std::string& addr) { m_addr = addr; } - void setPort(int port) { m_port = port; } - void setNbThreads(int threads) { m_nbThreads = threads; } - void setMultiZimSearchLimit(unsigned int limit) { m_multizimSearchLimit = limit; } - void setIpConnectionLimit(int limit) { m_ipConnectionLimit = limit; } - void setVerbose(bool verbose) { m_verbose = verbose; } - void setIndexTemplateString(const std::string& indexTemplateString) { m_indexTemplateString = indexTemplateString; } - void setTaskbar(bool withTaskbar, bool withLibraryButton) - { m_withTaskbar = withTaskbar; m_withLibraryButton = withLibraryButton; } - void setBlockExternalLinks(bool blockExternalLinks) - { m_blockExternalLinks = blockExternalLinks; } + /** + * Tell if the server is running or not. + */ + bool isRunning(); + + /** + * Get the port of the server + */ int getPort(); + + /** + * Get the ipAddress of the server + */ std::string getAddress(); protected: - Library* mp_library; - NameMapper* mp_nameMapper; - std::string m_root = ""; - std::string m_addr = ""; - std::string m_indexTemplateString = ""; - int m_port = 80; - int m_nbThreads = 1; - unsigned int m_multizimSearchLimit = 0; - bool m_verbose = false; - bool m_withTaskbar = true; - bool m_withLibraryButton = true; - bool m_blockExternalLinks = false; - int m_ipConnectionLimit = 0; std::unique_ptr mp_server; }; } diff --git a/src/manager.cpp b/src/manager.cpp index 3f24fad17..4feb0a96e 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -41,8 +41,8 @@ struct NoDelete // LibraryManipulator //////////////////////////////////////////////////////////////////////////////// -LibraryManipulator::LibraryManipulator(Library* library) - : library(*library) +LibraryManipulator::LibraryManipulator(std::shared_ptr library) + : library(library) {} LibraryManipulator::~LibraryManipulator() @@ -50,7 +50,7 @@ LibraryManipulator::~LibraryManipulator() bool LibraryManipulator::addBookToLibrary(const Book& book) { - const auto ret = library.addBook(book); + const auto ret = library->addBook(book); if ( ret ) { bookWasAddedToLibrary(book); } @@ -59,13 +59,13 @@ bool LibraryManipulator::addBookToLibrary(const Book& book) void LibraryManipulator::addBookmarkToLibrary(const Bookmark& bookmark) { - library.addBookmark(bookmark); + library->addBookmark(bookmark); bookmarkWasAddedToLibrary(bookmark); } uint32_t LibraryManipulator::removeBooksNotUpdatedSince(Library::Revision rev) { - const auto n = library.removeBooksNotUpdatedSince(rev); + const auto n = library->removeBooksNotUpdatedSince(rev); if ( n != 0 ) { booksWereRemovedFromLibrary(); } @@ -95,7 +95,7 @@ Manager::Manager(LibraryManipulator* manipulator): { } -Manager::Manager(Library* library) : +Manager::Manager(std::shared_ptr library) : writableLibraryPath(""), manipulator(new LibraryManipulator(library)) { diff --git a/src/name_mapper.cpp b/src/name_mapper.cpp index dccf40c9b..17c1cf23f 100644 --- a/src/name_mapper.cpp +++ b/src/name_mapper.cpp @@ -24,7 +24,7 @@ namespace kiwix { -HumanReadableNameMapper::HumanReadableNameMapper(kiwix::Library& library, bool withAlias) { +HumanReadableNameMapper::HumanReadableNameMapper(const kiwix::Library& library, bool withAlias) { for (auto& bookId: library.filter(kiwix::Filter().local(true).valid(true))) { auto& currentBook = library.getBookById(bookId); auto bookName = currentBook.getHumanReadableIdFromPath(); @@ -63,7 +63,7 @@ std::string HumanReadableNameMapper::getIdForName(const std::string& name) const // UpdatableNameMapper //////////////////////////////////////////////////////////////////////////////// -UpdatableNameMapper::UpdatableNameMapper(Library& lib, bool withAlias) +UpdatableNameMapper::UpdatableNameMapper(std::shared_ptr lib, bool withAlias) : library(lib) , withAlias(withAlias) { @@ -72,7 +72,7 @@ UpdatableNameMapper::UpdatableNameMapper(Library& lib, bool withAlias) void UpdatableNameMapper::update() { - const auto newNameMapper = new HumanReadableNameMapper(library, withAlias); + const auto newNameMapper = new HumanReadableNameMapper(*library, withAlias); std::lock_guard lock(mutex); nameMapper.reset(newNameMapper); } diff --git a/src/opds_dumper.cpp b/src/opds_dumper.cpp index 7436ebc29..40b2f87a1 100644 --- a/src/opds_dumper.cpp +++ b/src/opds_dumper.cpp @@ -19,6 +19,8 @@ #include "opds_dumper.h" #include "book.h" +#include "library.h" +#include "name_mapper.h" #include "libkiwix-resources.h" #include @@ -30,8 +32,8 @@ namespace kiwix { /* Constructor */ -OPDSDumper::OPDSDumper(Library* library) - : library(library) +OPDSDumper::OPDSDumper(Server::Configuration configuration) + : m_configuration(configuration) { } /* Destructor */ @@ -71,17 +73,17 @@ IllustrationInfo getBookIllustrationInfo(const Book& book) return illustrations; } -std::string fullEntryXML(const Book& book, const std::string& rootLocation) +std::string fullEntryXML(const Server::Configuration& configuration, const Book& book) { const auto bookDate = book.getDate() + "T00:00:00Z"; const kainjow::mustache::object data{ - {"root", rootLocation}, + {"root", configuration.m_root}, {"id", book.getId()}, {"name", book.getName()}, {"title", book.getTitle()}, {"description", book.getDescription()}, {"language", book.getLanguage()}, - {"content_id", urlEncode(book.getHumanReadableIdFromPath(), true)}, + {"content_id", urlEncode(configuration.mp_nameMapper->getNameForId(book.getId()), true)}, {"updated", bookDate}, // XXX: this should be the entry update datetime {"book_date", bookDate}, {"category", book.getCategory()}, @@ -98,12 +100,12 @@ std::string fullEntryXML(const Book& book, const std::string& rootLocation) return render_template(RESOURCE::templates::catalog_v2_entry_xml, data); } -std::string partialEntryXML(const Book& book, const std::string& rootLocation) +std::string partialEntryXML(const Server::Configuration& configuration, const Book& book) { const auto bookDate = book.getDate() + "T00:00:00Z"; const kainjow::mustache::object data{ - {"root", rootLocation}, - {"endpoint_root", rootLocation + "/catalog/v2"}, + {"root", configuration.m_root}, + {"endpoint_root", configuration.m_root + "/catalog/v2"}, {"id", book.getId()}, {"title", book.getTitle()}, {"updated", bookDate}, // XXX: this should be the entry update datetime @@ -112,15 +114,15 @@ std::string partialEntryXML(const Book& book, const std::string& rootLocation) return render_template(xmlTemplate, data); } -BooksData getBooksData(const Library* library, const std::vector& bookIds, const std::string& rootLocation, bool partial) +BooksData getBooksData(const Server::Configuration& configuration, const std::vector& bookIds, bool partial) { BooksData booksData; for ( const auto& bookId : bookIds ) { try { - const Book book = library->getBookByIdThreadSafe(bookId); + const Book book = configuration.mp_library->getBookByIdThreadSafe(bookId); const auto entryXML = partial - ? partialEntryXML(book, rootLocation) - : fullEntryXML(book, rootLocation); + ? partialEntryXML(configuration, book) + : fullEntryXML(configuration, book); booksData.push_back(kainjow::mustache::object{ {"entry", entryXML} }); } catch ( const std::out_of_range& ) { // the book was removed from the library since its id was obtained @@ -188,10 +190,10 @@ std::string getLanguageSelfName(const std::string& lang) { string OPDSDumper::dumpOPDSFeed(const std::vector& bookIds, const std::string& query) const { - const auto booksData = getBooksData(library, bookIds, rootLocation, false); + const auto booksData = getBooksData(m_configuration, bookIds, false); const kainjow::mustache::object template_data{ {"date", gen_date_str()}, - {"root", rootLocation}, + {"root", m_configuration.m_root}, {"feed_id", gen_uuid(libraryId + "/catalog/search?"+query)}, {"filter", onlyAsNonEmptyMustacheValue(query)}, {"totalResults", to_string(m_totalResults)}, @@ -205,8 +207,8 @@ string OPDSDumper::dumpOPDSFeed(const std::vector& bookIds, const s string OPDSDumper::dumpOPDSFeedV2(const std::vector& bookIds, const std::string& query, bool partial) const { - const auto endpointRoot = rootLocation + "/catalog/v2"; - const auto booksData = getBooksData(library, bookIds, rootLocation, partial); + const auto endpointRoot = m_configuration.m_root + "/catalog/v2"; + const auto booksData = getBooksData(m_configuration, bookIds, partial); const char* const endpoint = partial ? "/partial_entries" : "/entries"; const kainjow::mustache::object template_data{ @@ -227,17 +229,17 @@ string OPDSDumper::dumpOPDSFeedV2(const std::vector& bookIds, const std::string OPDSDumper::dumpOPDSCompleteEntry(const std::string& bookId) const { - const auto book = library->getBookById(bookId); + const auto book = m_configuration.mp_library->getBookById(bookId); return XML_HEADER + "\n" - + fullEntryXML(book, rootLocation); + + fullEntryXML(m_configuration, book); } std::string OPDSDumper::categoriesOPDSFeed() const { const auto now = gen_date_str(); kainjow::mustache::list categoryData; - for ( const auto& category : library->getBooksCategories() ) { + for ( const auto& category : m_configuration.mp_library->getBooksCategories() ) { const auto urlencodedCategoryName = urlEncode(category); categoryData.push_back(kainjow::mustache::object{ {"name", category}, @@ -251,7 +253,7 @@ std::string OPDSDumper::categoriesOPDSFeed() const RESOURCE::templates::catalog_v2_categories_xml, kainjow::mustache::object{ {"date", now}, - {"endpoint_root", rootLocation + "/catalog/v2"}, + {"endpoint_root", m_configuration.m_root + "/catalog/v2"}, {"feed_id", gen_uuid(libraryId + "/categories")}, {"categories", categoryData } } @@ -263,7 +265,7 @@ std::string OPDSDumper::languagesOPDSFeed() const const auto now = gen_date_str(); kainjow::mustache::list languageData; std::call_once(fillLanguagesFlag, fillLanguagesMap); - for ( const auto& langAndBookCount : library->getBooksLanguagesWithCounts() ) { + for ( const auto& langAndBookCount : m_configuration.mp_library->getBooksLanguagesWithCounts() ) { const std::string languageCode = langAndBookCount.first; const int bookCount = langAndBookCount.second; const auto languageSelfName = getLanguageSelfName(languageCode); @@ -280,7 +282,7 @@ std::string OPDSDumper::languagesOPDSFeed() const RESOURCE::templates::catalog_v2_languages_xml, kainjow::mustache::object{ {"date", now}, - {"endpoint_root", rootLocation + "/catalog/v2"}, + {"endpoint_root", m_configuration.m_root + "/catalog/v2"}, {"feed_id", gen_uuid(libraryId + "/languages")}, {"languages", languageData } } diff --git a/src/search_renderer.cpp b/src/search_renderer.cpp index 7b293f628..91cafe4a5 100644 --- a/src/search_renderer.cpp +++ b/src/search_renderer.cpp @@ -36,12 +36,12 @@ namespace kiwix { /* Constructor */ -SearchRenderer::SearchRenderer(zim::SearchResultSet srs, NameMapper* mapper, +SearchRenderer::SearchRenderer(zim::SearchResultSet srs, std::shared_ptr mapper, unsigned int start, unsigned int estimatedResultCount) : SearchRenderer(srs, mapper, nullptr, start, estimatedResultCount) {} -SearchRenderer::SearchRenderer(zim::SearchResultSet srs, NameMapper* mapper, Library* library, +SearchRenderer::SearchRenderer(zim::SearchResultSet srs, std::shared_ptr mapper, std::shared_ptr library, unsigned int start, unsigned int estimatedResultCount) : m_srs(srs), mp_nameMapper(mapper), diff --git a/src/server.cpp b/src/server.cpp index e9373417c..61668f4a5 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -26,52 +26,38 @@ #include #include "server/internalServer.h" +#include "tools/otherTools.h" namespace kiwix { -Server::Server(Library* library, NameMapper* nameMapper) : +Server::Configuration::Configuration(std::shared_ptr library, std::shared_ptr nameMapper) : mp_library(library), - mp_nameMapper(nameMapper), - mp_server(nullptr) + mp_nameMapper(nameMapper ? nameMapper : std::make_shared(*library, true)) +{} + +Server::Configuration& Server::Configuration::setRoot(const std::string& root) +{ + m_root = normalizeRootUrl(root); + return *this; +} + +Server::Server(const Server::Configuration& configuration) : + mp_server(new InternalServer(configuration)) { } Server::~Server() = default; bool Server::start() { - mp_server.reset(new InternalServer( - mp_library, - mp_nameMapper, - m_addr, - m_port, - m_root, - m_nbThreads, - m_multizimSearchLimit, - m_verbose, - m_withTaskbar, - m_withLibraryButton, - m_blockExternalLinks, - m_indexTemplateString, - m_ipConnectionLimit)); return mp_server->start(); } void Server::stop() { - if (mp_server) { - mp_server->stop(); - mp_server.reset(nullptr); - } + mp_server->stop(); } -void Server::setRoot(const std::string& root) -{ - m_root = root; - if (m_root[0] != '/') { - m_root = "/" + m_root; - } - if (m_root.back() == '/') { - m_root.erase(m_root.size() - 1); - } +bool Server::isRunning() { + return mp_server->isRunning(); } int Server::getPort() diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index d6e6a91a4..c4d2ae02d 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -85,16 +85,6 @@ namespace kiwix { namespace { -inline std::string normalizeRootUrl(std::string rootUrl) -{ - while ( !rootUrl.empty() && rootUrl.back() == '/' ) - rootUrl.pop_back(); - - while ( !rootUrl.empty() && rootUrl.front() == '/' ) - rootUrl = rootUrl.substr(1); - return rootUrl.empty() ? rootUrl : "/" + rootUrl; -} - Filter get_search_filter(const RequestContext& request, const std::string& prefix="") { auto filter = kiwix::Filter().valid(true).local(true); @@ -333,8 +323,6 @@ zim::Query SearchInfo::getZimQuery(bool verbose) const { return query; } -static IdNameMapper defaultNameMapper; - static MHD_Result staticHandlerCallback(void* cls, struct MHD_Connection* connection, const char* url, @@ -366,33 +354,10 @@ class InternalServer::CustomizedResources : public std::map("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) @@ -406,7 +371,7 @@ bool InternalServer::start() { #else int flags = MHD_USE_POLL_INTERNALLY; #endif - if (m_verbose.load()) + if (m_verbose) flags |= MHD_USE_DEBUG; struct sockaddr_in sockAddr; @@ -450,8 +415,13 @@ bool InternalServer::start() { void InternalServer::stop() { MHD_stop_daemon(mp_daemon); + mp_daemon = nullptr; } +bool InternalServer::isRunning() const +{ + return mp_daemon != nullptr; +} static MHD_Result staticHandlerCallback(void* cls, struct MHD_Connection* connection, const char* url, @@ -481,14 +451,14 @@ MHD_Result InternalServer::handlerCallback(struct MHD_Connection* connection, void** cont_cls) { auto start_time = std::chrono::steady_clock::now(); - if (m_verbose.load() ) { + if (m_verbose) { printf("======================\n"); printf("Requesting : \n"); printf("full_url : %s\n", url); } RequestContext request(connection, m_root, url, method, version); - if (m_verbose.load() ) { + if (m_verbose) { request.print_debug_info(); } /* Unexpected method */ @@ -504,7 +474,7 @@ MHD_Result InternalServer::handlerCallback(struct MHD_Connection* connection, if (response->getReturnCode() == MHD_HTTP_INTERNAL_SERVER_ERROR) { printf("========== INTERNAL ERROR !! ============\n"); - if (!m_verbose.load()) { + if (!m_verbose) { printf("Requesting : \n"); printf("full_url : %s\n", url); request.print_debug_info(); @@ -517,7 +487,7 @@ MHD_Result InternalServer::handlerCallback(struct MHD_Connection* connection, auto ret = response->send(request, connection); auto end_time = std::chrono::steady_clock::now(); auto time_span = std::chrono::duration_cast>(end_time - start_time); - if (m_verbose.load()) { + if (m_verbose) { printf("Request time : %fs\n", time_span.count()); printf("----------------------\n"); } @@ -650,7 +620,7 @@ class InternalServer::LockableSuggestionSearcher : public zim::SuggestionSearche std::unique_ptr InternalServer::handle_suggest(const RequestContext& request) { - if (m_verbose.load()) { + if (m_verbose) { printf("** running handle_suggest\n"); } @@ -681,7 +651,7 @@ std::unique_ptr InternalServer::handle_suggest(const RequestContext& r count = 10; } - if (m_verbose.load()) { + if (m_verbose) { printf("Searching suggestions for: \"%s\"\n", queryString.c_str()); } @@ -734,7 +704,7 @@ std::unique_ptr InternalServer::handle_suggest(const RequestContext& r std::unique_ptr InternalServer::handle_viewer_settings(const RequestContext& request) { - if (m_verbose.load()) { + if (m_verbose) { printf("** running handle_viewer_settings\n"); } @@ -748,7 +718,7 @@ std::unique_ptr InternalServer::handle_viewer_settings(const RequestCo std::unique_ptr InternalServer::handle_skin(const RequestContext& request) { - if (m_verbose.load()) { + if (m_verbose) { printf("** running handle_skin\n"); } @@ -771,7 +741,7 @@ std::unique_ptr InternalServer::handle_skin(const RequestContext& requ std::unique_ptr InternalServer::handle_search(const RequestContext& request) { - if (m_verbose.load()) { + if (m_verbose) { printf("** running handle_search\n"); } @@ -800,7 +770,7 @@ std::unique_ptr InternalServer::handle_search(const RequestContext& re try { search = searchCache.getOrPut(searchInfo, [=](){ - return make_shared(searcher->search(searchInfo.getZimQuery(m_verbose.load()))); + return make_shared(searcher->search(searchInfo.getZimQuery(m_verbose))); } ); } catch(std::runtime_error& e) { @@ -872,7 +842,7 @@ std::unique_ptr InternalServer::handle_search(const RequestContext& re std::unique_ptr InternalServer::handle_random(const RequestContext& request) { - if (m_verbose.load()) { + if (m_verbose) { printf("** running handle_random\n"); } @@ -924,7 +894,7 @@ std::unique_ptr InternalServer::handle_captured_external(const Request std::unique_ptr InternalServer::handle_catch(const RequestContext& request) { - if (m_verbose.load()) { + if (m_verbose) { printf("** running handle_catch\n"); } @@ -938,7 +908,7 @@ std::unique_ptr InternalServer::handle_catch(const RequestContext& req std::unique_ptr InternalServer::handle_catalog(const RequestContext& request) { - if (m_verbose.load()) { + if (m_verbose) { printf("** running handle_catalog"); } @@ -967,8 +937,7 @@ std::unique_ptr InternalServer::handle_catalog(const RequestContext& r } zim::Uuid uuid; - kiwix::OPDSDumper opdsDumper(mp_library); - opdsDumper.setRootLocation(m_root); + kiwix::OPDSDumper opdsDumper(*this); opdsDumper.setLibraryId(m_library_id); std::vector bookIdsToDump; if (url == "root.xml") { @@ -1030,7 +999,7 @@ std::unique_ptr InternalServer::handle_content(const RequestContext& r { const std::string url = request.get_url(); const std::string pattern = url.substr((url.find_last_of('/'))+1); - if (m_verbose.load()) { + if (m_verbose) { printf("** running handle_content\n"); } @@ -1071,14 +1040,14 @@ std::unique_ptr InternalServer::handle_content(const RequestContext& r } auto response = ItemResponse::build(*this, request, entry.getItem()); - if (m_verbose.load()) { + if (m_verbose) { printf("Found %s\n", entry.getPath().c_str()); printf("mimeType: %s\n", entry.getItem(true).getMimetype().c_str()); } return response; } catch(zim::EntryNotFound& e) { - if (m_verbose.load()) + if (m_verbose) printf("Failed to find %s\n", urlStr.c_str()); std::string searchURL = m_root + "/search?content=" + bookName + "&pattern=" + kiwix::urlEncode(pattern, true); @@ -1091,7 +1060,7 @@ std::unique_ptr InternalServer::handle_content(const RequestContext& r std::unique_ptr InternalServer::handle_raw(const RequestContext& request) { - if (m_verbose.load()) { + if (m_verbose) { printf("** running handle_raw\n"); } @@ -1141,7 +1110,7 @@ std::unique_ptr InternalServer::handle_raw(const RequestContext& reque return ItemResponse::build(*this, request, entry.getItem()); } } catch (zim::EntryNotFound& e ) { - if (m_verbose.load()) { + if (m_verbose) { printf("Failed to find %s\n", itemPath.c_str()); } return HTTP404Response(*this, request) @@ -1157,13 +1126,13 @@ bool InternalServer::isLocallyCustomizedResource(const std::string& url) const std::unique_ptr InternalServer::handle_locally_customized_resource(const RequestContext& request) { - if (m_verbose.load()) { + if (m_verbose) { printf("** running handle_locally_customized_resource\n"); } const CustomizedResourceData& crd = m_customizedResources->at(request.get_url()); - if (m_verbose.load()) { + if (m_verbose) { std::cout << "Reading " << crd.resourceFilePath << std::endl; } const auto resourceData = getFileContent(crd.resourceFilePath); diff --git a/src/server/internalServer.h b/src/server/internalServer.h index 6f523336e..efd25a928 100644 --- a/src/server/internalServer.h +++ b/src/server/internalServer.h @@ -26,7 +26,7 @@ extern "C" { } #include "library.h" -#include "name_mapper.h" +#include "server.h" #include #include @@ -90,21 +90,9 @@ class SearchInfo { typedef kainjow::mustache::data MustacheData; class OPDSDumper; -class InternalServer { +class InternalServer : Server::Configuration { public: - InternalServer(Library* library, - NameMapper* nameMapper, - std::string addr, - int port, - std::string root, - int nbThreads, - unsigned int multizimSearchLimit, - bool verbose, - bool withTaskbar, - bool withLibraryButton, - bool blockExternalLinks, - std::string indexTemplateString, - int ipConnectionLimit); + InternalServer(const Server::Configuration& configuration); virtual ~InternalServer(); MHD_Result handlerCallback(struct MHD_Connection* connection, @@ -116,6 +104,7 @@ class InternalServer { void** cont_cls); bool start(); void stop(); + bool isRunning() const; std::string getAddress() { return m_addr; } int getPort() { return m_port; } @@ -161,21 +150,9 @@ class InternalServer { private: // data std::string m_addr; - int m_port; - std::string m_root; - int m_nbThreads; - unsigned int m_multizimSearchLimit; - std::atomic_bool m_verbose; - bool m_withTaskbar; - bool m_withLibraryButton; - bool m_blockExternalLinks; std::string m_indexTemplateString; - int m_ipConnectionLimit; struct MHD_Daemon* mp_daemon; - Library* mp_library; - NameMapper* mp_nameMapper; - SearchCache searchCache; SuggestionSearcherCache suggestionSearcherCache; diff --git a/src/server/internalServer_catalog_v2.cpp b/src/server/internalServer_catalog_v2.cpp index b082dd1c1..7820af46c 100644 --- a/src/server/internalServer_catalog_v2.cpp +++ b/src/server/internalServer_catalog_v2.cpp @@ -35,7 +35,7 @@ namespace kiwix { std::unique_ptr InternalServer::handle_catalog_v2(const RequestContext& request) { - if (m_verbose.load()) { + if (m_verbose) { printf("** running handle_catalog_v2"); } @@ -95,8 +95,7 @@ std::unique_ptr InternalServer::handle_catalog_v2_root(const RequestCo std::unique_ptr InternalServer::handle_catalog_v2_entries(const RequestContext& request, bool partial) { - OPDSDumper opdsDumper(mp_library); - opdsDumper.setRootLocation(m_root); + OPDSDumper opdsDumper(*this); opdsDumper.setLibraryId(m_library_id); const auto bookIds = search_catalog(request, opdsDumper); const auto opdsFeed = opdsDumper.dumpOPDSFeedV2(bookIds, request.get_query(), partial); @@ -116,8 +115,7 @@ std::unique_ptr InternalServer::handle_catalog_v2_complete_entry(const + urlNotFoundMsg; } - OPDSDumper opdsDumper(mp_library); - opdsDumper.setRootLocation(m_root); + OPDSDumper opdsDumper(*this); opdsDumper.setLibraryId(m_library_id); const auto opdsFeed = opdsDumper.dumpOPDSCompleteEntry(entryId); return ContentResponse::build( @@ -129,8 +127,7 @@ std::unique_ptr InternalServer::handle_catalog_v2_complete_entry(const std::unique_ptr InternalServer::handle_catalog_v2_categories(const RequestContext& request) { - OPDSDumper opdsDumper(mp_library); - opdsDumper.setRootLocation(m_root); + OPDSDumper opdsDumper(*this); opdsDumper.setLibraryId(m_library_id); return ContentResponse::build( *this, @@ -141,8 +138,7 @@ std::unique_ptr InternalServer::handle_catalog_v2_categories(const Req std::unique_ptr InternalServer::handle_catalog_v2_languages(const RequestContext& request) { - OPDSDumper opdsDumper(mp_library); - opdsDumper.setRootLocation(m_root); + OPDSDumper opdsDumper(*this); opdsDumper.setLibraryId(m_library_id); return ContentResponse::build( *this, diff --git a/src/server/response.cpp b/src/server/response.cpp index 7067ff207..46e3c86ea 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -114,7 +114,7 @@ Response::Response(bool verbose) std::unique_ptr Response::build(const InternalServer& server) { - return std::unique_ptr(new Response(server.m_verbose.load())); + return std::unique_ptr(new Response(server.m_verbose)); } std::unique_ptr Response::build_304(const InternalServer& server, const ETag& etag) @@ -390,7 +390,7 @@ std::unique_ptr ContentResponse::build( { return std::unique_ptr(new ContentResponse( server.m_root, - server.m_verbose.load(), + server.m_verbose, content, mimetype)); } @@ -435,7 +435,7 @@ std::unique_ptr ItemResponse::build(const InternalServer& server, cons } return std::unique_ptr(new ItemResponse( - server.m_verbose.load(), + server.m_verbose, item, mimetype, byteRange)); diff --git a/src/tools/otherTools.cpp b/src/tools/otherTools.cpp index ab5bf5874..6d6ff43b3 100644 --- a/src/tools/otherTools.cpp +++ b/src/tools/otherTools.cpp @@ -370,6 +370,16 @@ std::string kiwix::gen_uuid(const std::string& s) return kiwix::to_string(zim::Uuid::generate(s)); } +std::string kiwix::normalizeRootUrl(std::string rootUrl) +{ + while ( !rootUrl.empty() && rootUrl.back() == '/' ) + rootUrl.pop_back(); + + while ( !rootUrl.empty() && rootUrl.front() == '/' ) + rootUrl = rootUrl.substr(1); + return rootUrl.empty() ? rootUrl : "/" + rootUrl; +} + kainjow::mustache::data kiwix::onlyAsNonEmptyMustacheValue(const std::string& s) { return s.empty() diff --git a/src/tools/otherTools.h b/src/tools/otherTools.h index c0920d7bf..54d00c8eb 100644 --- a/src/tools/otherTools.h +++ b/src/tools/otherTools.h @@ -51,6 +51,8 @@ namespace kiwix std::string gen_date_str(); std::string gen_uuid(const std::string& s); + std::string normalizeRootUrl(std::string rootUrl); + // if s is empty then returns kainjow::mustache::data(false) // otherwise kainjow::mustache::data(value) kainjow::mustache::data onlyAsNonEmptyMustacheValue(const std::string& s); diff --git a/test/library.cpp b/test/library.cpp index ef41c4d7c..598d5e16c 100644 --- a/test/library.cpp +++ b/test/library.cpp @@ -20,6 +20,7 @@ #include "gtest/gtest.h" #include +#include "testing_tools.h" const char * sampleOpdsStream = R"( (lib)}; manager.readOpds(sampleOpdsStream, "library-opds-import.unittests.dev"); EXPECT_EQ(10U, lib.getBookCount(true, true)); @@ -297,8 +298,11 @@ class LibraryTest : public ::testing::Test { typedef kiwix::Library::BookIdCollection BookIdCollection; typedef std::vector TitleCollection; + explicit LibraryTest() + {} + void SetUp() override { - kiwix::Manager manager(&lib); + kiwix::Manager manager{NotOwned(lib)}; manager.readOpds(sampleOpdsStream, "foo.urlHost"); manager.readXml(sampleLibraryXML, false, "./test/library.xml", true); } diff --git a/test/library_server.cpp b/test/library_server.cpp index d8f1ecacf..277d139a2 100644 --- a/test/library_server.cpp +++ b/test/library_server.cpp @@ -18,8 +18,13 @@ class LibraryServerTest : public ::testing::Test const int PORT = 8002; protected: + void resetServer(ZimFileServer::Options options) { + zfs1_.reset(); + zfs1_.reset(new ZimFileServer(PORT, options, "./test/library.xml")); + } + void SetUp() override { - zfs1_.reset(new ZimFileServer(PORT, "./test/library.xml")); + zfs1_.reset(new ZimFileServer(PORT, ZimFileServer::DEFAULT_OPTIONS, "./test/library.xml")); } void TearDown() override { @@ -70,20 +75,20 @@ std::string maskVariableOPDSFeedData(std::string s) " type=\"application/opensearchdescription+xml\"" \ " href=\"/ROOT/catalog/searchdescription.xml\" />\n" -#define CHARLES_RAY_CATALOG_ENTRY \ +#define CATALOG_ENTRY(UUID, TITLE, SUMMARY, LANG, NAME, CATEGORY, TAGS, EXTRA_LINK, CONTENT_NAME, FILE_NAME, LENGTH) \ " \n" \ - " urn:uuid:charlesray\n" \ - " Charles, Ray\n" \ + " urn:uuid:" UUID "\n" \ + " " TITLE "\n" \ " YYYY-MM-DDThh:mm:ssZ\n" \ - " Wikipedia articles about Ray Charles\n" \ - " fra\n" \ - " wikipedia_fr_ray_charles\n" \ + " " SUMMARY "\n" \ + " " LANG "\n" \ + " " NAME "\n" \ " \n" \ - " jazz\n" \ - " unittest;wikipedia;_category:jazz;_pictures:no;_videos:no;_details:no;_ftindex:yes\n" \ + " " CATEGORY "\n" \ + " " TAGS "\n" \ " 284\n" \ " 2\n" \ - " \n" \ + " " EXTRA_LINK "\n" \ " \n" \ " Wikipedia\n" \ " \n" \ @@ -91,59 +96,57 @@ std::string maskVariableOPDSFeedData(std::string s) " Kiwix\n" \ " \n" \ " 2020-03-31T00:00:00Z\n" \ - " \n" \ + " \n" \ " \n" -#define RAY_CHARLES_CATALOG_ENTRY \ - " \n" \ - " urn:uuid:raycharles\n" \ - " Ray Charles\n" \ - " YYYY-MM-DDThh:mm:ssZ\n" \ - " Wikipedia articles about Ray Charles\n" \ - " eng\n" \ - " wikipedia_en_ray_charles\n" \ - " \n" \ - " wikipedia\n" \ - " public_tag_without_a_value;_private_tag_without_a_value;wikipedia;_category:wikipedia;_pictures:no;_videos:no;_details:no;_ftindex:yes\n" \ - " 284\n" \ - " 2\n" \ - " \n" \ - " \n" \ - " \n" \ - " Wikipedia\n" \ - " \n" \ - " \n" \ - " Kiwix\n" \ - " \n" \ - " 2020-03-31T00:00:00Z\n" \ - " \n" \ - " \n" -#define UNCATEGORIZED_RAY_CHARLES_CATALOG_ENTRY \ - " \n" \ - " urn:uuid:raycharles_uncategorized\n" \ - " Ray (uncategorized) Charles\n" \ - " YYYY-MM-DDThh:mm:ssZ\n" \ - " No category is assigned to this library entry.\n" \ - " rus\n" \ - " wikipedia_ru_ray_charles\n" \ - " \n" \ - " \n" \ - " public_tag_with_a_value:value_of_a_public_tag;_private_tag_with_a_value:value_of_a_private_tag;wikipedia;_pictures:no;_videos:no;_details:no\n" \ - " 284\n" \ - " 2\n" \ - " \n" \ - " \n" \ - " Wikipedia\n" \ - " \n" \ - " \n" \ - " Kiwix\n" \ - " \n" \ - " 2020-03-31T00:00:00Z\n" \ - " \n" \ - " \n" +#define _CHARLES_RAY_CATALOG_ENTRY(CONTENT_NAME) CATALOG_ENTRY( \ + "charlesray", \ + "Charles, Ray", \ + "Wikipedia articles about Ray Charles", \ + "fra", \ + "wikipedia_fr_ray_charles",\ + "jazz",\ + "unittest;wikipedia;_category:jazz;_pictures:no;_videos:no;_details:no;_ftindex:yes",\ + "", \ + CONTENT_NAME, \ + "zimfile%26other", \ + "569344" \ +) + +#define CHARLES_RAY_CATALOG_ENTRY _CHARLES_RAY_CATALOG_ENTRY("zimfile%26other") + +#define _RAY_CHARLES_CATALOG_ENTRY(CONTENT_NAME) CATALOG_ENTRY(\ + "raycharles",\ + "Ray Charles",\ + "Wikipedia articles about Ray Charles",\ + "eng",\ + "wikipedia_en_ray_charles",\ + "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", \ + "569344"\ +) + +#define RAY_CHARLES_CATALOG_ENTRY _RAY_CHARLES_CATALOG_ENTRY("zimfile") + +#define UNCATEGORIZED_RAY_CHARLES_CATALOG_ENTRY CATALOG_ENTRY(\ + "raycharles_uncategorized",\ + "Ray (uncategorized) Charles",\ + "No category is assigned to this library entry.",\ + "rus",\ + "wikipedia_ru_ray_charles",\ + "",\ + "public_tag_with_a_value:value_of_a_public_tag;_private_tag_with_a_value:value_of_a_private_tag;wikipedia;_pictures:no;_videos:no;_details:no",\ + "",\ + "zimfile", \ + "zimfile", \ + "125952"\ +) TEST_F(LibraryServerTest, catalog_root_xml) { @@ -780,4 +783,42 @@ TEST_F(LibraryServerTest, catalog_search_excludes_hidden_tags) #undef EXPECT_ZERO_RESULTS } +#define NO_MAPPER_CHARLES_RAY_CATALOG_ENTRY _CHARLES_RAY_CATALOG_ENTRY("charlesray") +#define NO_MAPPER_RAY_CHARLES_CATALOG_ENTRY _RAY_CHARLES_CATALOG_ENTRY("raycharles") +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"); + EXPECT_EQ(r->status, 200); + EXPECT_EQ(maskVariableOPDSFeedData(r->body), + OPDS_FEED_TAG + " 12345678-90ab-cdef-1234-567890abcdef\n" + " Filtered zims (tag=_category:jazz)\n" + " YYYY-MM-DDThh:mm:ssZ\n" + " 1\n" + " 0\n" + " 1\n" + CATALOG_LINK_TAGS + NO_MAPPER_CHARLES_RAY_CATALOG_ENTRY + "\n" + ); +} + + +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"); + EXPECT_EQ(r->status, 200); + EXPECT_EQ(maskVariableOPDSFeedData(r->body), + "\n" + NO_MAPPER_RAY_CHARLES_CATALOG_ENTRY + ); + + const auto r1 = zfs1_->GET("/ROOT/catalog/v2/entry/non-existent-entry"); + EXPECT_EQ(r1->status, 404); +} + + + #undef EXPECT_SEARCH_RESULTS diff --git a/test/manager.cpp b/test/manager.cpp index 34774f630..3b21ee7bc 100644 --- a/test/manager.cpp +++ b/test/manager.cpp @@ -6,10 +6,12 @@ #include #include +#include "testing_tools.h" + TEST(ManagerTest, addBookFromPathAndGetIdTest) { kiwix::Library lib; - kiwix::Manager manager = kiwix::Manager(&lib); + kiwix::Manager manager = kiwix::Manager(NotOwned(lib)); auto bookId = manager.addBookFromPathAndGetId("./test/example.zim"); ASSERT_NE(bookId, ""); @@ -49,7 +51,7 @@ const char sampleLibraryXML[] = R"( TEST(ManagerTest, readXml) { kiwix::Library lib; - kiwix::Manager manager = kiwix::Manager(&lib); + kiwix::Manager manager = kiwix::Manager(NotOwned(lib)); EXPECT_EQ(true, manager.readXml(sampleLibraryXML, true, "/data/lib.xml", true)); kiwix::Book book = lib.getBookById("0d0bcd57-d3f6-cb22-44cc-a723ccb4e1b2"); @@ -71,7 +73,7 @@ TEST(ManagerTest, readXml) TEST(Manager, reload) { kiwix::Library lib; - kiwix::Manager manager(&lib); + kiwix::Manager manager = kiwix::Manager(NotOwned(lib)); manager.reload({ "./test/library.xml" }); EXPECT_EQ(lib.getBooksIds(), (kiwix::Library::BookIdCollection{ diff --git a/test/name_mapper.cpp b/test/name_mapper.cpp index 0bc60254a..351369900 100644 --- a/test/name_mapper.cpp +++ b/test/name_mapper.cpp @@ -4,9 +4,12 @@ #include "../include/manager.h" #include "gtest/gtest.h" +#include "testing_tools.h" + namespace { + const char libraryXML[] = R"( @@ -18,9 +21,13 @@ const char libraryXML[] = R"( )"; class NameMapperTest : public ::testing::Test { + public: + explicit NameMapperTest() + {} + protected: void SetUp() override { - kiwix::Manager manager(&lib); + kiwix::Manager manager{NotOwned(lib)}; manager.readXml(libraryXML, false, "./library.xml", true); for ( const std::string& id : lib.getBooksIds() ) { kiwix::Book bookCopy = lib.getBookById(id); @@ -108,7 +115,7 @@ TEST_F(NameMapperTest, HumanReadableNameMapperWithAliases) TEST_F(NameMapperTest, UpdatableNameMapperWithoutAliases) { CapturedStderr stderror; - kiwix::UpdatableNameMapper nm(lib, false); + kiwix::UpdatableNameMapper nm(NotOwned(lib), false); EXPECT_EQ("", std::string(stderror)); checkUnaliasedEntriesInNameMapper(nm); @@ -124,7 +131,7 @@ TEST_F(NameMapperTest, UpdatableNameMapperWithoutAliases) TEST_F(NameMapperTest, UpdatableNameMapperWithAliases) { CapturedStderr stderror; - kiwix::UpdatableNameMapper nm(lib, true); + kiwix::UpdatableNameMapper nm(NotOwned(lib), true); EXPECT_EQ( "Path collision: /data/zero_four_2021-10.zim and" " /data/zero_four_2021-11.zim can't share the same URL path 'zero_four'." diff --git a/test/server.cpp b/test/server.cpp index 2d1e1068a..d03f9e6bb 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -131,6 +131,13 @@ TEST_F(ServerTest, 200) EXPECT_EQ(200, zfs1_->GET(res.url)->status) << "res.url: " << res.url; } +TEST_F(ServerTest, 200_IdNameMapper) +{ + 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); +} + TEST_F(ServerTest, CompressibleContentIsCompressedIfAcceptable) { for ( const Resource& res : resources200Compressible ) { diff --git a/test/server_testing_tools.h b/test/server_testing_tools.h index ab0b4a511..ad3099b26 100644 --- a/test/server_testing_tools.h +++ b/test/server_testing_tools.h @@ -6,6 +6,8 @@ #include #include +#include "testing_tools.h" + // Output generated via mustache templates sometimes contains end-of-line // whitespace. This complicates representing the expected output of a unit-test // as C++ raw strings in editors that are configured to delete EOL whitespace. @@ -61,6 +63,7 @@ class ZimFileServer WITH_TASKBAR = 1 << 1, WITH_LIBRARY_BUTTON = 1 << 2, BLOCK_EXTERNAL_LINKS = 1 << 3, + NO_NAME_MAPPER = 1 << 4, WITH_TASKBAR_AND_LIBRARY_BUTTON = WITH_TASKBAR | WITH_LIBRARY_BUTTON, @@ -68,7 +71,7 @@ class ZimFileServer }; public: // functions - ZimFileServer(int serverPort, std::string libraryFilePath); + ZimFileServer(int serverPort, Options options, std::string libraryFilePath); ZimFileServer(int serverPort, Options options, const FilePathCollection& zimpaths, @@ -91,14 +94,15 @@ class ZimFileServer private: // data kiwix::Library library; kiwix::Manager manager; - std::unique_ptr nameMapper; + std::shared_ptr nameMapper; std::unique_ptr server; std::unique_ptr client; const Options options = DEFAULT_OPTIONS; }; -ZimFileServer::ZimFileServer(int serverPort, std::string libraryFilePath) -: manager(&this->library) +ZimFileServer::ZimFileServer(int serverPort, Options _options, std::string libraryFilePath) +: manager(NotOwned(library)), + options(_options) { if ( kiwix::isRelativePath(libraryFilePath) ) libraryFilePath = kiwix::computeAbsolutePath(kiwix::getCurrentDirectory(), libraryFilePath); @@ -110,8 +114,8 @@ ZimFileServer::ZimFileServer(int serverPort, Options _options, const FilePathCollection& zimpaths, std::string indexTemplateString) -: manager(&this->library) -, options(_options) +: manager(NotOwned(library)), + options(_options) { for ( const auto& zimpath : zimpaths ) { if (!manager.addBookFromPath(zimpath, zimpath, "", false)) @@ -123,19 +127,25 @@ ZimFileServer::ZimFileServer(int serverPort, void ZimFileServer::run(int serverPort, std::string indexTemplateString) { const std::string address = "127.0.0.1"; - nameMapper.reset(new kiwix::HumanReadableNameMapper(library, false)); - server.reset(new kiwix::Server(&library, nameMapper.get())); - server->setRoot("ROOT"); - server->setAddress(address); - server->setPort(serverPort); - server->setNbThreads(2); - server->setVerbose(false); - server->setTaskbar(options & WITH_TASKBAR, options & WITH_LIBRARY_BUTTON); - server->setBlockExternalLinks(options & BLOCK_EXTERNAL_LINKS); - server->setMultiZimSearchLimit(3); + if (options & NO_NAME_MAPPER) { + nameMapper.reset(new kiwix::IdNameMapper()); + } else { + nameMapper.reset(new kiwix::HumanReadableNameMapper(library, false)); + } + kiwix::Server::Configuration configuration(NotOwned(library), nameMapper); + configuration.setRoot("ROOT") + .setAddress(address) + .setPort(serverPort) + .setNbThreads(2) + .setVerbose(false) + .setTaskbar(options & WITH_TASKBAR, options & WITH_LIBRARY_BUTTON) + .setBlockExternalLinks(options & BLOCK_EXTERNAL_LINKS) + .setMultiZimSearchLimit(3); + if (!indexTemplateString.empty()) { - server->setIndexTemplateString(indexTemplateString); + configuration.setIndexTemplateString(indexTemplateString); } + server.reset(new kiwix::Server(configuration)); if ( !server->start() ) throw std::runtime_error("ZimFileServer failed to start"); diff --git a/test/testing_tools.h b/test/testing_tools.h new file mode 100644 index 000000000..ad3a8378e --- /dev/null +++ b/test/testing_tools.h @@ -0,0 +1,19 @@ + +#ifndef TESTING_TOOLS +#define TESTING_TOOLS + +#include + +struct NoDelete { + template void operator()(T*) {} +}; + +template +class NotOwned : public std::shared_ptr { + public: + NotOwned(T& object) : + std::shared_ptr(&object, NoDelete()) {}; +}; + + +#endif // TESTING_TOOLS