Cleanup of #127: using standalone asio.

This commit is contained in:
eidheim 2017-06-07 18:36:53 +02:00
commit ec63c4345e
8 changed files with 238 additions and 265 deletions

View file

@ -6,7 +6,7 @@ services:
script: script:
- sudo docker run -it -v "$PWD:/repository" debian:testing sh -c " - sudo docker run -it -v "$PWD:/repository" debian:testing sh -c "
apt-get update && apt-get update &&
apt-get install --yes cmake make g\+\+ clang perl libssl-dev libboost-thread-dev libboost-regex-dev libboost-date-time-dev libboost-filesystem-dev && apt-get install --yes cmake make g\+\+ clang perl libssl-dev libboost-thread-dev libboost-regex-dev libboost-date-time-dev libboost-filesystem-dev libasio-dev &&
cd /repository && mkdir build && cd build && cd /repository && mkdir build && cd build &&
scan-build cmake -DCMAKE_CXX_FLAGS=-Werror .. && scan-build cmake -DCMAKE_CXX_FLAGS=-Werror .. &&
scan-build --status-bugs make && scan-build --status-bugs make &&
@ -16,5 +16,9 @@ script:
rm -r * && rm -r * &&
CXX=g++ cmake -DCMAKE_CXX_FLAGS=-Werror .. && CXX=g++ cmake -DCMAKE_CXX_FLAGS=-Werror .. &&
make && make &&
CTEST_OUTPUT_ON_FAILURE=1 make test &&
rm -r * &&
CXX=g++ cmake -DCMAKE_CXX_FLAGS=\"-Werror -DUSE_STANDALONE_ASIO\" .. &&
make &&
CTEST_OUTPUT_ON_FAILURE=1 make test CTEST_OUTPUT_ON_FAILURE=1 make test
" "

View file

