#include #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(""s + html.serialize(), "text/html"); } void serve_error(const httplib::Request& req, httplib::Response& res, const Config& config, std::string title, std::optional subtitle, std::optional 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(); }