Move the entry response to its own class.

This commit is contained in:
Matthieu Gautier 2020-07-29 14:03:03 +02:00
parent f014fb2895
commit 7b2ee37437
4 changed files with 91 additions and 60 deletions

View File

@ -840,9 +840,7 @@ std::unique_ptr<Response> InternalServer::handle_content(const RequestContext& r
return build_404(request, bookName); return build_404(request, bookName);
} }
auto response = Response::build(*this); auto response = EntryResponse::build(*this, request, entry);
response->set_entry(entry, request);
response->set_taskbar(bookName, reader->getTitle()); response->set_taskbar(bookName, reader->getTitle());
if (m_verbose.load()) { if (m_verbose.load()) {

View File

@ -108,6 +108,8 @@ class InternalServer {
friend std::unique_ptr<Response> Response::build(const InternalServer& server); friend std::unique_ptr<Response> Response::build(const InternalServer& server);
friend std::unique_ptr<Response> RedirectionResponse::build(const InternalServer& server, const std::string& redirectionUrl); friend std::unique_ptr<Response> RedirectionResponse::build(const InternalServer& server, const std::string& redirectionUrl);
friend std::unique_ptr<Response> ContentResponse::build(const InternalServer& server, const std::string& content, const std::string& mimetype); friend std::unique_ptr<Response> ContentResponse::build(const InternalServer& server, const std::string& content, const std::string& mimetype);
friend std::unique_ptr<Response> EntryResponse::build(const InternalServer& server, const RequestContext& request, const Entry& entry);
}; };
} }

View File

@ -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* MHD_Response*
Response::create_mhd_response(const RequestContext& request) Response::create_mhd_response(const RequestContext& request)
@ -288,9 +263,6 @@ Response::create_mhd_response(const RequestContext& request)
case ResponseMode::RAW_CONTENT : case ResponseMode::RAW_CONTENT :
return create_raw_content_mhd_response(request); return create_raw_content_mhd_response(request);
case ResponseMode::ENTRY :
return create_entry_mhd_response();
} }
return nullptr; return nullptr;
} }
@ -324,30 +296,6 @@ void Response::set_template(const std::string& template_str, kainjow::mustache::
m_mode = ResponseMode::RAW_CONTENT; 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) void Response::set_taskbar(const std::string& bookName, const std::string& bookTitle)
{ {
m_bookName = bookName; m_bookName = bookName;
@ -400,6 +348,77 @@ std::unique_ptr<Response> ContentResponse::build(const InternalServer& server, c
mimetype)); 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<Response> 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<Response>(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;
}
} }

View File

@ -37,12 +37,13 @@ namespace kiwix {
enum class ResponseMode { enum class ResponseMode {
ERROR_RESPONSE, ERROR_RESPONSE,
RAW_CONTENT, RAW_CONTENT,
ENTRY
}; };
class InternalServer; class InternalServer;
class RequestContext; class RequestContext;
class EntryResponse;
class Response { class Response {
public: public:
Response(const std::string& root, bool verbose, bool withTaskbar, bool withLibraryButton, bool blockExternalLinks); 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); MHD_Result send(const RequestContext& request, MHD_Connection* connection);
void set_template(const std::string& template_str, kainjow::mustache::data data); 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_mimeType(const std::string& mimeType) { m_mimeType = mimeType; }
void set_code(int code) { m_returnCode = code; } void set_code(int code) { m_returnCode = code; }
@ -77,14 +76,12 @@ class Response {
virtual MHD_Response* create_mhd_response(const RequestContext& request); virtual MHD_Response* create_mhd_response(const RequestContext& request);
MHD_Response* create_error_response(const RequestContext& request) const; MHD_Response* create_error_response(const RequestContext& request) const;
MHD_Response* create_raw_content_mhd_response(const RequestContext& request); MHD_Response* create_raw_content_mhd_response(const RequestContext& request);
MHD_Response* create_entry_mhd_response() const;
protected: // data protected: // data
bool m_verbose; bool m_verbose;
ResponseMode m_mode; ResponseMode m_mode;
std::string m_root; std::string m_root;
std::string m_content; std::string m_content;
Entry m_entry;
std::string m_mimeType; std::string m_mimeType;
int m_returnCode; int m_returnCode;
bool m_withTaskbar; bool m_withTaskbar;
@ -95,6 +92,8 @@ class Response {
std::string m_bookTitle; std::string m_bookTitle;
ByteRange m_byteRange; ByteRange m_byteRange;
ETag m_etag; 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<Response> build(const InternalServer& server, const std::string& content, const std::string& mimetype); static std::unique_ptr<Response> 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<Response> 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 #endif //KIWIXLIB_SERVER_RESPONSE_H