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.
webserver/webserver.cc

121 lines
3.6 KiB
C++

// this file is derived from a boost::beast sample
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/config.hpp>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
#include "webserver.hh"
namespace pEp {
Webserver::Webserver(net::ip::address addr, unsigned short port, std::string doc_root)
: _ioc(1), _acceptor(_ioc, {addr, port}), _doc_root(doc_root), _running(false) { }
// Return a reasonable mime type based on the extension of a file.
static beast::string_view mime_type(beast::string_view path)
{
using beast::iequals;
auto const ext = [&path]
{
auto const pos = path.rfind(".");
if(pos == beast::string_view::npos)
return beast::string_view{};
return path.substr(pos);
}();
if(iequals(ext, ".htm")) return "text/html";
if(iequals(ext, ".html")) return "text/html";
if(iequals(ext, ".css")) return "text/css";
if(iequals(ext, ".txt")) return "text/plain";
if(iequals(ext, ".js")) return "application/javascript";
if(iequals(ext, ".json")) return "application/json";
if(iequals(ext, ".xml")) return "application/xml";
if(iequals(ext, ".png")) return "image/png";
if(iequals(ext, ".jpeg")) return "image/jpeg";
if(iequals(ext, ".jpg")) return "image/jpeg";
if(iequals(ext, ".gif")) return "image/gif";
if(iequals(ext, ".ico")) return "image/vnd.microsoft.icon";
if(iequals(ext, ".tiff")) return "image/tiff";
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";
}
// Report a failure
void fail(beast::error_code ec, char const* what)
{
std::cerr << what << ": " << ec.message() << "\n";
}
// Handles an HTTP server connection
void Webserver::do_session(tcp::socket& socket)
{
bool close = false;
beast::error_code ec;
// This buffer is required to persist across reads
beast::flat_buffer buffer;
// This lambda is used to send messages
// send_lambda<tcp::socket> lambda{socket, close, ec};
for(;;)
{
// 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.
break;
}
}
// Send a TCP shutdown
socket.shutdown(tcp::socket::shutdown_send, ec);
// At this point the connection is closed gracefully
}
void Webserver::run()
{
_running = true;
// The acceptor receives incoming connections
while (_running)
{
// This will receive the new connection
tcp::socket socket{_ioc};
// 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();
}
}
};