refactor to use beast

This commit is contained in:
Thomas Schleicher 2024-10-25 10:35:05 +02:00
parent 2a4e32a274
commit 656ddf2941
12 changed files with 177 additions and 150 deletions

50
src/http_connection.cpp Normal file
View file

@ -0,0 +1,50 @@
#include "../includes/http_connection.hpp"
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/beast/core/error.hpp>
#include <iostream>
#include <sys/socket.h>
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;
}
});
}

24
src/http_server.cpp Normal file
View file

@ -0,0 +1,24 @@
#include "../includes/http_server.hpp"
#include "http_connection.hpp"
#include <boost/asio/io_context.hpp>
#include <boost/asio/placeholders.hpp>
#include <sys/socket.h>
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();
}

View file

@ -1,38 +1,18 @@
#include "../includes/tcp_connection.hpp"
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio.hpp>
#include "../includes/http_server.hpp"
#include <iostream>
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)

14
src/request_handler.cpp Normal file
View file

@ -0,0 +1,14 @@
#include "../includes/request_handler.hpp"
#include <boost/beast/http/field.hpp>
#include <boost/beast/http/message.hpp>
#include <boost/beast/http/status.hpp>
#include <boost/beast/http/string_body.hpp>
http::response<http::string_body> RequestHandler::handle(const http::request<http::string_body>& request) {
http::response<http::string_body> 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;
}

View file

@ -1,51 +0,0 @@
#include "../includes/tcp_connection.hpp"
#include <boost/asio/buffer.hpp>
#include <boost/asio/write.hpp>
#include <boost/system/detail/error_code.hpp>
#include <iostream>
#include <boost/bind/bind.hpp>
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;
}
}