Created
September 2, 2016 23:33
-
-
Save zxmarcos/ca3eed8d33014dcfaf531a5c1cc2dfd3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/asio/spawn.hpp> | |
#include <boost/http/buffered_socket.hpp> | |
#include <boost/http/algorithm/query.hpp> | |
#include <boost/http/file_server.hpp> | |
#include <spdlog/spdlog.h> | |
namespace http_server | |
{ | |
namespace asio = boost::asio; | |
namespace http = boost::http; | |
using tcp = asio::ip::tcp; | |
static std::shared_ptr<spdlog::logger> logger; | |
class HttpConnection; | |
class HttpConnection : public std::enable_shared_from_this<HttpConnection> | |
{ | |
http::buffered_socket socket_; | |
int counter_; | |
std::string method_; | |
std::string path_; | |
http::message message_; | |
HttpConnection(asio::io_service &ios, int counter) | |
: socket_(ios) | |
, counter_(counter) | |
{ | |
} | |
public: | |
void operator()(asio::yield_context yield); | |
tcp::socket &tcp_layer() | |
{ | |
return socket_.next_layer(); | |
} | |
static std::shared_ptr<HttpConnection> MakeConnection(asio::io_service &ios, int counter) | |
{ | |
return std::shared_ptr<HttpConnection>{ new HttpConnection(ios, counter) }; | |
} | |
} | |
; | |
void HttpConnection::operator()(asio::yield_context yield) | |
{ | |
auto self = shared_from_this(); | |
try | |
{ | |
while (socket_.is_open()) | |
{ | |
// Lê uma requisição HTTP | |
socket_.async_read_request(method_, path_, message_, yield); | |
message_.body().clear(); | |
// Envia a messagem 100-continue, para pedir o corpo da mensagem. | |
if (http::request_continue_required(message_)) | |
{ | |
socket_.async_write_response_continue(yield); | |
} | |
while (socket_.read_state() != http::read_state::empty) | |
{ | |
switch (socket_.read_state()) | |
{ | |
case http::read_state::message_ready: | |
message_.body().clear(); | |
socket_.async_read_some(message_, yield); | |
break; | |
case http::read_state::body_ready: | |
socket_.async_read_trailers(message_, yield); | |
break; | |
default: | |
; | |
} | |
} | |
logger->info("Método: {} uri: {}", method_, path_); | |
auto body = std::string(std::begin(message_.body()), std::end(message_.body())); | |
logger->info(body); | |
http::message reply; | |
http::async_response_transmit_file(socket_, message_, reply, "/root/test.html", yield); | |
logger->info("Arquivo transmitido com sucesso!"); | |
} | |
} | |
catch (boost::system::system_error &e) | |
{ | |
if (e.code() == boost::system::error_code{ asio::error::eof }) | |
{ | |
logger->info("{} conexão fechada, EOF", counter_); | |
} | |
else | |
{ | |
logger->error("{} exceção recebida {}", counter_, e.what()); | |
} | |
} | |
catch (std::exception &e) | |
{ | |
logger->error("{} exceção recebida {}", counter_, e.what()); | |
} | |
} | |
class HttpServer | |
{ | |
boost::asio::io_service ios_; | |
public: | |
void Start(); | |
}; | |
void HttpServer::Start() | |
{ | |
if (!logger) | |
{ | |
logger = spdlog::stdout_logger_mt("HTTP", true); | |
} | |
logger->info("Iniciando servidor HTTP"); | |
// Cria um acceptor na porta 8080 | |
tcp::acceptor acceptor(ios_, tcp::endpoint(tcp::v4(), 8080)); | |
auto do_accept = [&](asio::yield_context yield) | |
{ | |
int counter = 0; | |
while (true) | |
{ | |
// Contador de conexões recebidas... | |
++counter; | |
try | |
{ | |
auto connection = HttpConnection::MakeConnection(ios_, counter); | |
// Aceita uma nova conexão assincronamente. | |
acceptor.async_accept(connection->tcp_layer(), yield); | |
logger->info("Nova conexão aceita de {}", connection->tcp_layer().remote_endpoint().address().to_string()); | |
// Controla as mensagens nesta conexão que acabamos de aceitar. | |
auto handle_connection = [connection](asio::yield_context yield) mutable | |
{ | |
(*connection)(yield); | |
}; | |
spawn(ios_, handle_connection); | |
} | |
catch (std::exception &e) | |
{ | |
logger->critical("Abortando, exceção recebida: {}", e.what()); | |
break; | |
} | |
} | |
}; | |
spawn(ios_, do_accept); | |
ios_.run(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment