Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 32 additions & 14 deletions src/odr/http_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ namespace odr {

class HttpServer::Impl {
public:
explicit Impl(HttpServer::Config config) : m_config{std::move(config)} {
Impl(HttpServer::Config config, std::shared_ptr<Logger> logger)
: m_config{std::move(config)}, m_logger{std::move(logger)} {
m_server.Get("/",
[](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("Hello World!", "text/plain");
Expand All @@ -30,13 +31,16 @@ class HttpServer::Impl {

const HttpServer::Config &config() const { return m_config; }

const std::shared_ptr<Logger> &logger() const { return m_logger; }

void serve_file(const httplib::Request &req, httplib::Response &res) {
std::string id = req.matches[1].str();
std::string path = req.matches.size() > 1 ? req.matches[2].str() : "";

std::unique_lock lock{m_mutex};
auto it = m_content.find(id);
if (it == m_content.end()) {
ODR_ERROR(*m_logger, "Content not found for ID: " << id);
res.status = 404;
return;
}
Expand All @@ -46,13 +50,16 @@ class HttpServer::Impl {
serve_file(res, content.service, path);
}

static void serve_file(httplib::Response &res, const HtmlService &service,
const std::string &path) {
void serve_file(httplib::Response &res, const HtmlService &service,
const std::string &path) {
if (!service.exists(path)) {
ODR_ERROR(*m_logger, "File not found: " << path);
res.status = 404;
return;
}

ODR_VERBOSE(*m_logger, "Serving file: " << path);

httplib::ContentProviderWithoutLength content_provider =
[service = service, path = path](std::size_t offset,
httplib::DataSink &sink) -> bool {
Expand All @@ -67,6 +74,8 @@ class HttpServer::Impl {
}

void connect_service(HtmlService service, const std::string &prefix) {
ODR_VERBOSE(*m_logger, "Connecting service with prefix: " << prefix);

std::unique_lock lock{m_mutex};

if (m_content.contains(prefix)) {
Expand All @@ -77,10 +86,14 @@ class HttpServer::Impl {
}

void listen(const std::string &host, std::uint32_t port) {
ODR_VERBOSE(*m_logger, "Listening on " << host << ":" << port);

m_server.listen(host, static_cast<int>(port));
}

void clear() {
ODR_VERBOSE(*m_logger, "Clearing HTTP server cache...");

std::unique_lock lock{m_mutex};

m_content.clear();
Expand All @@ -92,6 +105,8 @@ class HttpServer::Impl {
}

void stop() {
ODR_VERBOSE(*m_logger, "Stopping HTTP server...");

clear();

m_server.stop();
Expand All @@ -100,6 +115,8 @@ class HttpServer::Impl {
private:
HttpServer::Config m_config;

std::shared_ptr<Logger> m_logger;

httplib::Server m_server;

struct Content {
Expand All @@ -111,40 +128,41 @@ class HttpServer::Impl {
std::unordered_map<std::string, Content> m_content;
};

HttpServer::HttpServer(const Config &config)
: m_impl{std::make_unique<Impl>(config)} {}
HttpServer::HttpServer(const Config &config, std::shared_ptr<Logger> logger)
: m_impl{std::make_unique<Impl>(config, std::move(logger))} {}

const HttpServer::Config &HttpServer::config() const {
return m_impl->config();
}

void HttpServer::connect_service(HtmlService service,
const std::string &prefix) {
m_impl->connect_service(std::move(service), prefix);
}

HtmlViews HttpServer::serve_file(DecodedFile file, const std::string &prefix,
const HtmlConfig &config) {
static std::regex prefix_regex(prefix_pattern);
if (!std::regex_match(prefix, prefix_regex)) {
throw InvalidPrefix(prefix);
}

if (config.relative_resource_paths) {
if (service.config().relative_resource_paths) {
throw UnsupportedOption(
"relative_resource_paths cannot be enabled in server mode");
}
if (!config.embed_shipped_resources) {
if (!service.config().embed_shipped_resources) {
throw UnsupportedOption(
"embed_shipped_resources must be enabled in server mode");
}

m_impl->connect_service(std::move(service), prefix);
}

HtmlViews HttpServer::serve_file(DecodedFile file, const std::string &prefix,
const HtmlConfig &config) {
std::string cache_path = m_impl->config().cache_path + "/" + prefix;
std::filesystem::create_directories(cache_path);

HtmlService service = html::translate(file, cache_path, config);
HtmlService service =
html::translate(file, cache_path, config, m_impl->logger());

m_impl->connect_service(service, prefix);
connect_service(service, prefix);

return service.list_views();
}
Expand Down
6 changes: 4 additions & 2 deletions src/odr/http_server.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <odr/html.hpp>
#include <odr/logger.hpp>

#include <cstdint>
#include <memory>
Expand All @@ -21,9 +22,10 @@ class HttpServer {
std::string cache_path{"/tmp/odr"};
};

explicit HttpServer(const Config &config);
explicit HttpServer(const Config &config,
std::shared_ptr<Logger> logger = Logger::create_null());

const Config &config() const;
[[nodiscard]] const Config &config() const;

void connect_service(HtmlService service, const std::string &prefix);

Expand Down