forked from boostorg/beast
		
	* The examples/ directory is renamed to example/ * Each program is in its own directory with its own build scripts
		
			
				
	
	
		
			216 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//
 | 
						|
// Copyright (c) 2013-2017 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)
 | 
						|
//
 | 
						|
 | 
						|
#ifndef BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
 | 
						|
#define BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
 | 
						|
 | 
						|
#include "file_body.hpp"
 | 
						|
#include "mime_type.hpp"
 | 
						|
 | 
						|
#include <beast/http.hpp>
 | 
						|
#include <beast/core/multi_buffer.hpp>
 | 
						|
#include <boost/asio.hpp>
 | 
						|
#include <cstdint>
 | 
						|
#include <cstdio>
 | 
						|
#include <functional>
 | 
						|
#include <iostream>
 | 
						|
#include <memory>
 | 
						|
#include <mutex>
 | 
						|
#include <thread>
 | 
						|
#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<string_body>;
 | 
						|
    using resp_type = response<file_body>;
 | 
						|
 | 
						|
    bool log_ = true;
 | 
						|
    std::mutex m_;
 | 
						|
    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,
 | 
						|
                std::placeholders::_1));
 | 
						|
        thread_ = std::thread{[&]{ ios_.run(); }};
 | 
						|
    }
 | 
						|
 | 
						|
    ~http_sync_server()
 | 
						|
    {
 | 
						|
        error_code ec;
 | 
						|
        ios_.dispatch(
 | 
						|
            [&]{ acceptor_.close(ec); });
 | 
						|
        thread_.join();
 | 
						|
    }
 | 
						|
 | 
						|
    template<class... Args>
 | 
						|
    void
 | 
						|
    log(Args const&... args)
 | 
						|
    {
 | 
						|
        if(log_)
 | 
						|
        {
 | 
						|
            std::lock_guard<std::mutex> lock(m_);
 | 
						|
            log_args(args...);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
private:
 | 
						|
    void
 | 
						|
    log_args()
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    template<class Arg, class... Args>
 | 
						|
    void
 | 
						|
    log_args(Arg const& arg, Args const&... args)
 | 
						|
    {
 | 
						|
        std::cerr << arg;
 | 
						|
        log_args(args...);
 | 
						|
    }
 | 
						|
 | 
						|
    void
 | 
						|
    fail(error_code ec, std::string what)
 | 
						|
    {
 | 
						|
        log(what, ": ", ec.message(), "\n");
 | 
						|
    }
 | 
						|
 | 
						|
    void
 | 
						|
    fail(int id, error_code const& ec)
 | 
						|
    {
 | 
						|
        if(ec != boost::asio::error::operation_aborted &&
 | 
						|
                ec != error::end_of_stream)
 | 
						|
            log("#", id, " ", ec.message(), "\n");
 | 
						|
    }
 | 
						|
 | 
						|
    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));
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    void
 | 
						|
    on_accept(error_code ec)
 | 
						|
    {
 | 
						|
        if(! acceptor_.is_open())
 | 
						|
            return;
 | 
						|
        if(ec)
 | 
						|
            return fail(ec, "accept");
 | 
						|
        static int id_ = 0;
 | 
						|
        std::thread{lambda{++id_, *this, std::move(sock_)}}.detach();
 | 
						|
        acceptor_.async_accept(sock_,
 | 
						|
            std::bind(&http_sync_server::on_accept, this,
 | 
						|
                std::placeholders::_1));
 | 
						|
    }
 | 
						|
 | 
						|
    void
 | 
						|
    do_peer(int id, socket_type&& sock0)
 | 
						|
    {
 | 
						|
        socket_type sock(std::move(sock0));
 | 
						|
        multi_buffer b;
 | 
						|
        error_code ec;
 | 
						|
        for(;;)
 | 
						|
        {
 | 
						|
            req_type req;
 | 
						|
            http::read(sock, b, req, ec);
 | 
						|
            if(ec)
 | 
						|
                break;
 | 
						|
            auto path = req.target().to_string();
 | 
						|
            if(path == "/")
 | 
						|
                path = "/index.html";
 | 
						|
            path = root_ + path;
 | 
						|
            if(! boost::filesystem::exists(path))
 | 
						|
            {
 | 
						|
                response<string_body> res;
 | 
						|
                res.result(status::not_found);
 | 
						|
                res.version = req.version;
 | 
						|
                res.insert(field::server, "http_sync_server");
 | 
						|
                res.insert(field::content_type, "text/html");
 | 
						|
                res.body = "The file '" + path + "' was not found";
 | 
						|
                res.prepare();
 | 
						|
                write(sock, res, ec);
 | 
						|
                if(ec)
 | 
						|
                    break;
 | 
						|
                return;
 | 
						|
            }
 | 
						|
            try
 | 
						|
            {
 | 
						|
                resp_type res;
 | 
						|
                res.result(status::ok);
 | 
						|
                res.reason("OK");
 | 
						|
                res.version = req.version;
 | 
						|
                res.insert(field::server, "http_sync_server");
 | 
						|
                res.insert(field::content_type, mime_type(path));
 | 
						|
                res.body = path;
 | 
						|
                res.prepare();
 | 
						|
                write(sock, res, ec);
 | 
						|
                if(ec)
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
            catch(std::exception const& e)
 | 
						|
            {
 | 
						|
                response<string_body> res;
 | 
						|
                res.result(status::internal_server_error);
 | 
						|
                res.reason("Internal Error");
 | 
						|
                res.version = req.version;
 | 
						|
                res.insert(field::server, "http_sync_server");
 | 
						|
                res.insert(field::content_type, "text/html");
 | 
						|
                res.body =
 | 
						|
                    std::string{"An internal error occurred: "} + e.what();
 | 
						|
                res.prepare();
 | 
						|
                write(sock, res, ec);
 | 
						|
                if(ec)
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        fail(id, ec);
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
} // http
 | 
						|
} // beast
 | 
						|
 | 
						|
#endif
 |