Implement ETags
This commit is contained in:
parent
9259f7c198
commit
b277d0274c
|
@ -1,8 +1,10 @@
|
||||||
|
#include <string>
|
||||||
|
#include <FastHash.h>
|
||||||
|
|
||||||
#include "routes.h"
|
#include "routes.h"
|
||||||
|
#include "../servehelper.h"
|
||||||
|
|
||||||
void css_route(const httplib::Request& req, httplib::Response& res) {
|
#define CSS R"EOF(
|
||||||
res.set_content(R"EOF(
|
|
||||||
|
|
||||||
/* GENERAL */
|
/* GENERAL */
|
||||||
:root {
|
:root {
|
||||||
--background-color: black;
|
--background-color: black;
|
||||||
|
@ -127,6 +129,20 @@ void css_route(const httplib::Request& req, httplib::Response& res) {
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-color: var(--error-border-color);
|
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
|
struct Config; // forward declaration from ../config.h
|
||||||
class PixivClient; // forward declaration from ../pixivclient.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 home_route(const httplib::Request& req, httplib::Response& res, const Config& config);
|
||||||
void css_route(const httplib::Request& req, httplib::Response& res);
|
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);
|
void user_illustrations_route(const httplib::Request& req, httplib::Response& res, const Config& config, PixivClient& pixiv_client);
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <FastHash.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "pixivmodels.h"
|
#include "pixivmodels.h"
|
||||||
#include "servehelper.h"
|
#include "servehelper.h"
|
||||||
|
#include "routes/routes.h"
|
||||||
|
|
||||||
static Element generate_pager(const Illusts& illusts, size_t page, const char* id);
|
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);
|
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
|
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());
|
+ "; 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("head", {
|
||||||
Element("meta", {{"charset", "utf-8"}}, {}),
|
Element("meta", {{"charset", "utf-8"}}, {}),
|
||||||
Element("title", {std::move(title)}),
|
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"}}, {})
|
Element("meta", {{"name", "viewport"}, {"content", "width=device-width,initial-scale=1"}}, {})
|
||||||
}),
|
}),
|
||||||
std::move(element)
|
std::move(element)
|
||||||
});
|
}).serialize();
|
||||||
res.set_content("<!DOCTYPE html>"s + html.serialize(), "text/html");
|
|
||||||
|
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,
|
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));
|
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) {
|
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 get_origin(const httplib::Request& req, const Config& config);
|
||||||
std::string proxy_url(blankie::murl::Url base, blankie::murl::Url url);
|
std::string proxy_url(blankie::murl::Url base, blankie::murl::Url url);
|
||||||
std::string proxy_image_url(const Config& config, 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);
|
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