90 lines
2.8 KiB
C++
90 lines
2.8 KiB
C++
#include <regex>
|
|
|
|
#include "config.h"
|
|
#include "servehelper.h"
|
|
|
|
static std::regex image_proxy_regex(
|
|
"(https?://)?" // optional scheme
|
|
"(?:.+?@)?" // optional username and pass
|
|
"([^/]+(?::\\d+)?)" // host
|
|
"(?:/.*)?$");
|
|
static inline std::string get_image_proxy_origin(const std::string& url);
|
|
|
|
void serve(const httplib::Request& req, httplib::Response& res, const Config& config, std::string title, Element element) {
|
|
using namespace std::string_literals;
|
|
|
|
std::string origin = get_origin(req, config);
|
|
std::string css_url = origin + "/style.css";
|
|
res.set_header("Content-Security-Policy", "default-src 'none'; style-src "s + css_url
|
|
+ "; img-src " + get_image_proxy_origin(config.image_proxy_url));
|
|
|
|
Element html("html", {
|
|
Element("head", {
|
|
Element("meta", {{"charset", "utf-8"}}, {}),
|
|
Element("title", {std::move(title)}),
|
|
Element("link", {{"rel", "stylesheet"}, {"href", std::move(css_url)}}, {})
|
|
}),
|
|
std::move(element)
|
|
});
|
|
res.set_content("<!DOCTYPE html>"s + html.serialize(), "text/html");
|
|
}
|
|
|
|
void serve_error(const httplib::Request& req, httplib::Response& res, const Config& config,
|
|
std::string title, std::optional<std::string> subtitle, std::optional<std::string> info) {
|
|
|
|
Element error_div("div", {{"class", "error"}}, {
|
|
Element("h2", {title})
|
|
});
|
|
if (subtitle) {
|
|
error_div.nodes.push_back(Element("p", {
|
|
std::move(*subtitle)
|
|
}));
|
|
}
|
|
if (info) {
|
|
error_div.nodes.push_back(Element("pre", {
|
|
Element("code", {std::move(*info)})
|
|
}));
|
|
}
|
|
|
|
Element body("body", {std::move(error_div)});
|
|
serve(req, res, config, std::move(title), std::move(body));
|
|
}
|
|
|
|
void serve_redirect(const httplib::Request& req, httplib::Response& res, const Config& config, std::string url) {
|
|
using namespace std::string_literals;
|
|
|
|
Element body("body", {
|
|
"Redirecting to ",
|
|
Element("a", {{"href", url}}, {url}),
|
|
"…"
|
|
});
|
|
res.set_redirect(url);
|
|
serve(req, res, config, "Redirecting to "s + std::move(url) + "…", std::move(body));
|
|
}
|
|
|
|
std::string get_origin(const httplib::Request& req, const Config& config) {
|
|
if (req.has_header("X-Canonical-Origin")) {
|
|
return req.get_header_value("X-Canonical-Origin");
|
|
}
|
|
|
|
std::string origin = "http://";
|
|
if (req.has_header("Host")) {
|
|
origin += req.get_header_value("Host");
|
|
} else {
|
|
origin += config.bind_host;
|
|
if (config.bind_port != 80) {
|
|
origin += ':' + std::to_string(config.bind_port);
|
|
}
|
|
}
|
|
return origin;
|
|
}
|
|
|
|
|
|
static inline std::string get_image_proxy_origin(const std::string& url) {
|
|
std::smatch sm;
|
|
if (!std::regex_match(url, sm, image_proxy_regex)) {
|
|
return url;
|
|
}
|
|
return sm[1].str() + sm[2].str();
|
|
}
|