mirror of
https://github.com/boostorg/beast.git
synced 2025-08-03 23:04:35 +02:00
Fixes and simplifications to HTTP example server:
The example HTTP server is updated to provide the correct MIME-type. It no longer uses the now-deprecated http::stream class, since that implementation does not provide flow control. A new example async_write function is provided in the asynchronous server for managing the lifetime of a message sent asynchronously. The logging is thread-safe, and a bug causing connections to malfunction is fixed.
This commit is contained in:
@@ -19,9 +19,8 @@ endif()
|
|||||||
add_executable (http-server
|
add_executable (http-server
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
file_body.hpp
|
file_body.hpp
|
||||||
|
mime_type.hpp
|
||||||
http_async_server.hpp
|
http_async_server.hpp
|
||||||
http_stream.hpp
|
|
||||||
http_stream.ipp
|
|
||||||
http_sync_server.hpp
|
http_sync_server.hpp
|
||||||
http_server.cpp
|
http_server.cpp
|
||||||
)
|
)
|
||||||
|
@@ -9,9 +9,11 @@
|
|||||||
#define BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED
|
#define BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED
|
||||||
|
|
||||||
#include "file_body.hpp"
|
#include "file_body.hpp"
|
||||||
#include "http_stream.hpp"
|
#include "mime_type.hpp"
|
||||||
|
|
||||||
|
#include <beast/http.hpp>
|
||||||
#include <beast/core/placeholders.hpp>
|
#include <beast/core/placeholders.hpp>
|
||||||
|
#include <beast/core/streambuf.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -32,17 +34,19 @@ class http_async_server
|
|||||||
using req_type = request_v1<string_body>;
|
using req_type = request_v1<string_body>;
|
||||||
using resp_type = response_v1<file_body>;
|
using resp_type = response_v1<file_body>;
|
||||||
|
|
||||||
|
std::mutex m_;
|
||||||
|
bool log_ = true;
|
||||||
boost::asio::io_service ios_;
|
boost::asio::io_service ios_;
|
||||||
socket_type sock_;
|
|
||||||
boost::asio::ip::tcp::acceptor acceptor_;
|
boost::asio::ip::tcp::acceptor acceptor_;
|
||||||
|
socket_type sock_;
|
||||||
std::string root_;
|
std::string root_;
|
||||||
std::vector<std::thread> thread_;
|
std::vector<std::thread> thread_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
http_async_server(endpoint_type const& ep,
|
http_async_server(endpoint_type const& ep,
|
||||||
int threads, std::string const& root)
|
int threads, std::string const& root)
|
||||||
: sock_(ios_)
|
: acceptor_(ios_)
|
||||||
, acceptor_(ios_)
|
, sock_(ios_)
|
||||||
, root_(root)
|
, root_(root)
|
||||||
{
|
{
|
||||||
acceptor_.open(ep.protocol());
|
acceptor_.open(ep.protocol());
|
||||||
@@ -67,13 +71,124 @@ public:
|
|||||||
t.join();
|
t.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
void
|
||||||
|
log(Args const&... args)
|
||||||
|
{
|
||||||
|
if(log_)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_);
|
||||||
|
log_args(args...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
template<class Stream, class Handler,
|
||||||
|
bool isRequest, class Body, class Headers>
|
||||||
|
class write_op
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
handler_alloc<char, Handler>;
|
||||||
|
|
||||||
|
struct data
|
||||||
|
{
|
||||||
|
Stream& s;
|
||||||
|
message_v1<isRequest, Body, Headers> m;
|
||||||
|
Handler h;
|
||||||
|
bool cont;
|
||||||
|
|
||||||
|
template<class DeducedHandler>
|
||||||
|
data(DeducedHandler&& h_, Stream& s_,
|
||||||
|
message_v1<isRequest, Body, Headers>&& m_)
|
||||||
|
: s(s_)
|
||||||
|
, m(std::move(m_))
|
||||||
|
, h(std::forward<DeducedHandler>(h_))
|
||||||
|
, cont(boost_asio_handler_cont_helpers::
|
||||||
|
is_continuation(h))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<data> d_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
write_op(write_op&&) = default;
|
||||||
|
write_op(write_op const&) = default;
|
||||||
|
|
||||||
|
template<class DeducedHandler, class... Args>
|
||||||
|
write_op(DeducedHandler&& h, Stream& s, Args&&... args)
|
||||||
|
: d_(std::allocate_shared<data>(alloc_type{h},
|
||||||
|
std::forward<DeducedHandler>(h), s,
|
||||||
|
std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
(*this)(error_code{}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(error_code ec, bool again = true)
|
||||||
|
{
|
||||||
|
auto& d = *d_;
|
||||||
|
d.cont = d.cont || again;
|
||||||
|
if(! again)
|
||||||
|
{
|
||||||
|
beast::http::async_write(d.s, d.m, std::move(*this));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d.h(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void* asio_handler_allocate(
|
||||||
|
std::size_t size, write_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
allocate(size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void asio_handler_deallocate(
|
||||||
|
void* p, std::size_t size, write_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
deallocate(p, size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
bool asio_handler_is_continuation(write_op* op)
|
||||||
|
{
|
||||||
|
return op->d_->cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Function>
|
||||||
|
friend
|
||||||
|
void asio_handler_invoke(Function&& f, write_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_invoke_helpers::
|
||||||
|
invoke(f, op->d_->h);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Stream,
|
||||||
|
bool isRequest, class Body, class Headers,
|
||||||
|
class DeducedHandler>
|
||||||
|
static
|
||||||
|
void
|
||||||
|
async_write(Stream& stream, message_v1<
|
||||||
|
isRequest, Body, Headers>&& msg,
|
||||||
|
DeducedHandler&& handler)
|
||||||
|
{
|
||||||
|
write_op<Stream, typename std::decay<DeducedHandler>::type,
|
||||||
|
isRequest, Body, Headers>{std::forward<DeducedHandler>(
|
||||||
|
handler), stream, std::move(msg)};
|
||||||
|
}
|
||||||
|
|
||||||
class peer : public std::enable_shared_from_this<peer>
|
class peer : public std::enable_shared_from_this<peer>
|
||||||
{
|
{
|
||||||
int id_;
|
int id_;
|
||||||
stream<socket_type> stream_;
|
streambuf sb_;
|
||||||
|
socket_type sock_;
|
||||||
|
http_async_server& server_;
|
||||||
boost::asio::io_service::strand strand_;
|
boost::asio::io_service::strand strand_;
|
||||||
std::string root_;
|
|
||||||
req_type req_;
|
req_type req_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -82,16 +197,22 @@ private:
|
|||||||
peer& operator=(peer&&) = delete;
|
peer& operator=(peer&&) = delete;
|
||||||
peer& operator=(peer const&) = delete;
|
peer& operator=(peer const&) = delete;
|
||||||
|
|
||||||
explicit
|
peer(socket_type&& sock, http_async_server& server)
|
||||||
peer(socket_type&& sock, std::string const& root)
|
: sock_(std::move(sock))
|
||||||
: stream_(std::move(sock))
|
, server_(server)
|
||||||
, strand_(stream_.get_io_service())
|
, strand_(sock_.get_io_service())
|
||||||
, root_(root)
|
|
||||||
{
|
{
|
||||||
static int n = 0;
|
static int n = 0;
|
||||||
id_ = ++n;
|
id_ = ++n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fail(error_code ec, std::string what)
|
||||||
|
{
|
||||||
|
if(ec != boost::asio::error::operation_aborted)
|
||||||
|
server_.log("#", id_, " ", what, ": ", ec.message(), "\n");
|
||||||
|
}
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
do_read();
|
do_read();
|
||||||
@@ -99,43 +220,58 @@ private:
|
|||||||
|
|
||||||
void do_read()
|
void do_read()
|
||||||
{
|
{
|
||||||
stream_.async_read(req_, strand_.wrap(
|
async_read(sock_, sb_, req_, strand_.wrap(
|
||||||
std::bind(&peer::on_read, shared_from_this(),
|
std::bind(&peer::on_read, shared_from_this(),
|
||||||
asio::placeholders::error)));
|
asio::placeholders::error)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_read(error_code ec)
|
void on_read(error_code const& ec)
|
||||||
{
|
{
|
||||||
if(ec)
|
if(ec)
|
||||||
return fail(ec, "read");
|
return fail(ec, "read");
|
||||||
do_read();
|
|
||||||
auto path = req_.url;
|
auto path = req_.url;
|
||||||
if(path == "/")
|
if(path == "/")
|
||||||
path = "/index.html";
|
path = "/index.html";
|
||||||
path = root_ + path;
|
path = server_.root_ + path;
|
||||||
if(! boost::filesystem::exists(path))
|
if(! boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
response_v1<string_body> resp;
|
response_v1<string_body> res;
|
||||||
resp.status = 404;
|
res.status = 404;
|
||||||
resp.reason = "Not Found";
|
res.reason = "Not Found";
|
||||||
resp.version = req_.version;
|
res.version = req_.version;
|
||||||
resp.headers.replace("Server", "http_async_server");
|
res.headers.insert("Server", "http_async_server");
|
||||||
resp.body = "The file '" + path + "' was not found";
|
res.headers.insert("Content-Type", "text/html");
|
||||||
prepare(resp);
|
res.body = "The file '" + path + "' was not found";
|
||||||
stream_.async_write(std::move(resp),
|
prepare(res);
|
||||||
|
async_write(sock_, std::move(res),
|
||||||
std::bind(&peer::on_write, shared_from_this(),
|
std::bind(&peer::on_write, shared_from_this(),
|
||||||
asio::placeholders::error));
|
asio::placeholders::error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
resp_type resp;
|
resp_type res;
|
||||||
resp.status = 200;
|
res.status = 200;
|
||||||
resp.reason = "OK";
|
res.reason = "OK";
|
||||||
resp.version = req_.version;
|
res.version = req_.version;
|
||||||
resp.headers.replace("Server", "http_async_server");
|
res.headers.insert("Server", "http_async_server");
|
||||||
resp.headers.replace("Content-Type", "text/html");
|
res.headers.insert("Content-Type", mime_type(path));
|
||||||
resp.body = path;
|
res.body = path;
|
||||||
prepare(resp);
|
try
|
||||||
stream_.async_write(std::move(resp),
|
{
|
||||||
|
prepare(res);
|
||||||
|
}
|
||||||
|
catch(std::exception const& e)
|
||||||
|
{
|
||||||
|
res = {};
|
||||||
|
res.status = 500;
|
||||||
|
res.reason = "Internal Error";
|
||||||
|
res.version = req_.version;
|
||||||
|
res.headers.insert("Server", "http_async_server");
|
||||||
|
res.headers.insert("Content-Type", "text/html");
|
||||||
|
res.body =
|
||||||
|
std::string{"An internal error occurred"} + e.what();
|
||||||
|
prepare(res);
|
||||||
|
}
|
||||||
|
async_write(sock_, std::move(res),
|
||||||
std::bind(&peer::on_write, shared_from_this(),
|
std::bind(&peer::on_write, shared_from_this(),
|
||||||
asio::placeholders::error));
|
asio::placeholders::error));
|
||||||
}
|
}
|
||||||
@@ -144,36 +280,27 @@ private:
|
|||||||
{
|
{
|
||||||
if(ec)
|
if(ec)
|
||||||
fail(ec, "write");
|
fail(ec, "write");
|
||||||
}
|
do_read();
|
||||||
|
|
||||||
private:
|
|
||||||
void
|
|
||||||
fail(error_code ec, std::string what)
|
|
||||||
{
|
|
||||||
if(ec != boost::asio::error::operation_aborted)
|
|
||||||
{
|
|
||||||
std::cerr <<
|
|
||||||
"#" << std::to_string(id_) << " " <<
|
|
||||||
what << ": " << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
fail(error_code ec, std::string what)
|
log_args()
|
||||||
{
|
{
|
||||||
std::cerr <<
|
}
|
||||||
what << ": " << ec.message() << std::endl;
|
|
||||||
|
template<class Arg, class... Args>
|
||||||
|
void
|
||||||
|
log_args(Arg const& arg, Args const&... args)
|
||||||
|
{
|
||||||
|
std::cerr << arg;
|
||||||
|
log_args(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
maybe_throw(error_code ec, std::string what)
|
fail(error_code ec, std::string what)
|
||||||
{
|
{
|
||||||
if(ec)
|
log(what, ": ", ec.message(), "\n");
|
||||||
{
|
|
||||||
fail(ec, what);
|
|
||||||
throw ec;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -181,12 +308,13 @@ private:
|
|||||||
{
|
{
|
||||||
if(! acceptor_.is_open())
|
if(! acceptor_.is_open())
|
||||||
return;
|
return;
|
||||||
maybe_throw(ec, "accept");
|
if(ec)
|
||||||
|
return fail(ec, "accept");
|
||||||
socket_type sock(std::move(sock_));
|
socket_type sock(std::move(sock_));
|
||||||
acceptor_.async_accept(sock_,
|
acceptor_.async_accept(sock_,
|
||||||
std::bind(&http_async_server::on_accept, this,
|
std::bind(&http_async_server::on_accept, this,
|
||||||
asio::placeholders::error));
|
asio::placeholders::error));
|
||||||
std::make_shared<peer>(std::move(sock), root_)->run();
|
std::make_shared<peer>(std::move(sock), *this)->run();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -57,8 +57,13 @@ int main(int ac, char const* av[])
|
|||||||
endpoint_type ep{address_type::from_string(ip), port};
|
endpoint_type ep{address_type::from_string(ip), port};
|
||||||
|
|
||||||
if(sync)
|
if(sync)
|
||||||
|
{
|
||||||
http_sync_server server(ep, root);
|
http_sync_server server(ep, root);
|
||||||
|
beast::test::sig_wait();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
http_async_server server(ep, threads, root);
|
http_async_server server(ep, threads, root);
|
||||||
beast::test::sig_wait();
|
beast::test::sig_wait();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@@ -9,8 +9,9 @@
|
|||||||
#define BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
|
#define BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
|
||||||
|
|
||||||
#include "file_body.hpp"
|
#include "file_body.hpp"
|
||||||
#include "http_stream.hpp"
|
#include "mime_type.hpp"
|
||||||
|
|
||||||
|
#include <beast/core/streambuf.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@@ -34,6 +35,8 @@ class http_sync_server
|
|||||||
using req_type = request_v1<string_body>;
|
using req_type = request_v1<string_body>;
|
||||||
using resp_type = response_v1<file_body>;
|
using resp_type = response_v1<file_body>;
|
||||||
|
|
||||||
|
bool log_ = true;
|
||||||
|
std::mutex m_;
|
||||||
boost::asio::io_service ios_;
|
boost::asio::io_service ios_;
|
||||||
socket_type sock_;
|
socket_type sock_;
|
||||||
boost::asio::ip::tcp::acceptor acceptor_;
|
boost::asio::ip::tcp::acceptor acceptor_;
|
||||||
@@ -65,21 +68,43 @@ public:
|
|||||||
thread_.join();
|
thread_.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
void
|
void
|
||||||
fail(error_code ec, std::string what)
|
log(Args const&... args)
|
||||||
{
|
{
|
||||||
std::cerr <<
|
if(log_)
|
||||||
what << ": " << ec.message() << std::endl;
|
{
|
||||||
|
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
|
void
|
||||||
maybe_throw(error_code ec, std::string what)
|
fail(error_code ec, std::string what)
|
||||||
{
|
{
|
||||||
if(ec)
|
log(what, ": ", ec.message(), "\n");
|
||||||
{
|
|
||||||
fail(ec, what);
|
|
||||||
throw ec;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fail(int id, error_code const& ec)
|
||||||
|
{
|
||||||
|
if(ec != boost::asio::error::operation_aborted &&
|
||||||
|
ec != boost::asio::error::eof)
|
||||||
|
log("#", id, " ", ec.message(), "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lambda
|
struct lambda
|
||||||
@@ -109,7 +134,8 @@ public:
|
|||||||
{
|
{
|
||||||
if(! acceptor_.is_open())
|
if(! acceptor_.is_open())
|
||||||
return;
|
return;
|
||||||
maybe_throw(ec, "accept");
|
if(ec)
|
||||||
|
return fail(ec, "accept");
|
||||||
static int id_ = 0;
|
static int id_ = 0;
|
||||||
std::thread{lambda{++id_, *this, std::move(sock_)}}.detach();
|
std::thread{lambda{++id_, *this, std::move(sock_)}}.detach();
|
||||||
acceptor_.async_accept(sock_,
|
acceptor_.async_accept(sock_,
|
||||||
@@ -118,23 +144,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fail(int id, error_code const& ec)
|
do_peer(int id, socket_type&& sock0)
|
||||||
{
|
{
|
||||||
if(ec != boost::asio::error::operation_aborted &&
|
socket_type sock(std::move(sock0));
|
||||||
ec != boost::asio::error::eof)
|
streambuf sb;
|
||||||
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;
|
error_code ec;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
req_type req;
|
req_type req;
|
||||||
hs.read(req, ec);
|
http::read(sock, sb, req, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
break;
|
break;
|
||||||
auto path = req.url;
|
auto path = req.url;
|
||||||
@@ -143,26 +161,42 @@ public:
|
|||||||
path = root_ + path;
|
path = root_ + path;
|
||||||
if(! boost::filesystem::exists(path))
|
if(! boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
response_v1<string_body> resp;
|
response_v1<string_body> res;
|
||||||
resp.status = 404;
|
res.status = 404;
|
||||||
resp.reason = "Not Found";
|
res.reason = "Not Found";
|
||||||
resp.version = req.version;
|
res.version = req.version;
|
||||||
resp.headers.replace("Server", "http_sync_server");
|
res.headers.insert("Server", "http_sync_server");
|
||||||
resp.body = "The file '" + path + "' was not found";
|
res.headers.insert("Content-Type", "text/html");
|
||||||
prepare(resp);
|
res.body = "The file '" + path + "' was not found";
|
||||||
hs.write(resp, ec);
|
prepare(res);
|
||||||
|
write(sock, res, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
resp_type resp;
|
resp_type res;
|
||||||
resp.status = 200;
|
res.status = 200;
|
||||||
resp.reason = "OK";
|
res.reason = "OK";
|
||||||
resp.version = req.version;
|
res.version = req.version;
|
||||||
resp.headers.replace("Server", "http_sync_server");
|
res.headers.insert("Server", "http_sync_server");
|
||||||
resp.headers.replace("Content-Type", "text/html");
|
res.headers.insert("Content-Type", mime_type(path));
|
||||||
resp.body = path;
|
res.body = path;
|
||||||
prepare(resp);
|
try
|
||||||
hs.write(resp, ec);
|
{
|
||||||
|
prepare(res);
|
||||||
|
}
|
||||||
|
catch(std::exception const& e)
|
||||||
|
{
|
||||||
|
res = {};
|
||||||
|
res.status = 500;
|
||||||
|
res.reason = "Internal Error";
|
||||||
|
res.version = req.version;
|
||||||
|
res.headers.insert("Server", "http_sync_server");
|
||||||
|
res.headers.insert("Content-Type", "text/html");
|
||||||
|
res.body =
|
||||||
|
std::string{"An internal error occurred"} + e.what();
|
||||||
|
prepare(res);
|
||||||
|
}
|
||||||
|
write(sock, res, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
51
examples/mime_type.hpp
Normal file
51
examples/mime_type.hpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
//
|
||||||
|
// 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)
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BEAST_EXAMPLE_HTTP_MIME_TYPE_H_INCLUDED
|
||||||
|
#define BEAST_EXAMPLE_HTTP_MIME_TYPE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
// Return the Mime-Type for a given file extension
|
||||||
|
template<class = void>
|
||||||
|
std::string
|
||||||
|
mime_type(std::string const& path)
|
||||||
|
{
|
||||||
|
auto const ext =
|
||||||
|
boost::filesystem::path{path}.extension().string();
|
||||||
|
if(ext == ".txt") return "text/plain";
|
||||||
|
if(ext == ".htm") return "text/html";
|
||||||
|
if(ext == ".html") return "text/html";
|
||||||
|
if(ext == ".php") return "text/html";
|
||||||
|
if(ext == ".css") return "text/css";
|
||||||
|
if(ext == ".js") return "application/javascript";
|
||||||
|
if(ext == ".json") return "application/json";
|
||||||
|
if(ext == ".xml") return "application/xml";
|
||||||
|
if(ext == ".swf") return "application/x-shockwave-flash";
|
||||||
|
if(ext == ".flv") return "video/x-flv";
|
||||||
|
if(ext == ".png") return "image/png";
|
||||||
|
if(ext == ".jpe") return "image/jpeg";
|
||||||
|
if(ext == ".jpeg") return "image/jpeg";
|
||||||
|
if(ext == ".jpg") return "image/jpeg";
|
||||||
|
if(ext == ".gif") return "image/gif";
|
||||||
|
if(ext == ".bmp") return "image/bmp";
|
||||||
|
if(ext == ".ico") return "image/vnd.microsoft.icon";
|
||||||
|
if(ext == ".tiff") return "image/tiff";
|
||||||
|
if(ext == ".tif") return "image/tiff";
|
||||||
|
if(ext == ".svg") return "image/svg+xml";
|
||||||
|
if(ext == ".svgz") return "image/svg+xml";
|
||||||
|
return "application/text";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user