|
|
@ -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; |
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|