diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index 7c7d23386..4f11b3d77 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -840,9 +840,7 @@ std::unique_ptr InternalServer::handle_content(const RequestContext& r return build_404(request, bookName); } - auto response = Response::build(*this); - - response->set_entry(entry, request); + auto response = EntryResponse::build(*this, request, entry); response->set_taskbar(bookName, reader->getTitle()); if (m_verbose.load()) { diff --git a/src/server/internalServer.h b/src/server/internalServer.h index ba34fd3d2..7e27962fe 100644 --- a/src/server/internalServer.h +++ b/src/server/internalServer.h @@ -108,6 +108,8 @@ class InternalServer { friend std::unique_ptr Response::build(const InternalServer& server); friend std::unique_ptr RedirectionResponse::build(const InternalServer& server, const std::string& redirectionUrl); friend std::unique_ptr ContentResponse::build(const InternalServer& server, const std::string& content, const std::string& mimetype); + friend std::unique_ptr EntryResponse::build(const InternalServer& server, const RequestContext& request, const Entry& entry); + }; } diff --git a/src/server/response.cpp b/src/server/response.cpp index 9fac355b2..f1293f059 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -253,31 +253,6 @@ Response::create_raw_content_mhd_response(const RequestContext& request) } -MHD_Response* -Response::create_entry_mhd_response() const -{ - const auto content_length = m_byteRange.length(); - MHD_Response* response = MHD_create_response_from_callback(content_length, - 16384, - callback_reader_from_entry, - new RunningResponse(m_entry, m_byteRange.first()), - callback_free_response); - MHD_add_response_header(response, - MHD_HTTP_HEADER_CONTENT_TYPE, m_mimeType.c_str()); - MHD_add_response_header(response, MHD_HTTP_HEADER_ACCEPT_RANGES, "bytes"); - if ( m_byteRange.kind() == ByteRange::RESOLVED_PARTIAL_CONTENT ) { - std::ostringstream oss; - oss << "bytes " << m_byteRange.first() << "-" << m_byteRange.last() - << "/" << m_entry.getSize(); - - MHD_add_response_header(response, - MHD_HTTP_HEADER_CONTENT_RANGE, oss.str().c_str()); - } - - MHD_add_response_header(response, - MHD_HTTP_HEADER_CONTENT_LENGTH, kiwix::to_string(content_length).c_str()); - return response; -} MHD_Response* Response::create_mhd_response(const RequestContext& request) @@ -288,9 +263,6 @@ Response::create_mhd_response(const RequestContext& request) case ResponseMode::RAW_CONTENT : return create_raw_content_mhd_response(request); - - case ResponseMode::ENTRY : - return create_entry_mhd_response(); } return nullptr; } @@ -324,30 +296,6 @@ void Response::set_template(const std::string& template_str, kainjow::mustache:: m_mode = ResponseMode::RAW_CONTENT; } -void Response::set_entry(const Entry& entry, const RequestContext& request) { - m_entry = entry; - m_mode = ResponseMode::ENTRY; - - const std::string mimeType = get_mime_type(entry); - set_mimeType(mimeType); - set_cacheable(); - - m_byteRange = request.get_range().resolve(entry.getSize()); - const bool noRange = m_byteRange.kind() == ByteRange::RESOLVED_FULL_CONTENT; - if ( noRange && is_compressible_mime_type(mimeType) ) { - zim::Blob raw_content = entry.getBlob(); - const std::string content = string(raw_content.data(), raw_content.size()); - - m_content = content; - m_mode = ResponseMode::RAW_CONTENT; - set_compress(true); - } else if ( m_byteRange.kind() == ByteRange::RESOLVED_UNSATISFIABLE ) { - set_code(416); - m_content = ""; - m_mode = ResponseMode::ERROR_RESPONSE; - } -} - void Response::set_taskbar(const std::string& bookName, const std::string& bookTitle) { m_bookName = bookName; @@ -400,6 +348,77 @@ std::unique_ptr ContentResponse::build(const InternalServer& server, c mimetype)); } +EntryResponse::EntryResponse(const std::string& root, bool verbose, bool withTaskbar, bool withLibraryButton, bool blockExternalLinks, const Entry& entry, const std::string& mimetype, const ByteRange& byterange) : + Response(root, verbose, withTaskbar, withLibraryButton, blockExternalLinks), + m_entry(entry) +{ + m_mimeType = mimetype; + m_byteRange = byterange; + m_mode = ResponseMode::RAW_CONTENT; // We don't care about raw, but we must init it to something else than error. + set_cacheable(); +} + +std::unique_ptr EntryResponse::build(const InternalServer& server, const RequestContext& request, const Entry& entry) +{ + const std::string mimetype = get_mime_type(entry); + auto byteRange = request.get_range().resolve(entry.getSize()); + const bool noRange = byteRange.kind() == ByteRange::RESOLVED_FULL_CONTENT; + if (noRange && is_compressible_mime_type(mimetype)) { + // Return a contentResponse + zim::Blob raw_content = entry.getBlob(); + const std::string content = string(raw_content.data(), raw_content.size()); + auto response = ContentResponse::build(server, content, mimetype); + response->set_cacheable(); + response->set_compress(true); + response->m_byteRange = byteRange; + return response; + } + + if (byteRange.kind() == ByteRange::RESOLVED_UNSATISFIABLE) { + auto response = ContentResponse::build(server, "", mimetype); + response->set_cacheable(); + response->set_code(416); + response->m_byteRange = byteRange; + response->m_mode = ResponseMode::ERROR_RESPONSE; + return response; + } + + return std::unique_ptr(new EntryResponse( + server.m_root, + server.m_verbose.load(), + server.m_withTaskbar, + server.m_withLibraryButton, + server.m_blockExternalLinks, + entry, + mimetype, + byteRange)); +} + +MHD_Response* +EntryResponse::create_mhd_response(const RequestContext& request) +{ + const auto content_length = m_byteRange.length(); + MHD_Response* response = MHD_create_response_from_callback(content_length, + 16384, + callback_reader_from_entry, + new RunningResponse(m_entry, m_byteRange.first()), + callback_free_response); + MHD_add_response_header(response, + MHD_HTTP_HEADER_CONTENT_TYPE, m_mimeType.c_str()); + MHD_add_response_header(response, MHD_HTTP_HEADER_ACCEPT_RANGES, "bytes"); + if ( m_byteRange.kind() == ByteRange::RESOLVED_PARTIAL_CONTENT ) { + std::ostringstream oss; + oss << "bytes " << m_byteRange.first() << "-" << m_byteRange.last() + << "/" << m_entry.getSize(); + + MHD_add_response_header(response, + MHD_HTTP_HEADER_CONTENT_RANGE, oss.str().c_str()); + } + + MHD_add_response_header(response, + MHD_HTTP_HEADER_CONTENT_LENGTH, kiwix::to_string(content_length).c_str()); + return response; +} } diff --git a/src/server/response.h b/src/server/response.h index 837de396b..9134e85ba 100644 --- a/src/server/response.h +++ b/src/server/response.h @@ -37,12 +37,13 @@ namespace kiwix { enum class ResponseMode { ERROR_RESPONSE, RAW_CONTENT, - ENTRY }; class InternalServer; class RequestContext; +class EntryResponse; + class Response { public: Response(const std::string& root, bool verbose, bool withTaskbar, bool withLibraryButton, bool blockExternalLinks); @@ -53,8 +54,6 @@ class Response { MHD_Result send(const RequestContext& request, MHD_Connection* connection); void set_template(const std::string& template_str, kainjow::mustache::data data); - void set_entry(const Entry& entry, const RequestContext& request); - void set_mimeType(const std::string& mimeType) { m_mimeType = mimeType; } void set_code(int code) { m_returnCode = code; } @@ -77,14 +76,12 @@ class Response { virtual MHD_Response* create_mhd_response(const RequestContext& request); MHD_Response* create_error_response(const RequestContext& request) const; MHD_Response* create_raw_content_mhd_response(const RequestContext& request); - MHD_Response* create_entry_mhd_response() const; protected: // data bool m_verbose; ResponseMode m_mode; std::string m_root; std::string m_content; - Entry m_entry; std::string m_mimeType; int m_returnCode; bool m_withTaskbar; @@ -95,6 +92,8 @@ class Response { std::string m_bookTitle; ByteRange m_byteRange; ETag m_etag; + + friend class EntryResponse; // temporary to allow the builder to change m_mode }; @@ -118,6 +117,19 @@ class ContentResponse : public Response { static std::unique_ptr build(const InternalServer& server, const std::string& content, const std::string& mimetype); }; +class EntryResponse : public Response { + public: + EntryResponse(const std::string& root, bool verbose, bool withTaskbar, bool withLibraryButton, bool blockExternalLinks, const Entry& entry, const std::string& mimetype, const ByteRange& byterange); + + static std::unique_ptr build(const InternalServer& server, const RequestContext& request, const Entry& entry); + + private: + MHD_Response* create_mhd_response(const RequestContext& request); + + Entry m_entry; + +}; + } #endif //KIWIXLIB_SERVER_RESPONSE_H