diff --git a/src/server/etag.cpp b/src/server/etag.cpp index 1ba89470..e031ce46 100644 --- a/src/server/etag.cpp +++ b/src/server/etag.cpp @@ -37,7 +37,7 @@ namespace { // into the ETag for ETag::Option opt. // IMPORTANT: The characters in all_options must come in sorted order (so that // IMPORTANT: isValidOptionsString() works correctly). -const char all_options[] = "cz"; +const char all_options[] = "Zz"; static_assert(ETag::OPTION_COUNT == sizeof(all_options) - 1, ""); diff --git a/src/server/etag.h b/src/server/etag.h index 49ff0e72..f8da0236 100644 --- a/src/server/etag.h +++ b/src/server/etag.h @@ -51,7 +51,7 @@ class ETag { public: // types enum Option { - CACHEABLE_ENTITY, + ZIM_CONTENT, COMPRESSED_CONTENT, OPTION_COUNT }; diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index d6e6a91a..772b056e 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -606,11 +606,8 @@ MustacheData InternalServer::get_default_data() const bool InternalServer::etag_not_needed(const RequestContext& request) const { const std::string url = request.get_url(); - return kiwix::startsWith(url, "/catalog") - || url == "/search" - || url == "/suggest" - || url == "/random" - || url == "/catch/external"; + return kiwix::startsWith(url, "/skin") + || url == "/random"; } ETag @@ -761,7 +758,7 @@ std::unique_ptr InternalServer::handle_skin(const RequestContext& requ *this, getResource(resourceName), getMimeTypeForFile(resourceName)); - response->set_cacheable(); + response->set_kind(Response::STATIC_RESOURCE); return std::move(response); } catch (const ResourceNotFound& e) { return HTTP404Response(*this, request) diff --git a/src/server/response.cpp b/src/server/response.cpp index 7067ff20..2c751e7b 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -102,6 +102,14 @@ bool compress(std::string &content) { } +const char* getCacheControlHeader(Response::Kind k) +{ + switch(k) { + case Response::STATIC_RESOURCE: return "max-age=31536000, immutable"; + case Response::ZIM_CONTENT: return "max-age=3600, must-revalidate"; + default: return "max-age=0, must-revalidate"; + } +} } // unnamed namespace @@ -112,6 +120,13 @@ Response::Response(bool verbose) add_header(MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*"); } +void Response::set_kind(Kind k) +{ + m_kind = k; + if ( k == ZIM_CONTENT ) + m_etag.set_option(ETag::ZIM_CONTENT); +} + std::unique_ptr Response::build(const InternalServer& server) { return std::unique_ptr(new Response(server.m_verbose.load())); @@ -122,6 +137,9 @@ std::unique_ptr Response::build_304(const InternalServer& server, cons auto response = Response::build(server); response->set_code(MHD_HTTP_NOT_MODIFIED); response->m_etag = etag; + if ( etag.get_option(ETag::ZIM_CONTENT) ) { + response->set_kind(Response::ZIM_CONTENT); + } if ( etag.get_option(ETag::COMPRESSED_CONTENT) ) { response->add_header(MHD_HTTP_HEADER_VARY, "Accept-Encoding"); } @@ -355,7 +373,7 @@ MHD_Result Response::send(const RequestContext& request, MHD_Connection* connect MHD_Response* response = create_mhd_response(request); MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL, - m_etag.get_option(ETag::CACHEABLE_ENTITY) ? "max-age=2723040, public" : "no-cache, no-store, must-revalidate"); + getCacheControlHeader(m_kind)); const std::string etag = m_etag.get_etag(); if ( ! etag.empty() ) MHD_add_response_header(response, MHD_HTTP_HEADER_ETAG, etag.c_str()); @@ -411,7 +429,7 @@ ItemResponse::ItemResponse(bool verbose, const zim::Item& item, const std::strin m_mimeType(mimetype) { m_byteRange = byterange; - set_cacheable(); + set_kind(Response::ZIM_CONTENT); add_header(MHD_HTTP_HEADER_CONTENT_TYPE, m_mimeType); } @@ -423,14 +441,14 @@ std::unique_ptr ItemResponse::build(const InternalServer& server, cons if (noRange && is_compressible_mime_type(mimetype)) { // Return a contentResponse auto response = ContentResponse::build(server, item.getData(), mimetype); - response->set_cacheable(); + response->set_kind(Response::ZIM_CONTENT); response->m_byteRange = byteRange; return std::move(response); } if (byteRange.kind() == ByteRange::RESOLVED_UNSATISFIABLE) { auto response = Response::build_416(server, item.getSize()); - response->set_cacheable(); + response->set_kind(Response::ZIM_CONTENT); return response; } diff --git a/src/server/response.h b/src/server/response.h index 55c8fde4..d1aa90ff 100644 --- a/src/server/response.h +++ b/src/server/response.h @@ -45,6 +45,14 @@ class InternalServer; class RequestContext; class Response { + public: + enum Kind + { + STATIC_RESOURCE, + ZIM_CONTENT, + DYNAMIC_CONTENT + }; + public: Response(bool verbose); virtual ~Response() = default; @@ -57,7 +65,7 @@ class Response { MHD_Result send(const RequestContext& request, MHD_Connection* connection); void set_code(int code) { m_returnCode = code; } - void set_cacheable() { m_etag.set_option(ETag::CACHEABLE_ENTITY); } + void set_kind(Kind k); void set_server_id(const std::string& id) { m_etag.set_server_id(id); } void add_header(const std::string& name, const std::string& value) { m_customHeaders[name] = value; } @@ -68,6 +76,7 @@ class Response { MHD_Response* create_error_response(const RequestContext& request) const; protected: // data + Kind m_kind = DYNAMIC_CONTENT; bool m_verbose; int m_returnCode; ByteRange m_byteRange; diff --git a/test/server.cpp b/test/server.cpp index 3b5d273a..bd67a3b7 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -35,7 +35,7 @@ struct Resource ResourceKind kind; const char* url; - bool etag_expected() const { return kind != DYNAMIC_CONTENT; } + bool etag_expected() const { return kind != STATIC_CONTENT; } }; std::ostream& operator<<(std::ostream& out, const Resource& r) @@ -47,7 +47,7 @@ std::ostream& operator<<(std::ostream& out, const Resource& r) typedef std::vector ResourceCollection; const ResourceCollection resources200Compressible{ - { STATIC_CONTENT, "/ROOT/" }, + { DYNAMIC_CONTENT, "/ROOT/" }, { STATIC_CONTENT, "/ROOT/skin/autoComplete.min.js" }, { STATIC_CONTENT, "/ROOT/skin/css/autoComplete.css" },