mirror of https://github.com/kiwix/libkiwix.git
Setting Cache-Control: for three types of content
At this point the ETag value for ZIM content is still generated from the timestamp of the server start-up time.
This commit is contained in:
parent
5471819021
commit
190156e095
|
@ -37,7 +37,7 @@ namespace {
|
||||||
// into the ETag for ETag::Option opt.
|
// into the ETag for ETag::Option opt.
|
||||||
// IMPORTANT: The characters in all_options must come in sorted order (so that
|
// IMPORTANT: The characters in all_options must come in sorted order (so that
|
||||||
// IMPORTANT: isValidOptionsString() works correctly).
|
// IMPORTANT: isValidOptionsString() works correctly).
|
||||||
const char all_options[] = "cz";
|
const char all_options[] = "Zz";
|
||||||
|
|
||||||
static_assert(ETag::OPTION_COUNT == sizeof(all_options) - 1, "");
|
static_assert(ETag::OPTION_COUNT == sizeof(all_options) - 1, "");
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ class ETag
|
||||||
{
|
{
|
||||||
public: // types
|
public: // types
|
||||||
enum Option {
|
enum Option {
|
||||||
CACHEABLE_ENTITY,
|
ZIM_CONTENT,
|
||||||
COMPRESSED_CONTENT,
|
COMPRESSED_CONTENT,
|
||||||
OPTION_COUNT
|
OPTION_COUNT
|
||||||
};
|
};
|
||||||
|
|
|
@ -606,11 +606,8 @@ MustacheData InternalServer::get_default_data() const
|
||||||
bool InternalServer::etag_not_needed(const RequestContext& request) const
|
bool InternalServer::etag_not_needed(const RequestContext& request) const
|
||||||
{
|
{
|
||||||
const std::string url = request.get_url();
|
const std::string url = request.get_url();
|
||||||
return kiwix::startsWith(url, "/catalog")
|
return kiwix::startsWith(url, "/skin")
|
||||||
|| url == "/search"
|
|| url == "/random";
|
||||||
|| url == "/suggest"
|
|
||||||
|| url == "/random"
|
|
||||||
|| url == "/catch/external";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ETag
|
ETag
|
||||||
|
@ -761,7 +758,7 @@ std::unique_ptr<Response> InternalServer::handle_skin(const RequestContext& requ
|
||||||
*this,
|
*this,
|
||||||
getResource(resourceName),
|
getResource(resourceName),
|
||||||
getMimeTypeForFile(resourceName));
|
getMimeTypeForFile(resourceName));
|
||||||
response->set_cacheable();
|
response->set_kind(Response::STATIC_RESOURCE);
|
||||||
return std::move(response);
|
return std::move(response);
|
||||||
} catch (const ResourceNotFound& e) {
|
} catch (const ResourceNotFound& e) {
|
||||||
return HTTP404Response(*this, request)
|
return HTTP404Response(*this, request)
|
||||||
|
|
|
@ -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
|
} // unnamed namespace
|
||||||
|
|
||||||
|
@ -112,6 +120,13 @@ Response::Response(bool verbose)
|
||||||
add_header(MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*");
|
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> Response::build(const InternalServer& server)
|
std::unique_ptr<Response> Response::build(const InternalServer& server)
|
||||||
{
|
{
|
||||||
return std::unique_ptr<Response>(new Response(server.m_verbose.load()));
|
return std::unique_ptr<Response>(new Response(server.m_verbose.load()));
|
||||||
|
@ -122,6 +137,9 @@ std::unique_ptr<Response> Response::build_304(const InternalServer& server, cons
|
||||||
auto response = Response::build(server);
|
auto response = Response::build(server);
|
||||||
response->set_code(MHD_HTTP_NOT_MODIFIED);
|
response->set_code(MHD_HTTP_NOT_MODIFIED);
|
||||||
response->m_etag = etag;
|
response->m_etag = etag;
|
||||||
|
if ( etag.get_option(ETag::ZIM_CONTENT) ) {
|
||||||
|
response->set_kind(Response::ZIM_CONTENT);
|
||||||
|
}
|
||||||
if ( etag.get_option(ETag::COMPRESSED_CONTENT) ) {
|
if ( etag.get_option(ETag::COMPRESSED_CONTENT) ) {
|
||||||
response->add_header(MHD_HTTP_HEADER_VARY, "Accept-Encoding");
|
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_Response* response = create_mhd_response(request);
|
||||||
|
|
||||||
MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL,
|
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();
|
const std::string etag = m_etag.get_etag();
|
||||||
if ( ! etag.empty() )
|
if ( ! etag.empty() )
|
||||||
MHD_add_response_header(response, MHD_HTTP_HEADER_ETAG, etag.c_str());
|
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_mimeType(mimetype)
|
||||||
{
|
{
|
||||||
m_byteRange = byterange;
|
m_byteRange = byterange;
|
||||||
set_cacheable();
|
set_kind(Response::ZIM_CONTENT);
|
||||||
add_header(MHD_HTTP_HEADER_CONTENT_TYPE, m_mimeType);
|
add_header(MHD_HTTP_HEADER_CONTENT_TYPE, m_mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,14 +441,14 @@ std::unique_ptr<Response> ItemResponse::build(const InternalServer& server, cons
|
||||||
if (noRange && is_compressible_mime_type(mimetype)) {
|
if (noRange && is_compressible_mime_type(mimetype)) {
|
||||||
// Return a contentResponse
|
// Return a contentResponse
|
||||||
auto response = ContentResponse::build(server, item.getData(), mimetype);
|
auto response = ContentResponse::build(server, item.getData(), mimetype);
|
||||||
response->set_cacheable();
|
response->set_kind(Response::ZIM_CONTENT);
|
||||||
response->m_byteRange = byteRange;
|
response->m_byteRange = byteRange;
|
||||||
return std::move(response);
|
return std::move(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (byteRange.kind() == ByteRange::RESOLVED_UNSATISFIABLE) {
|
if (byteRange.kind() == ByteRange::RESOLVED_UNSATISFIABLE) {
|
||||||
auto response = Response::build_416(server, item.getSize());
|
auto response = Response::build_416(server, item.getSize());
|
||||||
response->set_cacheable();
|
response->set_kind(Response::ZIM_CONTENT);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,14 @@ class InternalServer;
|
||||||
class RequestContext;
|
class RequestContext;
|
||||||
|
|
||||||
class Response {
|
class Response {
|
||||||
|
public:
|
||||||
|
enum Kind
|
||||||
|
{
|
||||||
|
STATIC_RESOURCE,
|
||||||
|
ZIM_CONTENT,
|
||||||
|
DYNAMIC_CONTENT
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Response(bool verbose);
|
Response(bool verbose);
|
||||||
virtual ~Response() = default;
|
virtual ~Response() = default;
|
||||||
|
@ -57,7 +65,7 @@ class Response {
|
||||||
MHD_Result send(const RequestContext& request, MHD_Connection* connection);
|
MHD_Result send(const RequestContext& request, MHD_Connection* connection);
|
||||||
|
|
||||||
void set_code(int code) { m_returnCode = code; }
|
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 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; }
|
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;
|
MHD_Response* create_error_response(const RequestContext& request) const;
|
||||||
|
|
||||||
protected: // data
|
protected: // data
|
||||||
|
Kind m_kind = DYNAMIC_CONTENT;
|
||||||
bool m_verbose;
|
bool m_verbose;
|
||||||
int m_returnCode;
|
int m_returnCode;
|
||||||
ByteRange m_byteRange;
|
ByteRange m_byteRange;
|
||||||
|
|
|
@ -35,7 +35,7 @@ struct Resource
|
||||||
ResourceKind kind;
|
ResourceKind kind;
|
||||||
const char* url;
|
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)
|
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<Resource> ResourceCollection;
|
typedef std::vector<Resource> ResourceCollection;
|
||||||
|
|
||||||
const ResourceCollection resources200Compressible{
|
const ResourceCollection resources200Compressible{
|
||||||
{ STATIC_CONTENT, "/ROOT/" },
|
{ DYNAMIC_CONTENT, "/ROOT/" },
|
||||||
|
|
||||||
{ STATIC_CONTENT, "/ROOT/skin/autoComplete.min.js" },
|
{ STATIC_CONTENT, "/ROOT/skin/autoComplete.min.js" },
|
||||||
{ STATIC_CONTENT, "/ROOT/skin/css/autoComplete.css" },
|
{ STATIC_CONTENT, "/ROOT/skin/css/autoComplete.css" },
|
||||||
|
|
Loading…
Reference in New Issue