summaryrefslogtreecommitdiffhomepage
path: root/http.cpp
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2023-01-12 15:30:07 +0100
committerRoland Reichwein <mail@reichwein.it>2023-01-12 15:30:07 +0100
commit00ed7df1a09cad8862f2c586347f4f55c99681e5 (patch)
treee24ef2699affc7630ea42e728e62df7c6686f714 /http.cpp
parent3cb78411178f8458f889975799060e0bb866d2cf (diff)
Consolidate HTTP+HTTPS via CRTP
Diffstat (limited to 'http.cpp')
-rw-r--r--http.cpp278
1 files changed, 0 insertions, 278 deletions
diff --git a/http.cpp b/http.cpp
index 469f1aa..89f78d7 100644
--- a/http.cpp
+++ b/http.cpp
@@ -30,281 +30,3 @@ namespace net = boost::asio; // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
namespace websocket = beast::websocket;
-namespace {
-
-//------------------------------------------------------------------------------
-
-// Report a failure
-void fail(beast::error_code ec, char const* what)
-{
- std::cerr << what << ": " << ec.message() << "\n";
-}
-
-// Handles an HTTP server connection
-class session : public std::enable_shared_from_this<session>
-{
- boost::asio::io_context& ioc_;
- beast::tcp_stream stream_;
- beast::flat_buffer buffer_;
- Server& m_server;
- std::optional<http::request_parser<http::string_body>> parser_;
- request_type req_;
- std::shared_ptr<response_type> res_; // std::shared_ptr<void> ?
-
- void handle_request(::Server& server, request_type&& req)
- {
- stream_.expires_after(std::chrono::seconds(300)); // timeout on write by server much longer than read timeout from client
- auto sp = std::make_shared<response_type>(response::generate_response(req, server));
-
- res_ = sp;
-
- // Write the response
- http::async_write(
- stream_,
- *sp,
- beast::bind_front_handler(
- &session::on_write,
- shared_from_this(),
- sp->need_eof()));
- }
-
- void handle_websocket()
- {
- beast::get_lowest_layer(stream_).expires_never();
- make_websocket_session(ioc_, std::move(stream_), response::get_websocket_address(req_, m_server), parser_->release());
- }
-
-public:
- // Take ownership of the stream
- session(
- boost::asio::io_context& ioc,
- tcp::socket&& socket,
- Server& server):
- ioc_(ioc),
- stream_(std::move(socket)),
- m_server(server)
- {
- }
-
- // Start the asynchronous operation
- void run()
- {
- // We need to be executing within a strand to perform async operations
- // on the I/O objects in this session.
- net::dispatch(stream_.get_executor(),
- beast::bind_front_handler(
- &session::do_read,
- shared_from_this()));
- }
-
- void do_read()
- {
- // Make the request empty before reading,
- // otherwise the operation behavior is undefined.
- req_ = {};
-
- // this is the way to reset the parser. it's necessary.
- // https://github.com/boostorg/beast/issues/927
- parser_.emplace();
- parser_->body_limit(1000000000); // 1GB limit
-
- // Set the timeout.
- stream_.expires_after(std::chrono::seconds(30));
-
- // Read a request
- http::async_read(stream_, buffer_, *parser_,
- beast::bind_front_handler(
- &session::on_read,
- shared_from_this()));
- }
-
- void
- on_read(
- beast::error_code ec,
- std::size_t bytes_transferred
- )
- {
- boost::ignore_unused(bytes_transferred);
-
- // This means they closed the connection
- if (ec == http::error::end_of_stream)
- return do_close();
-
- if (ec == http::error::partial_message)
- return; // ignore
-
- if (ec)
- return fail(ec, "read");
-
- req_ = parser_->get();
-
- if (websocket::is_upgrade(req_))
- {
- handle_websocket();
- return;
- }
-
- // Send the response
- handle_request(m_server, std::move(req_));
- }
-
- void
- on_write(
- bool close,
- beast::error_code ec,
- std::size_t bytes_transferred
- )
- {
- boost::ignore_unused(bytes_transferred);
-
- if(ec)
- return fail(ec, "write");
-
- if(close)
- {
- // This means we should close the connection, usually because
- // the response indicated the "Connection: close" semantic.
- return do_close();
- }
-
- // We're done with the response so delete it
- res_ = nullptr;
-
- // Read another request
- do_read();
- }
-
- void
- do_close()
- {
- // Send a TCP shutdown
- beast::error_code ec;
- stream_.socket().shutdown(tcp::socket::shutdown_send, ec);
- // At this point the connection is closed gracefully
- }
-};
-
-//------------------------------------------------------------------------------
-
-// Accepts incoming connections and launches the sessions
-class listener : public std::enable_shared_from_this<listener>
-{
- net::io_context& ioc_;
- tcp::acceptor acceptor_;
- Server& m_server;
-
-public:
- listener(
- net::io_context& ioc,
- tcp::endpoint endpoint,
- Server& server)
- : ioc_(ioc)
- , acceptor_(net::make_strand(ioc))
- , m_server(server)
- {
- beast::error_code ec;
-
- // Open the acceptor
- acceptor_.open(endpoint.protocol(), ec);
- if(ec)
- {
- fail(ec, "open");
- return;
- }
-
- // Allow address reuse
- acceptor_.set_option(net::socket_base::reuse_address(true), ec);
- if(ec)
- {
- fail(ec, "set_option");
- return;
- }
-
- // Bind to the server address
- acceptor_.bind(endpoint, ec);
- if(ec)
- {
- fail(ec, "bind");
- return;
- }
-
- // Start listening for connections
- acceptor_.listen(
- net::socket_base::max_listen_connections, ec);
- if(ec)
- {
- fail(ec, "listen");
- return;
- }
- }
-
- // Start accepting incoming connections
- void
- run()
- {
- do_accept();
- }
-
-private:
- void
- do_accept()
- {
- // The new connection gets its own strand
- acceptor_.async_accept(
- net::make_strand(ioc_),
- beast::bind_front_handler(
- &listener::on_accept,
- shared_from_this()));
- }
-
- void
- on_accept(beast::error_code ec, tcp::socket socket)
- {
- if(ec)
- {
- fail(ec, "accept");
- }
- else
- {
- // Create the session and run it
- std::make_shared<session>(
- ioc_,
- std::move(socket),
- m_server)->run();
- }
-
- // Accept another connection
- do_accept();
- }
-};
-
-} // anonymous namespace
-
-//------------------------------------------------------------------------------
-
-namespace HTTP {
-
- Server::Server(Config& config, boost::asio::io_context& ioc, const Socket& socket, plugins_container_type& plugins, Statistics& statistics)
- : ::Server(config, ioc, socket, plugins, statistics)
- {
- }
-
- Server::~Server()
- {
- }
-
- int Server::start()
- {
- auto const address = net::ip::make_address(m_socket.address);
- auto const port = static_cast<unsigned short>(std::atoi(m_socket.port.data()));
-
- // Create and launch a listening port
- std::make_shared<listener>(
- m_ioc,
- tcp::endpoint{address, port},
- *this)->run();
-
- return EXIT_SUCCESS;
- }
-
-} // namespace HTTP