@ -7,77 +7,56 @@
#include <mutex> #include <mutex>
#include <type_traits> #include <type_traits>
#ifdef NO_BOOST #ifdef USE_STANDALONE_ASIO
#include <boost/utility/string_ref.hpp> #include <boost/utility/string_ref.hpp>
#include <asio.hpp> #include <asio.hpp>
#include <type_traits> #include <type_traits>
#include <system_error> #include <system_error>
namespace asio_ns = asio; namespace SimpleWeb {
namespace error_ns = std; using error_code = std::error_code;
namespace merror_ns = std; using errc = std::errc;
# ifndef CASE_INSENSITIVE_EQUALS_AND_HASH using system_error = std::system_error;
# define CASE_INSENSITIVE_EQUALS_AND_HASH
class case_insensitive_equals {
public:
bool operator()(const std::string &Left, const std::string &Right) const {
return Left.size() == Right.size()
&& std::equal ( Left.begin() , Left.end() , Right.begin() ,
[]( char a , char b ) {
return tolower(a) == tolower(b);
});
} }
};
bool IEQUALS(const std::string& Left, const std::string& Right)
{
return Left.size() == Right.size()
&& std::equal ( Left.begin() , Left.end() , Right.begin() , []( char a , char b ) {
return tolower(a) == tolower(b);
});
}
class case_insensitive_hash {
public:
size_t operator()(const std::string& Keyval) const
{
//You might need a better hash function than this
size_t h = 0;
std::for_each( Keyval.begin() , Keyval.end() , [&](char c ) {
h += tolower(c);
});
return h;
}
};
# endif
#else #else
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/utility/string_ref.hpp> #include <boost/utility/string_ref.hpp>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
namespace asio_ns = boost::asio; namespace SimpleWeb {
namespace error_ns = boost::system; namespace asio = boost::asio;
namespace merror_ns = boost::system::errc; using error_code = boost::system::error_code;
namespace errc = boost::system::errc;
using system_error = boost::system::system_error;
}
#endif
# ifndef CASE_INSENSITIVE_EQUALS_AND_HASH # ifndef CASE_INSENSITIVE_EQUALS_AND_HASH
# define CASE_INSENSITIVE_EQUALS_AND_HASH # define CASE_INSENSITIVE_EQUALS_AND_HASH
# define IEQUALS boost::iequals namespace SimpleWeb {
//Based on http://www.boost.org/doc/libs/1_60_0/doc/html/unordered/hash_equality.html bool iequals(const std::string &str1, const std::string &str2) {
return str1.size() == str2.size() &&
std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) {
return tolower(a) == tolower(b);
});
}
class case_insensitive_equals { class case_insensitive_equals {
public: public:
bool operator()(const std::string &key1, const std::string &key2) const { bool operator()(const std::string &str1, const std::string &str2) const {
return boost::algorithm::iequals(key1, key2); return iequals(str1, str2);
} }
}; };
// Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226
class case_insensitive_hash { class case_insensitive_hash {
public: public:
size_t operator()(const std::string &key) const { size_t operator()(const std::string &str) const {
std::size_t seed=0; size_t h = 0;
for(auto &c: key) std::hash<int> hash;
boost::hash_combine(seed, std::tolower(c)); for (auto c : str)
return seed; h ^= hash(tolower(c)) + 0x9e3779b9 + (h << 6) + (h >> 2);
return h;
} }
}; };
# endif }
# endif # endif
namespace SimpleWeb { namespace SimpleWeb {
@ -100,7 +79,7 @@ namespace SimpleWeb {
std::unordered_multimap<std::string, std::string, case_insensitive_hash, case_insensitive_equals> header; std::unordered_multimap<std::string, std::string, case_insensitive_hash, case_insensitive_equals> header;
private: private:
asio_ns::streambuf content_buffer; asio::streambuf content_buffer;
Response(): content(&content_buffer) {} Response(): content(&content_buffer) {}
}; };
@ -126,10 +105,10 @@ namespace SimpleWeb {
auto corrected_path=path; auto corrected_path=path;
if(corrected_path=="") if(corrected_path=="")
corrected_path="/"; corrected_path="/";
if(!config.proxy_server.empty() && std::is_same<socket_type, asio_ns::ip::tcp::socket>::value) if(!config.proxy_server.empty() && std::is_same<socket_type, asio::ip::tcp::socket>::value)
corrected_path="http://"+host+':'+std::to_string(port)+corrected_path; corrected_path="http://"+host+':'+std::to_string(port)+corrected_path;
asio_ns::streambuf write_buffer; asio::streambuf write_buffer;
std::ostream write_stream(&write_buffer); std::ostream write_stream(&write_buffer);
write_stream << request_type << " " << corrected_path << " HTTP/1.1\r\n"; write_stream << request_type << " " << corrected_path << " HTTP/1.1\r\n";
write_stream << "Host: " << host << "\r\n"; write_stream << "Host: " << host << "\r\n";
@ -143,21 +122,21 @@ namespace SimpleWeb {
connect(); connect();
auto timer=get_timeout_timer(); auto timer=get_timeout_timer();
asio_ns::async_write(*socket, write_buffer, asio::async_write(*socket, write_buffer,
[this, &content, timer](const error_ns::error_code &ec, size_t /*bytes_transferred*/) { [this, &content, timer](const error_code &ec, size_t /*bytes_transferred*/) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(!ec) { if(!ec) {
if(!content.empty()) { if(!content.empty()) {
auto timer=get_timeout_timer(); auto timer=get_timeout_timer();
asio_ns::async_write(*socket, asio_ns::buffer(content.data(), content.size()), asio::async_write(*socket, asio::buffer(content.data(), content.size()),
[this, timer](const error_ns::error_code &ec, size_t /*bytes_transferred*/) { [this, timer](const error_code &ec, size_t /*bytes_transferred*/) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(ec) { if(ec) {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
this->socket=nullptr; this->socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
} }
@ -165,7 +144,7 @@ namespace SimpleWeb {
else { else {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
socket=nullptr; socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
io_service.reset(); io_service.reset();
@ -179,14 +158,14 @@ namespace SimpleWeb {
auto corrected_path=path; auto corrected_path=path;
if(corrected_path=="") if(corrected_path=="")
corrected_path="/"; corrected_path="/";
if(!config.proxy_server.empty() && std::is_same<socket_type, asio_ns::ip::tcp::socket>::value) if(!config.proxy_server.empty() && std::is_same<socket_type, asio::ip::tcp::socket>::value)
corrected_path="http://"+host+':'+std::to_string(port)+corrected_path; corrected_path="http://"+host+':'+std::to_string(port)+corrected_path;
content.seekp(0, std::ios::end); content.seekp(0, std::ios::end);
auto content_length=content.tellp(); auto content_length=content.tellp();
content.seekp(0, std::ios::beg); content.seekp(0, std::ios::beg);
asio_ns::streambuf write_buffer; asio::streambuf write_buffer;
std::ostream write_stream(&write_buffer); std::ostream write_stream(&write_buffer);
write_stream << request_type << " " << corrected_path << " HTTP/1.1\r\n"; write_stream << request_type << " " << corrected_path << " HTTP/1.1\r\n";
write_stream << "Host: " << host << "\r\n"; write_stream << "Host: " << host << "\r\n";
@ -202,14 +181,14 @@ namespace SimpleWeb {
connect(); connect();
auto timer=get_timeout_timer(); auto timer=get_timeout_timer();
asio_ns::async_write(*socket, write_buffer, asio::async_write(*socket, write_buffer,
[this, timer](const error_ns::error_code &ec, size_t /*bytes_transferred*/) { [this, timer](const error_code &ec, size_t /*bytes_transferred*/) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(ec) { if(ec) {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
socket=nullptr; socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
io_service.reset(); io_service.reset();
@ -221,15 +200,15 @@ namespace SimpleWeb {
void close() { void close() {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
if(socket) { if(socket) {
error_ns::error_code ec; error_code ec;
socket->lowest_layer().shutdown(asio_ns::ip::tcp::socket::shutdown_both, ec); socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec);
socket->lowest_layer().close(); socket->lowest_layer().close();
} }
} }
protected: protected:
asio_ns::io_service io_service; asio::io_service io_service;
asio_ns::ip::tcp::resolver resolver; asio::ip::tcp::resolver resolver;
std::unique_ptr<socket_type> socket; std::unique_ptr<socket_type> socket;
std::mutex socket_mutex; std::mutex socket_mutex;
@ -259,15 +238,15 @@ namespace SimpleWeb {
virtual void connect()=0; virtual void connect()=0;
std::shared_ptr<asio_ns::deadline_timer> get_timeout_timer(size_t timeout=0) { std::shared_ptr<asio::deadline_timer> get_timeout_timer(size_t timeout=0) {
if(timeout==0) if(timeout==0)
timeout=config.timeout; timeout=config.timeout;
if(timeout==0) if(timeout==0)
return nullptr; return nullptr;
auto timer=std::make_shared<asio_ns::deadline_timer>(io_service); auto timer=std::make_shared<asio::deadline_timer>(io_service);
timer->expires_from_now(boost::posix_time::seconds(timeout)); timer->expires_from_now(boost::posix_time::seconds(timeout));
timer->async_wait([this](const error_ns::error_code& ec) { timer->async_wait([this](const error_code& ec) {
if(!ec) { if(!ec) {
close(); close();
} }
@ -304,11 +283,11 @@ namespace SimpleWeb {
std::shared_ptr<Response> request_read() { std::shared_ptr<Response> request_read() {
std::shared_ptr<Response> response(new Response()); std::shared_ptr<Response> response(new Response());
asio_ns::streambuf chunked_streambuf; asio::streambuf chunked_streambuf;
auto timer=get_timeout_timer(); auto timer=get_timeout_timer();
asio_ns::async_read_until(*socket, response->content_buffer, "\r\n\r\n", asio::async_read_until(*socket, response->content_buffer, "\r\n\r\n",
[this, &response, &chunked_streambuf, timer](const error_ns::error_code& ec, size_t bytes_transferred) { [this, &response, &chunked_streambuf, timer](const error_code& ec, size_t bytes_transferred) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(!ec) { if(!ec) {
@ -321,15 +300,15 @@ namespace SimpleWeb {
auto content_length=stoull(header_it->second); auto content_length=stoull(header_it->second);
if(content_length>num_additional_bytes) { if(content_length>num_additional_bytes) {
auto timer=get_timeout_timer(); auto timer=get_timeout_timer();
asio_ns::async_read(*socket, response->content_buffer, asio::async_read(*socket, response->content_buffer,
asio_ns::transfer_exactly(content_length-num_additional_bytes), asio::transfer_exactly(content_length-num_additional_bytes),
[this, timer](const error_ns::error_code& ec, size_t /*bytes_transferred*/) { [this, timer](const error_code& ec, size_t /*bytes_transferred*/) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(ec) { if(ec) {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
this->socket=nullptr; this->socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
} }
@ -339,15 +318,15 @@ namespace SimpleWeb {
} }
else if(response->http_version<"1.1" || ((header_it=response->header.find("Connection"))!=response->header.end() && header_it->second=="close")) { else if(response->http_version<"1.1" || ((header_it=response->header.find("Connection"))!=response->header.end() && header_it->second=="close")) {
auto timer=get_timeout_timer(); auto timer=get_timeout_timer();
asio_ns::async_read(*socket, response->content_buffer, asio::async_read(*socket, response->content_buffer,
[this, timer](const error_ns::error_code& ec, size_t /*bytes_transferred*/) { [this, timer](const error_code& ec, size_t /*bytes_transferred*/) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(ec) { if(ec) {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
this->socket=nullptr; this->socket=nullptr;
if(ec!=asio_ns::error::eof) if(ec!=asio::error::eof)
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
} }
@ -355,7 +334,7 @@ namespace SimpleWeb {
else { else {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
socket=nullptr; socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
io_service.reset(); io_service.reset();
@ -364,10 +343,10 @@ namespace SimpleWeb {
return response; return response;
} }
void request_read_chunked(const std::shared_ptr<Response> &response, asio_ns::streambuf &streambuf) { void request_read_chunked(const std::shared_ptr<Response> &response, asio::streambuf &streambuf) {
auto timer=get_timeout_timer(); auto timer=get_timeout_timer();
asio_ns::async_read_until(*socket, response->content_buffer, "\r\n", asio::async_read_until(*socket, response->content_buffer, "\r\n",
[this, &response, &streambuf, timer](const error_ns::error_code& ec, size_t bytes_transferred) { [this, &response, &streambuf, timer](const error_code& ec, size_t bytes_transferred) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(!ec) { if(!ec) {
@ -401,9 +380,9 @@ namespace SimpleWeb {
if((2+length)>num_additional_bytes) { if((2+length)>num_additional_bytes) {
auto timer=get_timeout_timer(); auto timer=get_timeout_timer();
asio_ns::async_read(*socket, response->content_buffer, asio::async_read(*socket, response->content_buffer,
asio_ns::transfer_exactly(2+length-num_additional_bytes), asio::transfer_exactly(2+length-num_additional_bytes),
[this, post_process, timer](const error_ns::error_code& ec, size_t /*bytes_transferred*/) { [this, post_process, timer](const error_code& ec, size_t /*bytes_transferred*/) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(!ec) { if(!ec) {
@ -412,7 +391,7 @@ namespace SimpleWeb {
else { else {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
this->socket=nullptr; this->socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
} }
@ -422,7 +401,7 @@ namespace SimpleWeb {
else { else {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
socket=nullptr; socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
} }
@ -431,7 +410,7 @@ namespace SimpleWeb {
template<class socket_type> template<class socket_type>
class Client : public ClientBase<socket_type> {}; class Client : public ClientBase<socket_type> {};
typedef asio_ns::ip::tcp::socket HTTP; typedef asio::ip::tcp::socket HTTP;
template<> template<>
class Client<HTTP> : public ClientBase<HTTP> { class Client<HTTP> : public ClientBase<HTTP> {
@ -441,15 +420,15 @@ namespace SimpleWeb {
protected: protected:
void connect() { void connect() {
if(!socket || !socket->is_open()) { if(!socket || !socket->is_open()) {
std::unique_ptr<asio_ns::ip::tcp::resolver::query> query; std::unique_ptr<asio::ip::tcp::resolver::query> query;
if(config.proxy_server.empty()) if(config.proxy_server.empty())
query=std::unique_ptr<asio_ns::ip::tcp::resolver::query>(new asio_ns::ip::tcp::resolver::query(host, std::to_string(port))); query=std::unique_ptr<asio::ip::tcp::resolver::query>(new asio::ip::tcp::resolver::query(host, std::to_string(port)));
else { else {
auto proxy_host_port=parse_host_port(config.proxy_server, 8080); auto proxy_host_port=parse_host_port(config.proxy_server, 8080);
query=std::unique_ptr<asio_ns::ip::tcp::resolver::query>(new asio_ns::ip::tcp::resolver::query(proxy_host_port.first, std::to_string(proxy_host_port.second))); query=std::unique_ptr<asio::ip::tcp::resolver::query>(new asio::ip::tcp::resolver::query(proxy_host_port.first, std::to_string(proxy_host_port.second)));
} }
resolver.async_resolve(*query, [this](const error_ns::error_code &ec, resolver.async_resolve(*query, [this](const error_code &ec,
asio_ns::ip::tcp::resolver::iterator it){ asio::ip::tcp::resolver::iterator it){
if(!ec) { if(!ec) {
{ {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
@ -457,25 +436,25 @@ namespace SimpleWeb {
} }
auto timer=get_timeout_timer(config.timeout_connect); auto timer=get_timeout_timer(config.timeout_connect);
asio_ns::async_connect(*socket, it, [this, timer] asio::async_connect(*socket, it, [this, timer]
(const error_ns::error_code &ec, asio_ns::ip::tcp::resolver::iterator /*it*/){ (const error_code &ec, asio::ip::tcp::resolver::iterator /*it*/){
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(!ec) { if(!ec) {
asio_ns::ip::tcp::no_delay option(true); asio::ip::tcp::no_delay option(true);
this->socket->set_option(option); this->socket->set_option(option);
} }
else { else {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
this->socket=nullptr; this->socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
} }
else { else {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
socket=nullptr; socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
io_service.reset(); io_service.reset();

View file

@ -2,10 +2,15 @@
#define CLIENT_HTTPS_HPP #define CLIENT_HTTPS_HPP
#include "client_http.hpp" #include "client_http.hpp"
#ifdef USE_STANDALONE_ASIO
#include <asio/ssl.hpp>
#else
#include <boost/asio/ssl.hpp> #include <boost/asio/ssl.hpp>
#endif
namespace SimpleWeb { namespace SimpleWeb {
typedef asio_ns::ssl::stream<asio_ns::ip::tcp::socket> HTTPS; typedef asio::ssl::stream<asio::ip::tcp::socket> HTTPS;
template<> template<>
class Client<HTTPS> : public ClientBase<HTTPS> { class Client<HTTPS> : public ClientBase<HTTPS> {
@ -13,14 +18,14 @@ namespace SimpleWeb {
Client(const std::string& server_port_path, bool verify_certificate=true, Client(const std::string& server_port_path, bool verify_certificate=true,
const std::string& cert_file=std::string(), const std::string& private_key_file=std::string(), const std::string& cert_file=std::string(), const std::string& private_key_file=std::string(),
const std::string& verify_file=std::string()) : const std::string& verify_file=std::string()) :
ClientBase<HTTPS>::ClientBase(server_port_path, 443), context(asio_ns::ssl::context::tlsv12) { ClientBase<HTTPS>::ClientBase(server_port_path, 443), context(asio::ssl::context::tlsv12) {
if(cert_file.size()>0 && private_key_file.size()>0) { if(cert_file.size()>0 && private_key_file.size()>0) {
context.use_certificate_chain_file(cert_file); context.use_certificate_chain_file(cert_file);
context.use_private_key_file(private_key_file, asio_ns::ssl::context::pem); context.use_private_key_file(private_key_file, asio::ssl::context::pem);
} }
if(verify_certificate) if(verify_certificate)
context.set_verify_callback(asio_ns::ssl::rfc2818_verification(host)); context.set_verify_callback(asio::ssl::rfc2818_verification(host));
if(verify_file.size()>0) if(verify_file.size()>0)
context.load_verify_file(verify_file); context.load_verify_file(verify_file);
@ -28,25 +33,25 @@ namespace SimpleWeb {
context.set_default_verify_paths(); context.set_default_verify_paths();
if(verify_file.size()>0 || verify_certificate) if(verify_file.size()>0 || verify_certificate)
context.set_verify_mode(asio_ns::ssl::verify_peer); context.set_verify_mode(asio::ssl::verify_peer);
else else
context.set_verify_mode(asio_ns::ssl::verify_none); context.set_verify_mode(asio::ssl::verify_none);
} }
protected: protected:
asio_ns::ssl::context context; asio::ssl::context context;
void connect() { void connect() {
if(!socket || !socket->lowest_layer().is_open()) { if(!socket || !socket->lowest_layer().is_open()) {
std::unique_ptr<asio_ns::ip::tcp::resolver::query> query; std::unique_ptr<asio::ip::tcp::resolver::query> query;
if(config.proxy_server.empty()) if(config.proxy_server.empty())
query=std::unique_ptr<asio_ns::ip::tcp::resolver::query>(new asio_ns::ip::tcp::resolver::query(host, std::to_string(port))); query=std::unique_ptr<asio::ip::tcp::resolver::query>(new asio::ip::tcp::resolver::query(host, std::to_string(port)));
else { else {
auto proxy_host_port=parse_host_port(config.proxy_server, 8080); auto proxy_host_port=parse_host_port(config.proxy_server, 8080);
query=std::unique_ptr<asio_ns::ip::tcp::resolver::query>(new asio_ns::ip::tcp::resolver::query(proxy_host_port.first, std::to_string(proxy_host_port.second))); query=std::unique_ptr<asio::ip::tcp::resolver::query>(new asio::ip::tcp::resolver::query(proxy_host_port.first, std::to_string(proxy_host_port.second)));
} }
resolver.async_resolve(*query, [this] resolver.async_resolve(*query, [this]
(const error_ns::error_code &ec, asio_ns::ip::tcp::resolver::iterator it){ (const error_code &ec, asio::ip::tcp::resolver::iterator it){
if(!ec) { if(!ec) {
{ {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
@ -54,44 +59,44 @@ namespace SimpleWeb {
} }
auto timer=get_timeout_timer(config.timeout_connect); auto timer=get_timeout_timer(config.timeout_connect);
asio_ns::async_connect(socket->lowest_layer(), it, [this, timer] asio::async_connect(socket->lowest_layer(), it, [this, timer]
(const error_ns::error_code &ec, asio_ns::ip::tcp::resolver::iterator /*it*/){ (const error_code &ec, asio::ip::tcp::resolver::iterator /*it*/){
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(!ec) { if(!ec) {
asio_ns::ip::tcp::no_delay option(true); asio::ip::tcp::no_delay option(true);
this->socket->lowest_layer().set_option(option); this->socket->lowest_layer().set_option(option);
} }
else { else {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
this->socket=nullptr; this->socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
} }
else { else {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
socket=nullptr; socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
io_service.reset(); io_service.reset();
io_service.run(); io_service.run();
if(!config.proxy_server.empty()) { if(!config.proxy_server.empty()) {
asio_ns::streambuf write_buffer; asio::streambuf write_buffer;
std::ostream write_stream(&write_buffer); std::ostream write_stream(&write_buffer);
auto host_port=host+':'+std::to_string(port); auto host_port=host+':'+std::to_string(port);
write_stream << "CONNECT "+host_port+" HTTP/1.1\r\n" << "Host: " << host_port << "\r\n\r\n"; write_stream << "CONNECT "+host_port+" HTTP/1.1\r\n" << "Host: " << host_port << "\r\n\r\n";
auto timer=get_timeout_timer(); auto timer=get_timeout_timer();
asio_ns::async_write(socket->next_layer(), write_buffer, asio::async_write(socket->next_layer(), write_buffer,
[this, timer](const error_ns::error_code &ec, size_t /*bytes_transferred*/) { [this, timer](const error_code &ec, size_t /*bytes_transferred*/) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(ec) { if(ec) {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
socket=nullptr; socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
io_service.reset(); io_service.reset();
@ -99,14 +104,14 @@ namespace SimpleWeb {
std::shared_ptr<Response> response(new Response()); std::shared_ptr<Response> response(new Response());
timer=get_timeout_timer(); timer=get_timeout_timer();
asio_ns::async_read_until(socket->next_layer(), response->content_buffer, "\r\n\r\n", asio::async_read_until(socket->next_layer(), response->content_buffer, "\r\n\r\n",
[this, timer](const error_ns::error_code& ec, size_t /*bytes_transferred*/) { [this, timer](const error_code& ec, size_t /*bytes_transferred*/) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(ec) { if(ec) {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
socket=nullptr; socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
io_service.reset(); io_service.reset();
@ -115,19 +120,19 @@ namespace SimpleWeb {
if (response->status_code.empty() || response->status_code.compare(0, 3, "200") != 0) { if (response->status_code.empty() || response->status_code.compare(0, 3, "200") != 0) {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
socket=nullptr; socket=nullptr;
throw merror_ns::make_error_code(error_ns::errc::permission_denied); throw make_error_code(errc::permission_denied);
} }
} }
auto timer=get_timeout_timer(); auto timer=get_timeout_timer();
this->socket->async_handshake(asio_ns::ssl::stream_base::client, this->socket->async_handshake(asio::ssl::stream_base::client,
[this, timer](const error_ns::error_code& ec) { [this, timer](const error_code& ec) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(ec) { if(ec) {
std::lock_guard<std::mutex> lock(socket_mutex); std::lock_guard<std::mutex> lock(socket_mutex);
socket=nullptr; socket=nullptr;
throw error_ns::system_error(ec); throw system_error(ec);
} }
}); });
io_service.reset(); io_service.reset();

View file

@ -196,7 +196,7 @@ void default_resource_send(const HttpServer &server, const shared_ptr<HttpServer
if((read_length=ifs->read(&buffer[0], buffer.size()).gcount())>0) { if((read_length=ifs->read(&buffer[0], buffer.size()).gcount())>0) {
response->write(&buffer[0], read_length); response->write(&buffer[0], read_length);
if(read_length==static_cast<streamsize>(buffer.size())) { if(read_length==static_cast<streamsize>(buffer.size())) {
server.send(response, [&server, response, ifs](const error_ns::error_code &ec) { server.send(response, [&server, response, ifs](const SimpleWeb::error_code &ec) {
if(!ec) if(!ec)
default_resource_send(server, response, ifs); default_resource_send(server, response, ifs);
else else

View file

@ -193,7 +193,7 @@ void default_resource_send(const HttpsServer &server, const shared_ptr<HttpsServ
if((read_length=ifs->read(&buffer[0], buffer.size()).gcount())>0) { if((read_length=ifs->read(&buffer[0], buffer.size()).gcount())>0) {
response->write(&buffer[0], read_length); response->write(&buffer[0], read_length);
if(read_length==static_cast<streamsize>(buffer.size())) { if(read_length==static_cast<streamsize>(buffer.size())) {
server.send(response, [&server, response, ifs](const error_ns::error_code &ec) { server.send(response, [&server, response, ifs](const SimpleWeb::error_code &ec) {
if(!ec) if(!ec)
default_resource_send(server, response, ifs); default_resource_send(server, response, ifs);
else else

View file

@ -8,83 +8,66 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#ifdef NO_BOOST #ifdef USE_STANDALONE_ASIO
#include <asio.hpp> #include <asio.hpp>
#include <type_traits> #include <type_traits>
#include <system_error> namespace SimpleWeb {
namespace asio_ns = asio; using error_code = std::error_code;
namespace error_ns = std; using errc = std::errc;
namespace merror_ns = std; error_code (&make_error_code)(errc) = std::make_error_code;
# ifndef CASE_INSENSITIVE_EQUALS_AND_HASH
# define CASE_INSENSITIVE_EQUALS_AND_HASH
class case_insensitive_equals {
public:
bool operator()(const std::string &Left, const std::string &Right) const {
return Left.size() == Right.size()
&& std::equal ( Left.begin() , Left.end() , Right.begin() ,
[]( char a , char b ) {
return tolower(a) == tolower(b);
});
} }
};
bool IEQUALS(const std::string& Left, const std::string& Right)
{
return Left.size() == Right.size()
&& std::equal ( Left.begin() , Left.end() , Right.begin() , []( char a , char b ) {
return tolower(a) == tolower(b);
});
}
class case_insensitive_hash {
public:
size_t operator()(const std::string& Keyval) const
{
//You might need a better hash function than this
size_t h = 0;
std::for_each( Keyval.begin() , Keyval.end() , [&](char c ) {
h += tolower(c);
});
return h;
}
};
# endif
#else #else
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
namespace asio_ns = boost::asio; namespace SimpleWeb {
namespace error_ns = boost::system; namespace asio = boost::asio;
namespace merror_ns = boost::system::errc; using error_code = boost::system::error_code;
namespace errc = boost::system::errc;
error_code (&make_error_code)(boost::system::errc::errc_t) = boost::system::errc::make_error_code;
}
#endif
# ifndef CASE_INSENSITIVE_EQUALS_AND_HASH # ifndef CASE_INSENSITIVE_EQUALS_AND_HASH
# define CASE_INSENSITIVE_EQUALS_AND_HASH # define CASE_INSENSITIVE_EQUALS_AND_HASH
# define IEQUALS boost::iequals namespace SimpleWeb {
//Based on http://www.boost.org/doc/libs/1_60_0/doc/html/unordered/hash_equality.html bool iequals(const std::string &str1, const std::string &str2) {
return str1.size() == str2.size() &&
std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) {
return tolower(a) == tolower(b);
});
}
class case_insensitive_equals { class case_insensitive_equals {
public: public:
bool operator()(const std::string &key1, const std::string &key2) const { bool operator()(const std::string &str1, const std::string &str2) const {
return boost::algorithm::iequals(key1, key2); return iequals(str1, str2);
} }
}; };
// Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226
class case_insensitive_hash { class case_insensitive_hash {
public: public:
size_t operator()(const std::string &key) const { size_t operator()(const std::string &str) const {
std::size_t seed=0; size_t h = 0;
for(auto &c: key) std::hash<int> hash;
boost::hash_combine(seed, std::tolower(c)); for (auto c : str)
return seed; h ^= hash(tolower(c)) + 0x9e3779b9 + (h << 6) + (h >> 2);
return h;
} }
}; };
}
# endif # endif
#endif
// Late 2017 TODO: remove the following checks and always use std::regex // Late 2017 TODO: remove the following checks and always use std::regex
#ifdef USE_BOOST_REGEX #ifdef USE_BOOST_REGEX
#include <boost/regex.hpp> #include <boost/regex.hpp>
namespace regex_ns = boost; namespace SimpleWeb {
namespace regex = boost;
}
#else #else
#include <regex> #include <regex>
namespace regex_ns = std; namespace SimpleWeb {
namespace regex = std;
}
#endif #endif
// TODO when switching to c++14, use [[deprecated]] instead // TODO when switching to c++14, use [[deprecated]] instead
@ -110,7 +93,7 @@ namespace SimpleWeb {
class Response : public std::ostream { class Response : public std::ostream {
friend class ServerBase<socket_type>; friend class ServerBase<socket_type>;
asio_ns::streambuf streambuf; asio::streambuf streambuf;
std::shared_ptr<socket_type> socket; std::shared_ptr<socket_type> socket;
@ -140,8 +123,8 @@ namespace SimpleWeb {
return ss.str(); return ss.str();
} }
private: private:
asio_ns::streambuf &streambuf; asio::streambuf &streambuf;
Content(asio_ns::streambuf &streambuf): std::istream(&streambuf), streambuf(streambuf) {} Content(asio::streambuf &streambuf): std::istream(&streambuf), streambuf(streambuf) {}
}; };
class Request { class Request {
@ -154,7 +137,7 @@ namespace SimpleWeb {
std::unordered_multimap<std::string, std::string, case_insensitive_hash, case_insensitive_equals> header; std::unordered_multimap<std::string, std::string, case_insensitive_hash, case_insensitive_equals> header;
regex_ns::smatch path_match; regex::smatch path_match;
std::string remote_endpoint_address; std::string remote_endpoint_address;
unsigned short remote_endpoint_port; unsigned short remote_endpoint_port;
@ -165,10 +148,10 @@ namespace SimpleWeb {
auto qs_start_pos = path.find('?'); auto qs_start_pos = path.find('?');
if (qs_start_pos != std::string::npos && qs_start_pos + 1 < path.size()) { if (qs_start_pos != std::string::npos && qs_start_pos + 1 < path.size()) {
++qs_start_pos; ++qs_start_pos;
static regex_ns::regex pattern("([\\w+%]+)=?([^&]*)"); static regex::regex pattern("([\\w+%]+)=?([^&]*)");
int submatches[] = {1, 2}; int submatches[] = {1, 2};
auto it_begin = regex_ns::sregex_token_iterator(path.begin() + qs_start_pos, path.end(), pattern, submatches); auto it_begin = regex::sregex_token_iterator(path.begin() + qs_start_pos, path.end(), pattern, submatches);
auto it_end = regex_ns::sregex_token_iterator(); auto it_end = regex::sregex_token_iterator();
for (auto it = it_begin; it != it_end; ++it) { for (auto it = it_begin; it != it_end; ++it) {
auto submatch1=it->str(); auto submatch1=it->str();
auto submatch2=(++it)->str(); auto submatch2=(++it)->str();
@ -197,7 +180,7 @@ namespace SimpleWeb {
catch(...) {} catch(...) {}
} }
asio_ns::streambuf streambuf; asio::streambuf streambuf;
}; };
class Config { class Config {
@ -223,11 +206,11 @@ namespace SimpleWeb {
Config config; Config config;
private: private:
class regex_orderable : public regex_ns::regex { class regex_orderable : public regex::regex {
std::string str; std::string str;
public: public:
regex_orderable(const char *regex_cstr) : regex_ns::regex(regex_cstr), str(regex_cstr) {} regex_orderable(const char *regex_cstr) : regex::regex(regex_cstr), str(regex_cstr) {}
regex_orderable(const std::string &regex_str) : regex_ns::regex(regex_str), str(regex_str) {} regex_orderable(const std::string &regex_str) : regex::regex(regex_str), str(regex_str) {}
bool operator<(const regex_orderable &rhs) const { bool operator<(const regex_orderable &rhs) const {
return str<rhs.str; return str<rhs.str;
} }
@ -240,27 +223,27 @@ namespace SimpleWeb {
std::map<std::string, std::map<std::string,
std::function<void(std::shared_ptr<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;
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Request>, const error_ns::error_code&)> on_error; std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Request>, const error_code&)> on_error;
std::function<void(std::shared_ptr<socket_type> socket, std::shared_ptr<typename ServerBase<socket_type>::Request>)> on_upgrade; std::function<void(std::shared_ptr<socket_type> socket, std::shared_ptr<typename ServerBase<socket_type>::Request>)> on_upgrade;
virtual void start() { virtual void start() {
if(!io_service) if(!io_service)
io_service=std::make_shared<asio_ns::io_service>(); io_service=std::make_shared<asio::io_service>();
if(io_service->stopped()) if(io_service->stopped())
io_service->reset(); io_service->reset();
asio_ns::ip::tcp::endpoint endpoint; asio::ip::tcp::endpoint endpoint;
if(config.address.size()>0) if(config.address.size()>0)
endpoint=asio_ns::ip::tcp::endpoint(asio_ns::ip::address::from_string(config.address), config.port); endpoint=asio::ip::tcp::endpoint(asio::ip::address::from_string(config.address), config.port);
else else
endpoint=asio_ns::ip::tcp::endpoint(asio_ns::ip::tcp::v4(), config.port); endpoint=asio::ip::tcp::endpoint(asio::ip::tcp::v4(), config.port);
if(!acceptor) if(!acceptor)
acceptor=std::unique_ptr<asio_ns::ip::tcp::acceptor>(new asio_ns::ip::tcp::acceptor(*io_service)); acceptor=std::unique_ptr<asio::ip::tcp::acceptor>(new asio::ip::tcp::acceptor(*io_service));
acceptor->open(endpoint.protocol()); acceptor->open(endpoint.protocol());
acceptor->set_option(asio_ns::socket_base::reuse_address(config.reuse_address)); acceptor->set_option(asio::socket_base::reuse_address(config.reuse_address));
acceptor->bind(endpoint); acceptor->bind(endpoint);
acceptor->listen(); acceptor->listen();
@ -291,34 +274,34 @@ namespace SimpleWeb {
} }
///Use this function if you need to recursively send parts of a longer message ///Use this function if you need to recursively send parts of a longer message
void send(const std::shared_ptr<Response> &response, const std::function<void(const error_ns::error_code&)>& callback=nullptr) const { void send(const std::shared_ptr<Response> &response, const std::function<void(const error_code&)>& callback=nullptr) const {
asio_ns::async_write(*response->socket, response->streambuf, [this, response, callback](const error_ns::error_code& ec, size_t /*bytes_transferred*/) { asio::async_write(*response->socket, response->streambuf, [this, response, callback](const error_code& ec, size_t /*bytes_transferred*/) {
if(callback) if(callback)
callback(ec); callback(ec);
}); });
} }
/// If you have your own asio_ns::io_service, store its pointer here before running start(). /// If you have your own asio::io_service, store its pointer here before running start().
/// You might also want to set config.thread_pool_size to 0. /// You might also want to set config.thread_pool_size to 0.
std::shared_ptr<asio_ns::io_service> io_service; std::shared_ptr<asio::io_service> io_service;
protected: protected:
std::unique_ptr<asio_ns::ip::tcp::acceptor> acceptor; std::unique_ptr<asio::ip::tcp::acceptor> acceptor;
std::vector<std::thread> threads; std::vector<std::thread> threads;
ServerBase(unsigned short port) : config(port) {} ServerBase(unsigned short port) : config(port) {}
virtual void accept()=0; virtual void accept()=0;
std::shared_ptr<asio_ns::deadline_timer> get_timeout_timer(const std::shared_ptr<socket_type> &socket, long seconds) { std::shared_ptr<asio::deadline_timer> get_timeout_timer(const std::shared_ptr<socket_type> &socket, long seconds) {
if(seconds==0) if(seconds==0)
return nullptr; return nullptr;
auto timer=std::make_shared<asio_ns::deadline_timer>(*io_service); auto timer=std::make_shared<asio::deadline_timer>(*io_service);
timer->expires_from_now(boost::posix_time::seconds(seconds)); timer->expires_from_now(boost::posix_time::seconds(seconds));
timer->async_wait([socket](const error_ns::error_code& ec){ timer->async_wait([socket](const error_code& ec){
if(!ec) { if(!ec) {
error_ns::error_code ec; error_code ec;
socket->lowest_layer().shutdown(asio_ns::ip::tcp::socket::shutdown_both, ec); socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec);
socket->lowest_layer().close(); socket->lowest_layer().close();
} }
}); });
@ -330,11 +313,11 @@ namespace SimpleWeb {
//shared_ptr is used to pass temporary objects to the asynchronous functions //shared_ptr is used to pass temporary objects to the asynchronous functions
std::shared_ptr<Request> request(new Request(*socket)); std::shared_ptr<Request> request(new Request(*socket));
//Set timeout on the following asio_ns::async-read or write function //Set timeout on the following asio::async-read or write function
auto timer=this->get_timeout_timer(socket, config.timeout_request); auto timer=this->get_timeout_timer(socket, config.timeout_request);
asio_ns::async_read_until(*socket, request->streambuf, "\r\n\r\n", asio::async_read_until(*socket, request->streambuf, "\r\n\r\n",
[this, socket, request, timer](const error_ns::error_code& ec, size_t bytes_transferred) { [this, socket, request, timer](const error_code& ec, size_t bytes_transferred) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(!ec) { if(!ec) {
@ -356,16 +339,16 @@ namespace SimpleWeb {
} }
catch(const std::exception &e) { catch(const std::exception &e) {
if(on_error) if(on_error)
on_error(request, merror_ns::make_error_code(error_ns::errc::protocol_error)); on_error(request, make_error_code(errc::protocol_error));
return; return;
} }
if(content_length>num_additional_bytes) { if(content_length>num_additional_bytes) {
//Set timeout on the following asio_ns::async-read or write function //Set timeout on the following asio::async-read or write function
auto timer=this->get_timeout_timer(socket, config.timeout_content); auto timer=this->get_timeout_timer(socket, config.timeout_content);
asio_ns::async_read(*socket, request->streambuf, asio::async_read(*socket, request->streambuf,
asio_ns::transfer_exactly(content_length-num_additional_bytes), asio::transfer_exactly(content_length-num_additional_bytes),
[this, socket, request, timer] [this, socket, request, timer]
(const error_ns::error_code& ec, size_t /*bytes_transferred*/) { (const error_code& ec, size_t /*bytes_transferred*/) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(!ec) if(!ec)
@ -439,8 +422,8 @@ namespace SimpleWeb {
for(auto &regex_method: resource) { for(auto &regex_method: resource) {
auto it=regex_method.second.find(request->method); auto it=regex_method.second.find(request->method);
if(it!=regex_method.second.end()) { if(it!=regex_method.second.end()) {
regex_ns::smatch sm_res; regex::smatch sm_res;
if(regex_ns::regex_match(request->path, sm_res, regex_method.first)) { if(regex::regex_match(request->path, sm_res, regex_method.first)) {
request->path_match=std::move(sm_res); request->path_match=std::move(sm_res);
write_response(socket, request, it->second); write_response(socket, request, it->second);
return; return;
@ -456,12 +439,12 @@ namespace SimpleWeb {
void write_response(const std::shared_ptr<socket_type> &socket, const std::shared_ptr<Request> &request, void write_response(const std::shared_ptr<socket_type> &socket, const std::shared_ptr<Request> &request,
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>,
std::shared_ptr<typename ServerBase<socket_type>::Request>)>& resource_function) { std::shared_ptr<typename ServerBase<socket_type>::Request>)>& resource_function) {
//Set timeout on the following asio_ns::async-read or write function //Set timeout on the following asio::async-read or write function
auto timer=this->get_timeout_timer(socket, config.timeout_content); auto timer=this->get_timeout_timer(socket, config.timeout_content);
auto response=std::shared_ptr<Response>(new Response(socket), [this, request, timer](Response *response_ptr) { auto response=std::shared_ptr<Response>(new Response(socket), [this, request, timer](Response *response_ptr) {
auto response=std::shared_ptr<Response>(response_ptr); auto response=std::shared_ptr<Response>(response_ptr);
this->send(response, [this, response, request, timer](const error_ns::error_code& ec) { this->send(response, [this, response, request, timer](const error_code& ec) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(!ec) { if(!ec) {
@ -470,9 +453,9 @@ namespace SimpleWeb {
auto range=request->header.equal_range("Connection"); auto range=request->header.equal_range("Connection");
for(auto it=range.first;it!=range.second;it++) { for(auto it=range.first;it!=range.second;it++) {
if(IEQUALS(it->second, "close")) { if(iequals(it->second, "close")) {
return; return;
} else if (IEQUALS(it->second, "keep-alive")) { } else if (iequals(it->second, "keep-alive")) {
this->read_request_and_content(response->socket); this->read_request_and_content(response->socket);
return; return;
} }
@ -490,7 +473,7 @@ namespace SimpleWeb {
} }
catch(const std::exception &e) { catch(const std::exception &e) {
if(on_error) if(on_error)
on_error(request, merror_ns::make_error_code(error_ns::errc::operation_canceled)); on_error(request, make_error_code(errc::operation_canceled));
return; return;
} }
} }
@ -499,7 +482,7 @@ namespace SimpleWeb {
template<class socket_type> template<class socket_type>
class Server : public ServerBase<socket_type> {}; class Server : public ServerBase<socket_type> {};
typedef asio_ns::ip::tcp::socket HTTP; typedef asio::ip::tcp::socket HTTP;
template<> template<>
class Server<HTTP> : public ServerBase<HTTP> { class Server<HTTP> : public ServerBase<HTTP> {
@ -520,13 +503,13 @@ namespace SimpleWeb {
//Shared_ptr is used to pass temporary objects to the asynchronous functions //Shared_ptr is used to pass temporary objects to the asynchronous functions
auto socket=std::make_shared<HTTP>(*io_service); auto socket=std::make_shared<HTTP>(*io_service);
acceptor->async_accept(*socket, [this, socket](const error_ns::error_code& ec){ acceptor->async_accept(*socket, [this, socket](const error_code& ec){
//Immediately start accepting a new connection (if io_service hasn't been stopped) //Immediately start accepting a new connection (if io_service hasn't been stopped)
if (ec != asio_ns::error::operation_aborted) if (ec != asio::error::operation_aborted)
accept(); accept();
if(!ec) { if(!ec) {
asio_ns::ip::tcp::no_delay option(true); asio::ip::tcp::no_delay option(true);
socket->set_option(option); socket->set_option(option);
this->read_request_and_content(socket); this->read_request_and_content(socket);

View file

@ -2,16 +2,18 @@
#define SERVER_HTTPS_HPP #define SERVER_HTTPS_HPP
#include "server_http.hpp" #include "server_http.hpp"
#ifdef NO_BOOST
#ifdef USE_STANDALONE_ASIO
#include <asio/ssl.hpp> #include <asio/ssl.hpp>
#else #else
#include <boost/asio/ssl.hpp> #include <boost/asio/ssl.hpp>
#endif #endif
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <algorithm> #include <algorithm>
namespace SimpleWeb { namespace SimpleWeb {
typedef asio_ns::ssl::stream<asio_ns::ip::tcp::socket> HTTPS; typedef asio::ssl::stream<asio::ip::tcp::socket> HTTPS;
template<> template<>
class Server<HTTPS> : public ServerBase<HTTPS> { class Server<HTTPS> : public ServerBase<HTTPS> {
@ -29,14 +31,14 @@ namespace SimpleWeb {
} }
Server(const std::string& cert_file, const std::string& private_key_file, const std::string& verify_file=std::string()): Server(const std::string& cert_file, const std::string& private_key_file, const std::string& verify_file=std::string()):
ServerBase<HTTPS>::ServerBase(443), context(asio_ns::ssl::context::tlsv12) { ServerBase<HTTPS>::ServerBase(443), context(asio::ssl::context::tlsv12) {
context.use_certificate_chain_file(cert_file); context.use_certificate_chain_file(cert_file);
context.use_private_key_file(private_key_file, asio_ns::ssl::context::pem); context.use_private_key_file(private_key_file, asio::ssl::context::pem);
if(verify_file.size()>0) { if(verify_file.size()>0) {
context.load_verify_file(verify_file); context.load_verify_file(verify_file);
context.set_verify_mode(asio_ns::ssl::verify_peer | asio_ns::ssl::verify_fail_if_no_peer_cert | context.set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert |
asio_ns::ssl::verify_client_once); asio::ssl::verify_client_once);
set_session_id_context=true; set_session_id_context=true;
} }
} }
@ -53,27 +55,27 @@ namespace SimpleWeb {
} }
protected: protected:
asio_ns::ssl::context context; asio::ssl::context context;
void accept() { void accept() {
//Create new socket for this connection //Create new socket for this connection
//Shared_ptr is used to pass temporary objects to the asynchronous functions //Shared_ptr is used to pass temporary objects to the asynchronous functions
auto socket=std::make_shared<HTTPS>(*io_service, context); auto socket=std::make_shared<HTTPS>(*io_service, context);
acceptor->async_accept((*socket).lowest_layer(), [this, socket](const error_ns::error_code& ec) { acceptor->async_accept((*socket).lowest_layer(), [this, socket](const error_code& ec) {
//Immediately start accepting a new connection (if io_service hasn't been stopped) //Immediately start accepting a new connection (if io_service hasn't been stopped)
if (ec != asio_ns::error::operation_aborted) if (ec != asio::error::operation_aborted)
accept(); accept();
if(!ec) { if(!ec) {
asio_ns::ip::tcp::no_delay option(true); asio::ip::tcp::no_delay option(true);
socket->lowest_layer().set_option(option); socket->lowest_layer().set_option(option);
//Set timeout on the following asio_ns::ssl::stream::async_handshake //Set timeout on the following asio::ssl::stream::async_handshake
auto timer=get_timeout_timer(socket, config.timeout_request); auto timer=get_timeout_timer(socket, config.timeout_request);
socket->async_handshake(asio_ns::ssl::stream_base::server, [this, socket, timer] socket->async_handshake(asio::ssl::stream_base::server, [this, socket, timer]
(const error_ns::error_code& ec) { (const error_code& ec) {
if(timer) if(timer)
timer->cancel(); timer->cancel();
if(!ec) if(!ec)

View file

@ -106,7 +106,7 @@ public:
int main() { int main() {
ServerTest serverTest; ServerTest serverTest;
serverTest.io_service=std::make_shared<boost::asio::io_service>(); serverTest.io_service=std::make_shared<asio::io_service>();
serverTest.parse_request_test(); serverTest.parse_request_test();
@ -119,8 +119,8 @@ int main() {
clientTest2.parse_response_header_test(); clientTest2.parse_response_header_test();
boost::asio::io_service io_service; asio::io_service io_service;
boost::asio::ip::tcp::socket socket(io_service); asio::ip::tcp::socket socket(io_service);
SimpleWeb::Server<HTTP>::Request request(socket); SimpleWeb::Server<HTTP>::Request request(socket);
{ {
request.path = "/?"; request.path = "/?";