From 656ddf2941c7be96696719abb6aca3bc1d8a0880 Mon Sep 17 00:00:00 2001 From: Thomas Schleicher Date: Fri, 25 Oct 2024 10:35:05 +0200 Subject: [PATCH] refactor to use beast --- CMakeLists.txt | 4 ++- includes/http_connection.hpp | 37 +++++++++++++++++++++++++ includes/http_server.hpp | 24 +++++++++++++++++ includes/request_handler.hpp | 17 ++++++++++++ includes/request_parser.hpp | 23 ---------------- includes/response_handler.hpp | 14 ---------- includes/tcp_connection.hpp | 33 ----------------------- src/http_connection.cpp | 50 ++++++++++++++++++++++++++++++++++ src/http_server.cpp | 24 +++++++++++++++++ src/main.cpp | 36 ++++++------------------- src/request_handler.cpp | 14 ++++++++++ src/tcp_connection.cpp | 51 ----------------------------------- 12 files changed, 177 insertions(+), 150 deletions(-) create mode 100644 includes/http_connection.hpp create mode 100644 includes/http_server.hpp create mode 100644 includes/request_handler.hpp delete mode 100644 includes/request_parser.hpp delete mode 100644 includes/response_handler.hpp delete mode 100644 includes/tcp_connection.hpp create mode 100644 src/http_connection.cpp create mode 100644 src/http_server.cpp create mode 100644 src/request_handler.cpp delete mode 100644 src/tcp_connection.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f9dd6d..fd9c31d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,9 @@ set(BUILD_SHARED_LIBS OFF) include_directories(${PROJECT_SOURCE_DIR}/includes) add_executable(Application src/main.cpp - src/tcp_connection.cpp + src/http_connection.cpp + src/http_server.cpp + src/request_handler.cpp ) find_package(Boost REQUIRED COMPONENTS filesystem system) diff --git a/includes/http_connection.hpp b/includes/http_connection.hpp new file mode 100644 index 0000000..ab53345 --- /dev/null +++ b/includes/http_connection.hpp @@ -0,0 +1,37 @@ +#ifndef HTTP_CONNECTION_HPP +#define HTTP_CONNECTION_HPP + +#include "request_handler.hpp" +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace boost::asio; +using namespace boost::beast; + +class HttpConnection : public enable_shared_from_this { +public: + typedef shared_ptr pointer; + + static pointer create(io_context& io_context); + ip::tcp::socket& socket(); + void process_connection(); + +private: + ip::tcp::socket socket_; + boost::beast::flat_buffer buffer_; + http::request request_; + http::response response_; + RequestHandler request_handler_; + + void read(); + void write(); + + explicit HttpConnection(io_context& io_context); +}; + +#endif \ No newline at end of file diff --git a/includes/http_server.hpp b/includes/http_server.hpp new file mode 100644 index 0000000..70f3ca0 --- /dev/null +++ b/includes/http_server.hpp @@ -0,0 +1,24 @@ +#ifndef HTTP_SERVER_HPP +#define HTTP_SERVER_HPP + +#include "http_connection.hpp" +#include +#include +#include +#include + +using namespace boost::asio; + +class HttpServer { +public: + HttpServer(io_context& io_context, const ip::tcp::endpoint& endpoint); + +private: + io_context& io_context_; + ip::tcp::acceptor acceptor_; + + void accept_connection(); + void handle_accept(HttpConnection::pointer& new_connection, const boost::system::error_code& error_code); +}; + +#endif \ No newline at end of file diff --git a/includes/request_handler.hpp b/includes/request_handler.hpp new file mode 100644 index 0000000..2d14176 --- /dev/null +++ b/includes/request_handler.hpp @@ -0,0 +1,17 @@ +#ifndef REQUEST_HANDLER_HPP +#define REQUEST_HANDLER_HPP + +#include +#include +#include + +using namespace boost::beast; + +class RequestHandler { +public: + http::response handle(const http::request& request); + +private: +}; + +#endif \ No newline at end of file diff --git a/includes/request_parser.hpp b/includes/request_parser.hpp deleted file mode 100644 index a256ec8..0000000 --- a/includes/request_parser.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef REQUEST_PARSER_HPP -#define REQUEST_PARSER_HPP - -#include -#include -#include - -using namespace std; - -struct HttpRequest { - string method; - string uri; - string version; - map headers; - string body; -}; - -class request_parser { -public: - HttpRequest& parse(istream& data_stream); -}; - -#endif \ No newline at end of file diff --git a/includes/response_handler.hpp b/includes/response_handler.hpp deleted file mode 100644 index cce703b..0000000 --- a/includes/response_handler.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef RESPONSE_HANDLER_HPP -#define RESPONSE_HANDLER_HPP - -#include "request_parser.hpp" -#include - -using namespace std; - -class response_handler { -public: - string& handle(HttpRequest request); -}; - -#endif \ No newline at end of file diff --git a/includes/tcp_connection.hpp b/includes/tcp_connection.hpp deleted file mode 100644 index 47dcf92..0000000 --- a/includes/tcp_connection.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef TCP_CONNECTION_HPP -#define TCP_CONNECTION_HPP - -#include -#include -#include -#include "request_parser.hpp" -#include "response_handler.hpp" - -using namespace boost; -using namespace std; - -class tcp_connection : public std::enable_shared_from_this { -public: - typedef std::shared_ptr pointer; - - static pointer create(asio::io_context& io_context); - asio::ip::tcp::socket& socket(); - void handle(); - -private: - asio::ip::tcp::socket socket_; - asio::streambuf buffer_; - request_parser request_parser_; - response_handler response_handler_; - - explicit tcp_connection(asio::io_context& io_context); - - void handle_read(const system::error_code& error, size_t bytes_transferred); - void handle_write(const system::error_code& error, size_t bytes_transferred); -}; - -#endif \ No newline at end of file diff --git a/src/http_connection.cpp b/src/http_connection.cpp new file mode 100644 index 0000000..ed30d2f --- /dev/null +++ b/src/http_connection.cpp @@ -0,0 +1,50 @@ +#include "../includes/http_connection.hpp" +#include +#include +#include +#include +#include + +HttpConnection::HttpConnection(io_context& io_context) +: socket_(io_context) {}; + +HttpConnection::pointer HttpConnection::create(io_context& io_context) { + return pointer(new HttpConnection(io_context)); +} + +ip::tcp::socket& HttpConnection::socket() { + return socket_; +} + +void HttpConnection::process_connection() { + read(); +} + +void HttpConnection::read() { + auto self = shared_from_this(); + http::async_read(socket_, buffer_, request_, + [self](boost::beast::error_code error_code, size_t bytes_transferred) { + if (!error_code) { + cout << "Request received:\n" << self->request_ << endl; + self->response_ = self->request_handler_.handle(self->request_); + self->write(); + } else { + cerr << "Error reading: " << error_code.message() << endl; + } + }); +} + +void HttpConnection::write() { + auto self = shared_from_this(); + http::async_write(socket_, response_, + [self](boost::beast::error_code error_code, size_t bytes_transferred) { + if (!error_code) { + auto error_code_socket = self->socket_.shutdown(ip::tcp::socket::shutdown_send, error_code); + if (error_code_socket) { + cerr << "Error shuting down socket: " << error_code_socket.message() << endl; + } + } else { + cerr << "Error writing response: " << error_code.message() << endl; + } + }); +} \ No newline at end of file diff --git a/src/http_server.cpp b/src/http_server.cpp new file mode 100644 index 0000000..60b18c0 --- /dev/null +++ b/src/http_server.cpp @@ -0,0 +1,24 @@ +#include "../includes/http_server.hpp" +#include "http_connection.hpp" +#include +#include +#include + +HttpServer::HttpServer(io_context& io_context, const ip::tcp::endpoint& endpoint) + : io_context_(io_context), acceptor_(io_context, endpoint) { + accept_connection(); +} + +void HttpServer::accept_connection() { + HttpConnection::pointer new_connection = HttpConnection::create(io_context_); + acceptor_.async_accept(new_connection->socket(), + bind(&HttpServer::handle_accept, this, new_connection, boost::asio::placeholders::error) + ); +} + +void HttpServer::handle_accept(HttpConnection::pointer& new_connection, const boost::system::error_code& error_code) { + if (!error_code) { + new_connection->process_connection(); + } + accept_connection(); +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index c201c70..f7624fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,38 +1,18 @@ -#include "../includes/tcp_connection.hpp" -#include -#include + +#include "../includes/http_server.hpp" #include -class tcp_server { - public: - explicit tcp_server(boost::asio::io_context& io_context, const int port): io_context_(io_context), acceptor_(io_context, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)) { - start_accept(); - } - - private: - boost::asio::io_context& io_context_; - boost::asio::ip::tcp::acceptor acceptor_; - - void start_accept() { - tcp_connection::pointer new_connection = tcp_connection::create(io_context_); - acceptor_.async_accept(new_connection->socket(), std::bind(&tcp_server::handle_accept, this, new_connection, boost::asio::placeholders::error)); - } - - void handle_accept(tcp_connection::pointer& new_connection, const boost::system::error_code& error) { - if (!error) - { - new_connection->handle(); - } - start_accept(); - } -}; +using namespace boost::asio; int main(int argc, char *argv[]) { + const int port = 8080; + std::cout << "Starting server!" << std::endl; try { - boost::asio::io_context io_context; - tcp_server server(io_context, 9090); + io_context io_context; + ip::tcp::endpoint endpoint(ip::tcp::v4(), port); + HttpServer server(io_context, endpoint); io_context.run(); } catch (std::exception& e) diff --git a/src/request_handler.cpp b/src/request_handler.cpp new file mode 100644 index 0000000..a9c328e --- /dev/null +++ b/src/request_handler.cpp @@ -0,0 +1,14 @@ +#include "../includes/request_handler.hpp" +#include +#include +#include +#include + +http::response RequestHandler::handle(const http::request& request) { + http::response response{http::status::ok, request.version()}; + response.set(http::field::server, "Beast"); + response.set(http::field::content_type, "text/plain"); + response.body() = "Hello, World!"; + response.prepare_payload(); + return response; +} \ No newline at end of file diff --git a/src/tcp_connection.cpp b/src/tcp_connection.cpp deleted file mode 100644 index 0331757..0000000 --- a/src/tcp_connection.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "../includes/tcp_connection.hpp" -#include -#include -#include -#include -#include - -tcp_connection::tcp_connection(asio::io_context& io_context) - : socket_(io_context) {} - -tcp_connection::pointer tcp_connection::create(asio::io_context& io_context) { - return pointer(new tcp_connection(io_context)); -} - -asio::ip::tcp::socket& tcp_connection::socket() { - return socket_; -} - -void tcp_connection::handle() { - asio::async_read_until(socket_, buffer_, "\r\n", - bind(&tcp_connection::handle_read, - shared_from_this(), - asio::placeholders::error, - asio::placeholders::bytes_transferred) - ); -} - -void tcp_connection::handle_read(const boost::system::error_code& error, size_t bytes_transferred) { - if (!error) { - istream request_stream(&buffer_); - auto requst = request_parser_.parse(request_stream); - string response = response_handler_.handle(requst); - - asio::async_write(socket_, asio::buffer(response), - bind(&tcp_connection::handle_write, - shared_from_this(), - asio::placeholders::error, - asio::placeholders::bytes_transferred) - ); - } else { - std::cerr << "Error during read: " << error.message() << std::endl; - } -} - -void tcp_connection::handle_write(const system::error_code& error, size_t bytes_transferred) { - if (error) { - std::cerr << "Error during write: " << error.message() << std::endl; - } else { - std::cout << "Successfully sent " << bytes_transferred << " bytes." << std::endl; - } -}