Fixes #46: library is now fully asynchronous
This commit is contained in:
parent
1609f80c38
commit
dc466e7d1d
4 changed files with 128 additions and 128 deletions
106
server_http.hpp
106
server_http.hpp
|
|
@ -2,7 +2,6 @@
|
|||
#define SERVER_HTTP_HPP
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
|
@ -21,27 +20,17 @@ namespace SimpleWeb {
|
|||
|
||||
class Response : public std::ostream {
|
||||
friend class ServerBase<socket_type>;
|
||||
private:
|
||||
boost::asio::yield_context& yield;
|
||||
|
||||
|
||||
boost::asio::streambuf streambuf;
|
||||
|
||||
socket_type &socket;
|
||||
|
||||
Response(socket_type &socket, boost::asio::yield_context& yield):
|
||||
std::ostream(&streambuf), yield(yield), socket(socket) {}
|
||||
|
||||
std::shared_ptr<socket_type> socket;
|
||||
|
||||
Response(std::shared_ptr<socket_type> socket): std::ostream(&streambuf), socket(socket) {}
|
||||
|
||||
public:
|
||||
size_t size() {
|
||||
return streambuf.size();
|
||||
}
|
||||
void flush() {
|
||||
boost::system::error_code ec;
|
||||
boost::asio::async_write(socket, streambuf, yield[ec]);
|
||||
|
||||
if(ec)
|
||||
throw std::runtime_error(ec.message());
|
||||
}
|
||||
};
|
||||
|
||||
class Content : public std::istream {
|
||||
|
|
@ -109,11 +98,11 @@ namespace SimpleWeb {
|
|||
|
||||
class Config {
|
||||
friend class ServerBase<socket_type>;
|
||||
private:
|
||||
Config(unsigned short port, size_t num_threads): port(port), num_threads(num_threads), reuse_address(true) {}
|
||||
unsigned short port;
|
||||
|
||||
Config(unsigned short port, size_t num_threads): num_threads(num_threads), port(port), reuse_address(true) {}
|
||||
size_t num_threads;
|
||||
public:
|
||||
unsigned short port;
|
||||
///IPv4 address in dotted decimal form or IPv6 address in hexadecimal notation.
|
||||
///If empty, the address will be any address.
|
||||
std::string address;
|
||||
|
|
@ -124,14 +113,14 @@ namespace SimpleWeb {
|
|||
Config config;
|
||||
|
||||
std::unordered_map<std::string, std::unordered_map<std::string,
|
||||
std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > > resource;
|
||||
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > > resource;
|
||||
|
||||
std::unordered_map<std::string,
|
||||
std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > default_resource;
|
||||
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > default_resource;
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::string, std::vector<std::pair<boost::regex,
|
||||
std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > > > > opt_resource;
|
||||
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > > > > opt_resource;
|
||||
|
||||
public:
|
||||
void start() {
|
||||
|
|
@ -191,6 +180,13 @@ namespace SimpleWeb {
|
|||
acceptor.close();
|
||||
io_service.stop();
|
||||
}
|
||||
|
||||
void send(std::shared_ptr<Response> response, const std::function<void(const boost::system::error_code&)>& callback=nullptr) {
|
||||
boost::asio::async_write(*response->socket, response->streambuf, [this, response, callback](const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
|
||||
if(callback)
|
||||
callback(ec);
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_service io_service;
|
||||
|
|
@ -357,48 +353,44 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
void write_response(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request,
|
||||
std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)>& resource_function) {
|
||||
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>,
|
||||
std::shared_ptr<typename ServerBase<socket_type>::Request>)>& resource_function) {
|
||||
//Set timeout on the following boost::asio::async-read or write function
|
||||
std::shared_ptr<boost::asio::deadline_timer> timer;
|
||||
if(timeout_content>0)
|
||||
timer=set_timeout_on_socket(socket, request, timeout_content);
|
||||
|
||||
boost::asio::spawn(request->strand, [this, &resource_function, socket, request, timer](boost::asio::yield_context yield) {
|
||||
Response response(*socket, yield);
|
||||
|
||||
try {
|
||||
resource_function(response, request);
|
||||
}
|
||||
catch(const std::exception&) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(response.size()>0) {
|
||||
try {
|
||||
response.flush();
|
||||
auto response=std::shared_ptr<Response>(new Response(socket), [this, request, timer](Response *response_ptr) {
|
||||
auto response=std::shared_ptr<Response>(response_ptr);
|
||||
send(response, [this, response, request, timer](const boost::system::error_code& ec) {
|
||||
if(!ec) {
|
||||
if(timeout_content>0)
|
||||
timer->cancel();
|
||||
float http_version;
|
||||
try {
|
||||
http_version=stof(request->http_version);
|
||||
}
|
||||
catch(const std::exception &) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto range=request->header.equal_range("Connection");
|
||||
for(auto it=range.first;it!=range.second;it++) {
|
||||
if(boost::iequals(it->second, "close"))
|
||||
return;
|
||||
}
|
||||
if(http_version>1.05)
|
||||
read_request_and_content(response->socket);
|
||||
}
|
||||
catch(const std::exception &) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(timeout_content>0)
|
||||
timer->cancel();
|
||||
float http_version;
|
||||
try {
|
||||
http_version=stof(request->http_version);
|
||||
}
|
||||
catch(const std::exception &) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto range=request->header.equal_range("Connection");
|
||||
for(auto it=range.first;it!=range.second;it++) {
|
||||
if(boost::iequals(it->second, "close"))
|
||||
return;
|
||||
}
|
||||
if(http_version>1.05)
|
||||
read_request_and_content(socket);
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
resource_function(response, request);
|
||||
}
|
||||
catch(const std::exception&) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue