332 lines
8.5 KiB
C++
332 lines
8.5 KiB
C++
#include <seafire/server/diagnostics.hxx>
|
|
#include <seafire/server/response.hxx>
|
|
#include <seafire/server/server.hxx>
|
|
|
|
#include <seafire/protocol/rfc7231/content-type.hxx>
|
|
|
|
#include <seafire/common/io/buffer.hxx>
|
|
#include <seafire/common/io/error.hxx>
|
|
|
|
#include <asio.hpp>
|
|
|
|
namespace seafire::server
|
|
{
|
|
|
|
/// Construct a new HTTP server using the specified acceptors
|
|
/// and request handler.
|
|
///
|
|
server_t::
|
|
server_t(common::diagnostics_t& diagnostics,
|
|
configuration_t configuration,
|
|
acceptor_set_t acceptors,
|
|
request_handler_t handler)
|
|
: diagnostics_{diagnostics},
|
|
configuration_{configuration},
|
|
acceptors_{std::move(acceptors)},
|
|
handler_{handler},
|
|
supervisor_{diagnostics_, *this, handler_}
|
|
{}
|
|
|
|
void
|
|
server_t::
|
|
start()
|
|
{
|
|
trace() << "starting Seafire server...";
|
|
|
|
// fixme: add tracing.
|
|
//
|
|
|
|
for (auto const& j : acceptors_) {
|
|
init_accept(*j);
|
|
}
|
|
}
|
|
|
|
void
|
|
server_t::
|
|
stop(bool quick)
|
|
{
|
|
trace() << "Seafire server stop requested...";
|
|
|
|
if (quick) {
|
|
supervisor_.stop_all();
|
|
}
|
|
}
|
|
|
|
void
|
|
server_t::
|
|
on_error(request_t& req, response_t& res, common_error_t error)
|
|
{
|
|
trace() << "on_error()...";
|
|
|
|
namespace rfc7231 = protocol::rfc7231;
|
|
|
|
switch (error) {
|
|
case common_error_t::bad_request: {
|
|
static std::string const message{"Bad request\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(400, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::payment_required: {
|
|
static std::string const message{"Payment required\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(402, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::forbidden: {
|
|
static std::string const message{"Forbidden\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(403, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::not_found: {
|
|
static std::string const message{"Not found\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(404, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::method_not_allowed: {
|
|
static std::string const message{"Method not allowed\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(405, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::not_acceptable: {
|
|
static std::string const message{"Not acceptable\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(406, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::request_timeout: {
|
|
static std::string const message{"Request timeout\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(408, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::conflict: {
|
|
static std::string const message{"Conflict\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(409, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::gone: {
|
|
static std::string const message{"Gone\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(410, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::length_required: {
|
|
static std::string const message{"Length required\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(411, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::payload_too_large: {
|
|
static std::string const message{"Payload too large\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(413, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::uri_too_long: {
|
|
static std::string const message{"Target URI too long\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(414, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::unsupported_media_type: {
|
|
static std::string const message{"Unsupported media type\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(415, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::expectation_failed: {
|
|
static std::string const message{"Expectation failed\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(417, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::upgrade_required: {
|
|
static std::string const message{"Upgrade required\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(426, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
|
|
case common_error_t::internal_server_error: {
|
|
static std::string const message{"Internal server error\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(500, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::not_implemented: {
|
|
static std::string const message{"Not implemented\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(501, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::bad_gateway: {
|
|
static std::string const message{"Bad gateway\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(502, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::service_unavailable: {
|
|
static std::string const message{"Service unavailable\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(503, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::gateway_timeout: {
|
|
static std::string const message{"Gateway timeout\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(504, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::http_version_not_supported: {
|
|
static std::string const message{"HTTP version not supported\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(505, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
// rfc 7232
|
|
//
|
|
|
|
case common_error_t::not_modified: {
|
|
static std::string const message{"Not modified\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(304, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::precondition_failed: {
|
|
static std::string const message{"Precondition failed\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(412, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
// rfc 7235
|
|
//
|
|
|
|
case common_error_t::unauthorized: {
|
|
static std::string const message{"Unauthorized\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(401, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
case common_error_t::proxy_auth_required: {
|
|
static std::string const message{"Proxy authentication required\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(407, common::io::buffer(message));
|
|
return;
|
|
}
|
|
|
|
// Unofficial.
|
|
//
|
|
|
|
case common_error_t::enhance_your_calm: {
|
|
static std::string const message{"Enhance your calm\n"};
|
|
|
|
set<rfc7231::content_type_t>(res, "text", "plain");
|
|
res.send(420, common::io::buffer(message));
|
|
return;
|
|
}
|
|
}
|
|
|
|
throw std::invalid_argument{"invalid common error"};
|
|
}
|
|
|
|
void
|
|
server_t::
|
|
on_exception(request_t&, response_t&) noexcept
|
|
{
|
|
trace() << "on_exception()...";
|
|
}
|
|
|
|
common::diagnostics_t::proxy_t
|
|
server_t::
|
|
trace()
|
|
{
|
|
return diagnostics_ << server_category();
|
|
}
|
|
|
|
void
|
|
server_t::
|
|
init_accept(common::io::acceptor_t& acceptor)
|
|
{
|
|
trace() << "init_accept()...";
|
|
|
|
auto bound = [this, &acceptor](std::error_code const& ec)
|
|
{
|
|
on_accept(acceptor, ec);
|
|
};
|
|
|
|
supervisor_.async_accept(acceptor, bound);
|
|
}
|
|
|
|
void
|
|
server_t::
|
|
on_accept(common::io::acceptor_t& acceptor, std::error_code const& ec)
|
|
{
|
|
trace() << "on_accept()...";
|
|
|
|
if (!ec) {
|
|
// no error.
|
|
//
|
|
init_accept(acceptor);
|
|
}
|
|
else if (ec != asio::error::operation_aborted) {
|
|
// fixme: handle error accordingly.
|
|
//
|
|
}
|
|
}
|
|
|
|
} // namespace seafire::server
|