Files
boost_beast/examples/http_sync_server.hpp
T

177 lines
4.4 KiB
C++
Raw Normal View History

2016-05-07 17:06:46 -04:00
//
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
2016-03-11 06:40:37 -05:00
#ifndef BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
#define BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
#include "file_body.hpp"
#include "http_stream.hpp"
2016-03-11 06:40:37 -05:00
#include <boost/asio.hpp>
#include <cstdint>
#include <cstdio>
#include <functional>
#include <iostream>
#include <memory>
#include <mutex>
#include <utility>
#include <iostream>
namespace beast {
namespace http {
class http_sync_server
{
using endpoint_type = boost::asio::ip::tcp::endpoint;
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
using req_type = request_v1<string_body>;
using resp_type = response_v1<file_body>;
2016-03-11 06:40:37 -05:00
boost::asio::io_service ios_;
socket_type sock_;
boost::asio::ip::tcp::acceptor acceptor_;
std::string root_;
std::thread thread_;
public:
http_sync_server(endpoint_type const& ep,
std::string const& root)
: sock_(ios_)
, acceptor_(ios_)
, root_(root)
{
acceptor_.open(ep.protocol());
acceptor_.bind(ep);
acceptor_.listen(
boost::asio::socket_base::max_connections);
acceptor_.async_accept(sock_,
std::bind(&http_sync_server::on_accept, this,
beast::asio::placeholders::error));
thread_ = std::thread{[&]{ ios_.run(); }};
}
~http_sync_server()
{
error_code ec;
ios_.dispatch(
[&]{ acceptor_.close(ec); });
thread_.join();
}
void
fail(error_code ec, std::string what)
{
std::cerr <<
what << ": " << ec.message() << std::endl;
}
void
maybe_throw(error_code ec, std::string what)
{
if(ec)
{
fail(ec, what);
throw ec;
}
}
2016-04-22 07:34:44 -04:00
struct lambda
{
int id;
http_sync_server& self;
socket_type sock;
boost::asio::io_service::work work;
lambda(int id_, http_sync_server& self_,
socket_type&& sock_)
: id(id_)
, self(self_)
, sock(std::move(sock_))
, work(sock.get_io_service())
{
}
void operator()()
{
self.do_peer(id, std::move(sock));
}
};
2016-03-11 06:40:37 -05:00
void
on_accept(error_code ec)
{
if(! acceptor_.is_open())
return;
maybe_throw(ec, "accept");
static int id_ = 0;
2016-04-22 07:34:44 -04:00
std::thread{lambda{++id_, *this, std::move(sock_)}}.detach();
2016-03-11 06:40:37 -05:00
acceptor_.async_accept(sock_,
std::bind(&http_sync_server::on_accept, this,
asio::placeholders::error));
}
void
fail(int id, error_code const& ec)
{
if(ec != boost::asio::error::operation_aborted &&
ec != boost::asio::error::eof)
std::cerr <<
"#" << std::to_string(id) << " " << std::endl;
}
void
do_peer(int id, socket_type&& sock)
{
http::stream<socket_type> hs(std::move(sock));
error_code ec;
for(;;)
{
req_type req;
hs.read(req, ec);
if(ec)
break;
auto path = req.url;
if(path == "/")
path = "/index.html";
path = root_ + path;
if(! boost::filesystem::exists(path))
{
2016-05-07 15:18:22 -04:00
response_v1<string_body> resp;
resp.status = 404;
resp.reason = "Not Found";
resp.version = req.version;
2016-03-11 06:40:37 -05:00
resp.headers.replace("Server", "http_sync_server");
resp.body = "The file '" + path + "' was not found";
prepare(resp);
2016-03-11 06:40:37 -05:00
hs.write(resp, ec);
if(ec)
break;
}
2016-05-07 15:18:22 -04:00
resp_type resp;
resp.status = 200;
resp.reason = "OK";
resp.version = req.version;
2016-03-11 06:40:37 -05:00
resp.headers.replace("Server", "http_sync_server");
resp.headers.replace("Content-Type", "text/html");
resp.body = path;
prepare(resp);
2016-03-11 06:40:37 -05:00
hs.write(resp, ec);
if(ec)
break;
}
fail(id, ec);
}
};
} // http
} // beast
#endif