Implement ETags
This commit is contained in:
parent
9259f7c198
commit
b277d0274c
|
@ -1,8 +1,10 @@
|
|||
#include <string>
|
||||
#include <FastHash.h>
|
||||
|
||||
#include "routes.h"
|
||||
#include "../servehelper.h"
|
||||
|
||||
void css_route(const httplib::Request& req, httplib::Response& res) {
|
||||
res.set_content(R"EOF(
|
||||
|
||||
#define CSS R"EOF(
|
||||
/* GENERAL */
|
||||
:root {
|
||||
--background-color: black;
|
||||
|
@ -127,6 +129,20 @@ void css_route(const httplib::Request& req, httplib::Response& res) {
|
|||
border-style: solid;
|
||||
border-color: var(--error-border-color);
|
||||
}
|
||||
)EOF"
|
||||
#define CSS_LEN sizeof(CSS) / sizeof(CSS[0]) - 1
|
||||
|
||||
)EOF", "text/css");
|
||||
const uint64_t css_hash = FastHashConstEval(CSS, CSS_LEN, 0);
|
||||
|
||||
void css_route(const httplib::Request& req, httplib::Response& res) {
|
||||
res.set_header("ETag", std::string(1, '"') + std::to_string(css_hash) + '"');
|
||||
res.set_header("Cache-Control", "max-age=31536000, immutable");
|
||||
|
||||
if (should_send_304(req, css_hash)) {
|
||||
res.status = 304;
|
||||
res.set_header("Content-Length", std::to_string(CSS_LEN));
|
||||
res.set_header("Content-Type", "text/css");
|
||||
} else {
|
||||
res.set_content(CSS, CSS_LEN, "text/css");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
struct Config; // forward declaration from ../config.h
|
||||
class PixivClient; // forward declaration from ../pixivclient.h
|
||||
|
||||
extern const uint64_t css_hash;
|
||||
|
||||
void home_route(const httplib::Request& req, httplib::Response& res, const Config& config);
|
||||
void css_route(const httplib::Request& req, httplib::Response& res);
|
||||
void user_illustrations_route(const httplib::Request& req, httplib::Response& res, const Config& config, PixivClient& pixiv_client);
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include <regex>
|
||||
#include <FastHash.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "pixivmodels.h"
|
||||
#include "servehelper.h"
|
||||
#include "routes/routes.h"
|
||||
|
||||
static Element generate_pager(const Illusts& illusts, size_t page, const char* id);
|
||||
static inline Element generate_illusts_grid(const httplib::Request& req, const Config& config, const Illusts& illusts);
|
||||
|
@ -16,16 +18,26 @@ void serve(const httplib::Request& req, httplib::Response& res, const Config& co
|
|||
res.set_header("Content-Security-Policy", "default-src 'none'; style-src "s + css_url
|
||||
+ "; img-src https://s.pximg.net " + config.image_proxy_url.get_origin());
|
||||
|
||||
Element html("html", {
|
||||
std::string html = "<!DOCTYPE html>"s + Element("html", {
|
||||
Element("head", {
|
||||
Element("meta", {{"charset", "utf-8"}}, {}),
|
||||
Element("title", {std::move(title)}),
|
||||
Element("link", {{"rel", "stylesheet"}, {"href", std::move(css_url)}}, {}),
|
||||
Element("link", {{"rel", "stylesheet"}, {"href", std::move(css_url) + "?v=" + std::to_string(css_hash)}}, {}),
|
||||
Element("meta", {{"name", "viewport"}, {"content", "width=device-width,initial-scale=1"}}, {})
|
||||
}),
|
||||
std::move(element)
|
||||
});
|
||||
res.set_content("<!DOCTYPE html>"s + html.serialize(), "text/html");
|
||||
}).serialize();
|
||||
|
||||
uint64_t hash = FastHash(html.data(), html.size(), 0);
|
||||
res.set_header("ETag", std::string(1, '"') + std::to_string(hash) + '"');
|
||||
|
||||
if (should_send_304(req, hash)) {
|
||||
res.status = 304;
|
||||
res.set_header("Content-Length", std::to_string(html.size()));
|
||||
res.set_header("Content-Type", "text/html");
|
||||
} else {
|
||||
res.set_content(std::move(html), "text/html");
|
||||
}
|
||||
}
|
||||
|
||||
void serve_error(const httplib::Request& req, httplib::Response& res, const Config& config,
|
||||
|
@ -100,6 +112,16 @@ std::string proxy_image_url(const Config& config, blankie::murl::Url url) {
|
|||
return proxy_url(config.image_proxy_url, std::move(url));
|
||||
}
|
||||
|
||||
bool should_send_304(const httplib::Request& req, uint64_t hash) {
|
||||
std::string header = req.get_header_value("If-None-Match");
|
||||
if (header == "*") {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t pos = header.find(std::string(1, '"') + std::to_string(hash) + '"');
|
||||
return pos != std::string::npos && (pos == 0 || header[pos - 1] != '/');
|
||||
}
|
||||
|
||||
|
||||
|
||||
Element generate_illusts_pager(const httplib::Request& req, const Config& config, const Illusts& illusts, size_t page, const char* id) {
|
||||
|
|
|
@ -18,5 +18,6 @@ void serve_redirect(const httplib::Request& req, httplib::Response& res, const C
|
|||
std::string get_origin(const httplib::Request& req, const Config& config);
|
||||
std::string proxy_url(blankie::murl::Url base, blankie::murl::Url url);
|
||||
std::string proxy_image_url(const Config& config, blankie::murl::Url url);
|
||||
bool should_send_304(const httplib::Request& req, uint64_t hash);
|
||||
|
||||
Element generate_illusts_pager(const httplib::Request& req, const Config& config, const Illusts& illusts, size_t page, const char* id);
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
// https://github.com/KoneLinx/small_ECS/blob/master/FastHash.h
|
||||
// but slightly modified to add FastHashConstEval and abandon ranges
|
||||
|
||||
// Copyright(C) 2021 Kobe Vrijsen <kobevrijsen@posteo.be>
|
||||
//
|
||||
// A simple ECS example
|
||||
//
|
||||
// This file is free software and distributed under the terms of the European Union
|
||||
// Public Lincense as published by the European Commision; either version 1.2 of the
|
||||
// License, or , at your option, any later version.
|
||||
|
||||
/* The MIT License
|
||||
|
||||
Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
// Source: fast-hash https://github.com/ztanml/fast-hash (26 Nov 2021)
|
||||
// Changes: General uplift and providing a general constant hash for ranges
|
||||
|
||||
#pragma once
|
||||
|
||||
// Compression function for Merkle-Damgard construction.
|
||||
// This function is generated using the framework provided.
|
||||
//#define mix(h) ({
|
||||
// (h) ^= (h) >> 23;
|
||||
// (h) *= 0x2127599bf4325c37ULL;
|
||||
// (h) ^= (h) >> 47; })
|
||||
|
||||
constexpr uint64_t FastHash(const char* str, size_t size, uint64_t seed/*, uint64_t back = {}*/)
|
||||
{
|
||||
auto const mix = [](uint64_t h)
|
||||
{
|
||||
h ^= h >> 23;
|
||||
h *= 0x2127599bf4325c37ULL;
|
||||
h ^= h >> 47;
|
||||
return h;
|
||||
};
|
||||
|
||||
const uint64_t m = 0x880355f21e6d1965ULL;
|
||||
|
||||
uint64_t h = seed ^ (size * m);
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
h ^= mix(static_cast<uint64_t>(str[i]));
|
||||
h *= m;
|
||||
}
|
||||
|
||||
//if (back != uint64_t())
|
||||
//{
|
||||
// h ^= mix(back);
|
||||
// h *= m;
|
||||
//}
|
||||
|
||||
return mix(h);
|
||||
}
|
||||
|
||||
consteval uint64_t FastHashConstEval(const char* str, size_t size, uint64_t seed) {
|
||||
return FastHash(str, size, seed);
|
||||
}
|
Loading…
Reference in New Issue