You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
3.4 KiB
C++
101 lines
3.4 KiB
C++
#pragma once
|
|
|
|
#include <mutex>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <thread>
|
|
#include <boost/asio/ip/tcp.hpp>
|
|
#include <boost/regex.hpp>
|
|
#include <boost/beast/http.hpp>
|
|
|
|
|
|
namespace pEp {
|
|
namespace beast = boost::beast;
|
|
namespace http = beast::http;
|
|
namespace net = boost::asio;
|
|
using tcp = boost::asio::ip::tcp;
|
|
|
|
// 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
|
|
//
|
|
// to deliver 404 return nullptr from handler
|
|
//
|
|
// this server is supporting GET for static files and POST for handlers
|
|
|
|
class Webserver {
|
|
public:
|
|
|
|
typedef boost::regex url_t;
|
|
typedef http::request< http::string_body > request;
|
|
typedef http::response< http::string_body > response;
|
|
typedef std::function< response(boost::cmatch, const request&) > handler_t;
|
|
|
|
private:
|
|
struct Handling {
|
|
boost::regex regex;
|
|
handler_t handler;
|
|
};
|
|
|
|
net::io_context _ioc;
|
|
tcp::acceptor _acceptor;
|
|
std::string _doc_root;
|
|
std::unordered_map< std::string, Handling > _urls;
|
|
handler_t _generic_handler;
|
|
unsigned short _port;
|
|
bool _running;
|
|
std::mutex _mtx;
|
|
std::thread _runner;
|
|
|
|
public:
|
|
|
|
// if doc_root is empty, don't deliver arbitrary files.
|
|
Webserver(net::ip::address addr, unsigned short port, const std::string& doc_root = "");
|
|
|
|
Webserver(const Webserver&) = delete;
|
|
Webserver& operator=(const Webserver&) = delete;
|
|
virtual ~Webserver() = default;
|
|
|
|
constexpr
|
|
int port() const noexcept { return _port; }
|
|
|
|
void add_url_handler (const std::string& url_regex, handler_t handler);
|
|
void remove_url_handler(const std::string& url_regex);
|
|
|
|
// 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();
|
|
|
|
void run();
|
|
void shutdown();
|
|
|
|
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 = "");
|
|
|
|
protected:
|
|
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.
|
|
void do_session(tcp::socket *socket);
|
|
};
|
|
};
|
|
|