webserver/webserver.hh

101 lines
3.4 KiB
C++
Raw Normal View History

2020-06-08 11:05:33 +02:00
#pragma once
#include <mutex>
2020-06-08 13:39:53 +02:00
#include <string>
2020-06-08 17:02:48 +02:00
#include <unordered_map>
2020-06-19 22:11:04 +02:00
#include <thread>
2020-06-08 13:39:53 +02:00
#include <boost/asio/ip/tcp.hpp>
#include <boost/regex.hpp>
2020-06-08 15:24:07 +02:00
#include <boost/beast/http.hpp>
2020-06-08 13:39:53 +02:00
2020-06-08 11:05:33 +02:00
namespace pEp {
2020-06-11 22:52:15 +02:00
namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::asio;
using tcp = boost::asio::ip::tcp;
2020-06-08 14:57:26 +02:00
// class Webserver
//
// when an URL handler is present it is called for each matching URL
// otherwise this server is searching for static files in doc_root
// only registered file types and no subdirectories are served for
// static files
2020-06-08 18:48:27 +02:00
//
// to deliver 404 return nullptr from handler
//
// this server is supporting GET for static files and POST for handlers
2020-06-08 14:57:26 +02:00
2020-06-08 13:01:56 +02:00
class Webserver {
2020-06-08 13:39:53 +02:00
public:
2020-06-08 13:39:53 +02:00
typedef boost::regex url_t;
2020-06-08 15:28:42 +02:00
typedef http::request< http::string_body > request;
typedef http::response< http::string_body > response;
typedef std::function< response(boost::cmatch, const request&) > handler_t;
2020-06-08 13:39:53 +02:00
private:
2020-06-08 17:02:48 +02:00
struct Handling {
boost::regex regex;
handler_t handler;
};
2020-06-08 13:39:53 +02:00
net::io_context _ioc;
tcp::acceptor _acceptor;
std::string _doc_root;
2020-06-08 17:02:48 +02:00
std::unordered_map< std::string, Handling > _urls;
handler_t _generic_handler;
unsigned short _port;
2020-06-08 14:57:26 +02:00
bool _running;
2020-06-08 17:02:48 +02:00
std::mutex _mtx;
2020-06-19 22:11:04 +02:00
std::thread _runner;
2020-06-08 13:01:56 +02:00
public:
// if doc_root is empty, don't deliver arbitrary files.
Webserver(net::ip::address addr, unsigned short port, const std::string& doc_root = "");
2020-06-08 13:01:56 +02:00
Webserver(const Webserver&) = delete;
Webserver& operator=(const Webserver&) = delete;
virtual ~Webserver() = default;
constexpr
int port() const noexcept { return _port; }
2020-06-08 13:01:56 +02:00
void add_url_handler (const std::string& url_regex, handler_t handler);
void remove_url_handler(const std::string& url_regex);
2020-06-08 17:02:48 +02:00
// the generic handler will be called if the URL does not match any registered handlers
void add_generic_url_handler (handler_t handler);
void remove_generic_url_handler();
2020-06-08 13:01:56 +02:00
void run();
2020-06-08 14:57:26 +02:00
void shutdown();
2020-06-08 13:01:56 +02:00
2020-06-08 22:00:49 +02:00
static beast::string_view mime_type(beast::string_view path);
static
response create_status_response(const request& req, http::status status);
static Webserver* probing_port_range(net::ip::address addr,
unsigned short start, unsigned short end, unsigned short&
port, const std::string& doc_root = "");
2020-06-08 13:01:56 +02:00
protected:
2020-06-19 22:11:04 +02:00
static void runner(Webserver *me);
void deliver_status(tcp::socket *socket, const request& req, http::status status);
void deliver_file (tcp::socket *socket, const request& req);
handler_t find_handler(const request& req, boost::cmatch& m);
// called at the beginning of a connection thread. Do nothing by default.
virtual void thread_init() {}
// called at the beginning of a connection thread. Do nothing by default.
virtual void thread_done() {}
// is called by run(), in a separate thread.
2020-06-08 17:02:48 +02:00
void do_session(tcp::socket *socket);
2020-06-08 13:01:56 +02:00
};
2020-06-08 11:05:33 +02:00
};