Created
September 4, 2016 02:43
-
-
Save zxmarcos/19a4edca8325d69371772aaaac58e95d 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) | |
{ | |
try | |
{ | |
auto self = shared_from_this(); | |
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: | |
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; | |
logger->info("Enviando arquivo..."); | |
http::async_response_transmit_file(socket_, message_, reply, "C:\\dev\\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()); | |
} | |
} | |
// <------ Se vazasse, deveria ser pego aqui! | |
catch (std::ios_base::failure &e) | |
{ | |
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", false); | |
} | |
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(); | |
} | |
} | |
using namespace http_server; | |
int main(int argc, char *argv[]) | |
{ | |
try | |
{ | |
HttpServer service; | |
service.Start(); | |
} | |
catch (std::ios_base::failure &e) | |
{ | |
logger->error(e.what()); | |
} | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment