|
|
|
@ -48,72 +48,73 @@ static beast::string_view mime_type(beast::string_view path)
|
|
|
|
|
if(iequals(ext, ".tif")) return "image/tiff";
|
|
|
|
|
if(iequals(ext, ".svg")) return "image/svg+xml";
|
|
|
|
|
if(iequals(ext, ".svgz")) return "image/svg+xml";
|
|
|
|
|
return "application/text";
|
|
|
|
|
return "application/octet-stream";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Report a failure
|
|
|
|
|
void fail(beast::error_code ec, char const* what)
|
|
|
|
|
static void fail(beast::error_code ec, char const* what)
|
|
|
|
|
{
|
|
|
|
|
std::cerr << what << ": " << ec.message() << "\n";
|
|
|
|
|
;}
|
|
|
|
|
|
|
|
|
|
void Webserver::add_url_handler(std::string url_regex, handler_t handler)
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard< std::mutex > lock(_mtx);
|
|
|
|
|
_urls.emplace(std::pair< std::string, Handling >(url_regex, {boost::regex(url_regex), handler}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handles an HTTP server connection
|
|
|
|
|
void Webserver::do_session(tcp::socket& socket)
|
|
|
|
|
void Webserver::remove_url_handler(std::string url_regex) {
|
|
|
|
|
std::lock_guard< std::mutex > lock(_mtx);
|
|
|
|
|
_urls.erase(url_regex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Webserver::handler_t Webserver::find_handler(request& r, boost::cmatch& m)
|
|
|
|
|
{
|
|
|
|
|
bool close = false;
|
|
|
|
|
beast::error_code ec;
|
|
|
|
|
for (auto it=_urls.begin(); it!=_urls.end(); ++it) {
|
|
|
|
|
if (boost::regex_match(r.target().data(), it->second.regex))
|
|
|
|
|
return it->second.handler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This buffer is required to persist across reads
|
|
|
|
|
beast::flat_buffer buffer;
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This lambda is used to send messages
|
|
|
|
|
// send_lambda<tcp::socket> lambda{socket, close, ec};
|
|
|
|
|
void Webserver::do_session(tcp::socket *socket)
|
|
|
|
|
{
|
|
|
|
|
beast::error_code ec;
|
|
|
|
|
beast::flat_buffer buffer;
|
|
|
|
|
|
|
|
|
|
while (_running)
|
|
|
|
|
{
|
|
|
|
|
// Read a request
|
|
|
|
|
http::request<http::string_body> req;
|
|
|
|
|
http::read(socket, buffer, req, ec);
|
|
|
|
|
if(ec == http::error::end_of_stream)
|
|
|
|
|
break;
|
|
|
|
|
if(ec)
|
|
|
|
|
return fail(ec, "read");
|
|
|
|
|
|
|
|
|
|
// Send the response
|
|
|
|
|
// handle_request(_doc_root, std::move(req), lambda);
|
|
|
|
|
if(ec)
|
|
|
|
|
return fail(ec, "write");
|
|
|
|
|
if(close)
|
|
|
|
|
{
|
|
|
|
|
// This means we should close the connection, usually because
|
|
|
|
|
// the response indicated the "Connection: close" semantic.
|
|
|
|
|
http::read(*socket, buffer, req, ec);
|
|
|
|
|
if (ec == http::error::end_of_stream)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ec)
|
|
|
|
|
return fail(ec, "reading from stream");
|
|
|
|
|
|
|
|
|
|
// Send a TCP shutdown
|
|
|
|
|
socket.shutdown(tcp::socket::shutdown_send, ec);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// At this point the connection is closed gracefully
|
|
|
|
|
socket->shutdown(tcp::socket::shutdown_send, ec);
|
|
|
|
|
delete socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Webserver::run()
|
|
|
|
|
{
|
|
|
|
|
_running = true;
|
|
|
|
|
// The acceptor receives incoming connections
|
|
|
|
|
while (_running)
|
|
|
|
|
{
|
|
|
|
|
// This will receive the new connection
|
|
|
|
|
tcp::socket socket{_ioc};
|
|
|
|
|
tcp::socket* socket = new tcp::socket{_ioc};
|
|
|
|
|
_acceptor.accept(*socket);
|
|
|
|
|
|
|
|
|
|
// Block until we get a connection
|
|
|
|
|
_acceptor.accept(socket);
|
|
|
|
|
|
|
|
|
|
// Launch the session, transferring ownership of the socket
|
|
|
|
|
std::function< void() > tf = [&](){do_session(socket);};
|
|
|
|
|
std::thread{tf}.detach();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Webserver::shutdown()
|
|
|
|
|
{
|
|
|
|
|
_running = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|