Added noexcept
This commit is contained in:
parent
3ba494e0ac
commit
7dd2d2108a
8 changed files with 122 additions and 112 deletions
|
|
@ -40,19 +40,24 @@ namespace SimpleWeb {
|
|||
friend class ClientBase<socket_type>;
|
||||
|
||||
public:
|
||||
size_t size() {
|
||||
size_t size() noexcept {
|
||||
return streambuf.size();
|
||||
}
|
||||
/// Convenience function to return std::string. Note that the stream buffer is emptied when this functions is used.
|
||||
std::string string() {
|
||||
std::stringstream ss;
|
||||
ss << rdbuf();
|
||||
return ss.str();
|
||||
std::string string() noexcept {
|
||||
try {
|
||||
std::stringstream ss;
|
||||
ss << rdbuf();
|
||||
return ss.str();
|
||||
}
|
||||
catch(...) {
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
asio::streambuf &streambuf;
|
||||
Content(asio::streambuf &streambuf) : std::istream(&streambuf), streambuf(streambuf) {}
|
||||
Content(asio::streambuf &streambuf) noexcept : std::istream(&streambuf), streambuf(streambuf) {}
|
||||
};
|
||||
|
||||
class Response {
|
||||
|
|
@ -69,14 +74,14 @@ namespace SimpleWeb {
|
|||
private:
|
||||
asio::streambuf content_buffer;
|
||||
|
||||
Response() : content(content_buffer) {}
|
||||
Response() noexcept : content(content_buffer) {}
|
||||
};
|
||||
|
||||
class Config {
|
||||
friend class ClientBase<socket_type>;
|
||||
|
||||
private:
|
||||
Config() {}
|
||||
Config() noexcept {}
|
||||
|
||||
public:
|
||||
/// Set timeout on requests in seconds. Default value: 0 (no timeout).
|
||||
|
|
@ -91,7 +96,7 @@ namespace SimpleWeb {
|
|||
class Connection : public std::enable_shared_from_this<Connection> {
|
||||
public:
|
||||
template <typename... Args>
|
||||
Connection(std::shared_ptr<ScopeRunner> handler_runner, long timeout, Args &&... args)
|
||||
Connection(std::shared_ptr<ScopeRunner> handler_runner, long timeout, Args &&... args) noexcept
|
||||
: handler_runner(std::move(handler_runner)), timeout(timeout), socket(new socket_type(std::forward<Args>(args)...)) {}
|
||||
|
||||
std::shared_ptr<ScopeRunner> handler_runner;
|
||||
|
|
@ -103,7 +108,7 @@ namespace SimpleWeb {
|
|||
|
||||
std::unique_ptr<asio::deadline_timer> timer;
|
||||
|
||||
void set_timeout(long seconds = 0) {
|
||||
void set_timeout(long seconds = 0) noexcept {
|
||||
if(seconds == 0)
|
||||
seconds = timeout;
|
||||
if(seconds == 0) {
|
||||
|
|
@ -121,7 +126,7 @@ namespace SimpleWeb {
|
|||
});
|
||||
}
|
||||
|
||||
void cancel_timeout() {
|
||||
void cancel_timeout() noexcept {
|
||||
if(timer)
|
||||
timer->cancel();
|
||||
}
|
||||
|
|
@ -129,7 +134,7 @@ namespace SimpleWeb {
|
|||
|
||||
class Session {
|
||||
public:
|
||||
Session(std::shared_ptr<Connection> connection, std::unique_ptr<asio::streambuf> request_buffer)
|
||||
Session(std::shared_ptr<Connection> connection, std::unique_ptr<asio::streambuf> request_buffer) noexcept
|
||||
: connection(std::move(connection)), request_buffer(std::move(request_buffer)), response(new Response()) {}
|
||||
|
||||
std::shared_ptr<Connection> connection;
|
||||
|
|
@ -209,7 +214,7 @@ namespace SimpleWeb {
|
|||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||
/// Do not use concurrently with the synchronous request functions.
|
||||
void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap &header,
|
||||
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) {
|
||||
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) noexcept {
|
||||
auto session = std::make_shared<Session>(get_connection(), create_request_header(method, path, header));
|
||||
auto response = session->response;
|
||||
auto request_callback = std::make_shared<std::function<void(std::shared_ptr<Response>, const error_code &)>>(std::move(request_callback_));
|
||||
|
|
@ -251,24 +256,24 @@ namespace SimpleWeb {
|
|||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||
/// Do not use concurrently with the synchronous request functions.
|
||||
void request(const std::string &method, const std::string &path, string_view content,
|
||||
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
|
||||
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) noexcept {
|
||||
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback));
|
||||
}
|
||||
|
||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||
void request(const std::string &method, const std::string &path,
|
||||
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
|
||||
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) noexcept {
|
||||
request(method, path, std::string(), CaseInsensitiveMultimap(), std::move(request_callback));
|
||||
}
|
||||
|
||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||
void request(const std::string &method, std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
|
||||
void request(const std::string &method, std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) noexcept {
|
||||
request(method, std::string("/"), std::string(), CaseInsensitiveMultimap(), std::move(request_callback));
|
||||
}
|
||||
|
||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||
void request(const std::string &method, const std::string &path, std::istream &content, const CaseInsensitiveMultimap &header,
|
||||
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) {
|
||||
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) noexcept {
|
||||
auto session = std::make_shared<Session>(get_connection(), create_request_header(method, path, header));
|
||||
auto response = session->response;
|
||||
auto request_callback = std::make_shared<std::function<void(std::shared_ptr<Response>, const error_code &)>>(std::move(request_callback_));
|
||||
|
|
@ -313,12 +318,12 @@ namespace SimpleWeb {
|
|||
|
||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||
void request(const std::string &method, const std::string &path, std::istream &content,
|
||||
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
|
||||
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) noexcept {
|
||||
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback));
|
||||
}
|
||||
|
||||
/// Close connections
|
||||
void stop() {
|
||||
void stop() noexcept {
|
||||
std::unique_lock<std::mutex> lock(connections_mutex);
|
||||
for(auto it = connections.begin(); it != connections.end();) {
|
||||
error_code ec;
|
||||
|
|
@ -327,7 +332,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
}
|
||||
|
||||
virtual ~ClientBase() {
|
||||
virtual ~ClientBase() noexcept {
|
||||
handler_runner->stop();
|
||||
stop();
|
||||
}
|
||||
|
|
@ -348,13 +353,13 @@ namespace SimpleWeb {
|
|||
size_t concurrent_synchronous_requests = 0;
|
||||
std::mutex concurrent_synchronous_requests_mutex;
|
||||
|
||||
ClientBase(const std::string &host_port, unsigned short default_port) : handler_runner(new ScopeRunner()) {
|
||||
ClientBase(const std::string &host_port, unsigned short default_port) noexcept : handler_runner(new ScopeRunner()) {
|
||||
auto parsed_host_port = parse_host_port(host_port, default_port);
|
||||
host = parsed_host_port.first;
|
||||
port = parsed_host_port.second;
|
||||
}
|
||||
|
||||
std::shared_ptr<Connection> get_connection() {
|
||||
std::shared_ptr<Connection> get_connection() noexcept {
|
||||
std::shared_ptr<Connection> connection;
|
||||
std::unique_lock<std::mutex> lock(connections_mutex);
|
||||
|
||||
|
|
@ -388,10 +393,10 @@ namespace SimpleWeb {
|
|||
return connection;
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<Connection> create_connection() = 0;
|
||||
virtual void connect(const std::shared_ptr<Session> &) = 0;
|
||||
virtual std::shared_ptr<Connection> create_connection() noexcept = 0;
|
||||
virtual void connect(const std::shared_ptr<Session> &) noexcept = 0;
|
||||
|
||||
std::unique_ptr<asio::streambuf> create_request_header(const std::string &method, const std::string &path, const CaseInsensitiveMultimap &header) const {
|
||||
std::unique_ptr<asio::streambuf> create_request_header(const std::string &method, const std::string &path, const CaseInsensitiveMultimap &header) const noexcept {
|
||||
auto corrected_path = path;
|
||||
if(corrected_path == "")
|
||||
corrected_path = "/";
|
||||
|
|
@ -407,7 +412,7 @@ namespace SimpleWeb {
|
|||
return request_buffer;
|
||||
}
|
||||
|
||||
std::pair<std::string, unsigned short> parse_host_port(const std::string &host_port, unsigned short default_port) const {
|
||||
std::pair<std::string, unsigned short> parse_host_port(const std::string &host_port, unsigned short default_port) const noexcept {
|
||||
std::pair<std::string, unsigned short> parsed_host_port;
|
||||
size_t host_end = host_port.find(':');
|
||||
if(host_end == std::string::npos) {
|
||||
|
|
@ -421,7 +426,7 @@ namespace SimpleWeb {
|
|||
return parsed_host_port;
|
||||
}
|
||||
|
||||
void write(const std::shared_ptr<Session> &session) {
|
||||
void write(const std::shared_ptr<Session> &session) noexcept {
|
||||
session->connection->set_timeout();
|
||||
asio::async_write(*session->connection->socket, session->request_buffer->data(), [this, session](const error_code &ec, size_t /*bytes_transferred*/) {
|
||||
session->connection->cancel_timeout();
|
||||
|
|
@ -435,7 +440,7 @@ namespace SimpleWeb {
|
|||
});
|
||||
}
|
||||
|
||||
void read(const std::shared_ptr<Session> &session) {
|
||||
void read(const std::shared_ptr<Session> &session) noexcept {
|
||||
session->connection->set_timeout();
|
||||
asio::async_read_until(*session->connection->socket, session->response->content_buffer, "\r\n\r\n", [this, session](const error_code &ec, size_t bytes_transferred) {
|
||||
session->connection->cancel_timeout();
|
||||
|
|
@ -515,7 +520,7 @@ namespace SimpleWeb {
|
|||
});
|
||||
}
|
||||
|
||||
void read_chunked(const std::shared_ptr<Session> &session, const std::shared_ptr<asio::streambuf> &tmp_streambuf) {
|
||||
void read_chunked(const std::shared_ptr<Session> &session, const std::shared_ptr<asio::streambuf> &tmp_streambuf) noexcept {
|
||||
session->connection->set_timeout();
|
||||
asio::async_read_until(*session->connection->socket, session->response->content_buffer, "\r\n", [this, session, tmp_streambuf](const error_code &ec, size_t bytes_transferred) {
|
||||
session->connection->cancel_timeout();
|
||||
|
|
@ -583,14 +588,14 @@ namespace SimpleWeb {
|
|||
template <>
|
||||
class Client<HTTP> : public ClientBase<HTTP> {
|
||||
public:
|
||||
Client(const std::string &server_port_path) : ClientBase<HTTP>::ClientBase(server_port_path, 80) {}
|
||||
Client(const std::string &server_port_path) noexcept : ClientBase<HTTP>::ClientBase(server_port_path, 80) {}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Connection> create_connection() override {
|
||||
std::shared_ptr<Connection> create_connection() noexcept override {
|
||||
return std::make_shared<Connection>(handler_runner, config.timeout, *io_service);
|
||||
}
|
||||
|
||||
void connect(const std::shared_ptr<Session> &session) override {
|
||||
void connect(const std::shared_ptr<Session> &session) noexcept override {
|
||||
if(!session->connection->socket->lowest_layer().is_open()) {
|
||||
auto resolver = std::make_shared<asio::ip::tcp::resolver>(*io_service);
|
||||
session->connection->set_timeout(config.timeout_connect);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace SimpleWeb {
|
|||
class Client<HTTPS> : public ClientBase<HTTPS> {
|
||||
public:
|
||||
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 &verify_file = std::string())
|
||||
const std::string &private_key_file = std::string(), const std::string &verify_file = std::string()) noexcept
|
||||
: ClientBase<HTTPS>::ClientBase(server_port_path, 443), context(asio::ssl::context::tlsv12) {
|
||||
if(cert_file.size() > 0 && private_key_file.size() > 0) {
|
||||
context.use_certificate_chain_file(cert_file);
|
||||
|
|
@ -40,11 +40,11 @@ namespace SimpleWeb {
|
|||
protected:
|
||||
asio::ssl::context context;
|
||||
|
||||
std::shared_ptr<Connection> create_connection() override {
|
||||
std::shared_ptr<Connection> create_connection() noexcept override {
|
||||
return std::make_shared<Connection>(handler_runner, config.timeout, *io_service, context);
|
||||
}
|
||||
|
||||
void connect(const std::shared_ptr<Session> &session) override {
|
||||
void connect(const std::shared_ptr<Session> &session) noexcept override {
|
||||
if(!session->connection->socket->lowest_layer().is_open()) {
|
||||
auto resolver = std::make_shared<asio::ip::tcp::resolver>(*io_service);
|
||||
resolver->async_resolve(*query, [this, session, resolver](const error_code &ec, asio::ip::tcp::resolver::iterator it) {
|
||||
|
|
@ -116,7 +116,7 @@ namespace SimpleWeb {
|
|||
write(session);
|
||||
}
|
||||
|
||||
void handshake(const std::shared_ptr<Session> &session) {
|
||||
void handshake(const std::shared_ptr<Session> &session) noexcept {
|
||||
session->connection->set_timeout(this->config.timeout_connect);
|
||||
session->connection->socket->async_handshake(asio::ssl::stream_base::client, [this, session](const error_code &ec) {
|
||||
session->connection->cancel_timeout();
|
||||
|
|
|
|||
26
crypto.hpp
26
crypto.hpp
|
|
@ -16,7 +16,7 @@
|
|||
namespace SimpleWeb {
|
||||
// TODO 2017: remove workaround for MSVS 2012
|
||||
#if _MSC_VER == 1700 // MSVS 2012 has no definition for round()
|
||||
inline double round(double x) { // Custom definition of round() for positive numbers
|
||||
inline double round(double x) noexcept { // Custom definition of round() for positive numbers
|
||||
return floor(x + 0.5);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -27,7 +27,7 @@ namespace SimpleWeb {
|
|||
public:
|
||||
class Base64 {
|
||||
public:
|
||||
static std::string encode(const std::string &ascii) {
|
||||
static std::string encode(const std::string &ascii) noexcept {
|
||||
std::string base64;
|
||||
|
||||
BIO *bio, *b64;
|
||||
|
|
@ -59,7 +59,7 @@ namespace SimpleWeb {
|
|||
return base64;
|
||||
}
|
||||
|
||||
static std::string decode(const std::string &base64) {
|
||||
static std::string decode(const std::string &base64) noexcept {
|
||||
std::string ascii;
|
||||
|
||||
// Resize ascii, however, the size is a up to two bytes too large.
|
||||
|
|
@ -84,7 +84,7 @@ namespace SimpleWeb {
|
|||
};
|
||||
|
||||
/// Return hex string from bytes in input string.
|
||||
static std::string to_hex_string(const std::string &input) {
|
||||
static std::string to_hex_string(const std::string &input) noexcept {
|
||||
std::stringstream hex_stream;
|
||||
hex_stream << std::hex << std::internal << std::setfill('0');
|
||||
for(auto &byte : input)
|
||||
|
|
@ -92,7 +92,7 @@ namespace SimpleWeb {
|
|||
return hex_stream.str();
|
||||
}
|
||||
|
||||
static std::string md5(const std::string &input, size_t iterations = 1) {
|
||||
static std::string md5(const std::string &input, size_t iterations = 1) noexcept {
|
||||
std::string hash;
|
||||
|
||||
hash.resize(128 / 8);
|
||||
|
|
@ -104,7 +104,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
static std::string md5(std::istream &stream, size_t iterations = 1) {
|
||||
static std::string md5(std::istream &stream, size_t iterations = 1) noexcept {
|
||||
MD5_CTX context;
|
||||
MD5_Init(&context);
|
||||
std::streamsize read_length;
|
||||
|
|
@ -121,7 +121,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
static std::string sha1(const std::string &input, size_t iterations = 1) {
|
||||
static std::string sha1(const std::string &input, size_t iterations = 1) noexcept {
|
||||
std::string hash;
|
||||
|
||||
hash.resize(160 / 8);
|
||||
|
|
@ -133,7 +133,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
static std::string sha1(std::istream &stream, size_t iterations = 1) {
|
||||
static std::string sha1(std::istream &stream, size_t iterations = 1) noexcept {
|
||||
SHA_CTX context;
|
||||
SHA1_Init(&context);
|
||||
std::streamsize read_length;
|
||||
|
|
@ -150,7 +150,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
static std::string sha256(const std::string &input, size_t iterations = 1) {
|
||||
static std::string sha256(const std::string &input, size_t iterations = 1) noexcept {
|
||||
std::string hash;
|
||||
|
||||
hash.resize(256 / 8);
|
||||
|
|
@ -162,7 +162,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
static std::string sha256(std::istream &stream, size_t iterations = 1) {
|
||||
static std::string sha256(std::istream &stream, size_t iterations = 1) noexcept {
|
||||
SHA256_CTX context;
|
||||
SHA256_Init(&context);
|
||||
std::streamsize read_length;
|
||||
|
|
@ -179,7 +179,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
static std::string sha512(const std::string &input, size_t iterations = 1) {
|
||||
static std::string sha512(const std::string &input, size_t iterations = 1) noexcept {
|
||||
std::string hash;
|
||||
|
||||
hash.resize(512 / 8);
|
||||
|
|
@ -191,7 +191,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
static std::string sha512(std::istream &stream, size_t iterations = 1) {
|
||||
static std::string sha512(std::istream &stream, size_t iterations = 1) noexcept {
|
||||
SHA512_CTX context;
|
||||
SHA512_Init(&context);
|
||||
std::streamsize read_length;
|
||||
|
|
@ -209,7 +209,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
/// key_size is number of bytes of the returned key.
|
||||
static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations, int key_size) {
|
||||
static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations, int key_size) noexcept {
|
||||
std::string key;
|
||||
key.resize(key_size);
|
||||
PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.size(),
|
||||
|
|
|
|||
|
|
@ -59,10 +59,10 @@ namespace SimpleWeb {
|
|||
std::shared_ptr<Session> session;
|
||||
long timeout_content;
|
||||
|
||||
Response(std::shared_ptr<Session> session, long timeout_content) : std::ostream(&streambuf), session(std::move(session)), timeout_content(timeout_content) {}
|
||||
Response(std::shared_ptr<Session> session, long timeout_content) noexcept : std::ostream(&streambuf), session(std::move(session)), timeout_content(timeout_content) {}
|
||||
|
||||
template <typename size_type>
|
||||
void write_header(const CaseInsensitiveMultimap &header, size_type size) {
|
||||
void write_header(const CaseInsensitiveMultimap &header, size_type size) noexcept {
|
||||
bool content_length_written = false;
|
||||
bool chunked_transfer_encoding = false;
|
||||
for(auto &field : header) {
|
||||
|
|
@ -80,12 +80,12 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
public:
|
||||
size_t size() {
|
||||
size_t size() noexcept {
|
||||
return streambuf.size();
|
||||
}
|
||||
|
||||
/// Use this function if you need to recursively send parts of a longer message
|
||||
void send(const std::function<void(const error_code &)> &callback = nullptr) {
|
||||
void send(const std::function<void(const error_code &)> &callback = nullptr) noexcept {
|
||||
session->connection->set_timeout(timeout_content);
|
||||
auto self = this->shared_from_this(); // Keep Response instance alive through the following async_write
|
||||
asio::async_write(*session->connection->socket, streambuf, [self, callback](const error_code &ec, size_t /*bytes_transferred*/) {
|
||||
|
|
@ -99,18 +99,18 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
/// Write directly to stream buffer using std::ostream::write
|
||||
void write(const char_type *ptr, std::streamsize n) {
|
||||
void write(const char_type *ptr, std::streamsize n) noexcept {
|
||||
std::ostream::write(ptr, n);
|
||||
}
|
||||
|
||||
/// Convenience function for writing status line, potential header fields, and empty content
|
||||
void write(StatusCode status_code = StatusCode::success_ok, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
void write(StatusCode status_code = StatusCode::success_ok, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) noexcept {
|
||||
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
|
||||
write_header(header, 0);
|
||||
}
|
||||
|
||||
/// Convenience function for writing status line, header fields, and content
|
||||
void write(StatusCode status_code, const std::string &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
void write(StatusCode status_code, const std::string &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) noexcept {
|
||||
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
|
||||
write_header(header, content.size());
|
||||
if(!content.empty())
|
||||
|
|
@ -118,7 +118,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
/// Convenience function for writing status line, header fields, and content
|
||||
void write(StatusCode status_code, std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
void write(StatusCode status_code, std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) noexcept {
|
||||
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
|
||||
content.seekg(0, std::ios::end);
|
||||
auto size = content.tellg();
|
||||
|
|
@ -129,17 +129,17 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
/// Convenience function for writing success status line, header fields, and content
|
||||
void write(const std::string &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
void write(const std::string &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) noexcept {
|
||||
write(StatusCode::success_ok, content, header);
|
||||
}
|
||||
|
||||
/// Convenience function for writing success status line, header fields, and content
|
||||
void write(std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
void write(std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) noexcept {
|
||||
write(StatusCode::success_ok, content, header);
|
||||
}
|
||||
|
||||
/// Convenience function for writing success status line, and header fields
|
||||
void write(const CaseInsensitiveMultimap &header) {
|
||||
void write(const CaseInsensitiveMultimap &header) noexcept {
|
||||
write(StatusCode::success_ok, std::string(), header);
|
||||
}
|
||||
|
||||
|
|
@ -154,19 +154,24 @@ namespace SimpleWeb {
|
|||
friend class ServerBase<socket_type>;
|
||||
|
||||
public:
|
||||
size_t size() {
|
||||
size_t size() noexcept {
|
||||
return streambuf.size();
|
||||
}
|
||||
/// Convenience function to return std::string. Note that the stream buffer is emptied when this functions is used.
|
||||
std::string string() {
|
||||
std::stringstream ss;
|
||||
ss << rdbuf();
|
||||
return ss.str();
|
||||
std::string string() noexcept {
|
||||
try {
|
||||
std::stringstream ss;
|
||||
ss << rdbuf();
|
||||
return ss.str();
|
||||
}
|
||||
catch(...) {
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
asio::streambuf &streambuf;
|
||||
Content(asio::streambuf &streambuf) : std::istream(&streambuf), streambuf(streambuf) {}
|
||||
Content(asio::streambuf &streambuf) noexcept : std::istream(&streambuf), streambuf(streambuf) {}
|
||||
};
|
||||
|
||||
class Request {
|
||||
|
|
@ -187,14 +192,14 @@ namespace SimpleWeb {
|
|||
unsigned short remote_endpoint_port;
|
||||
|
||||
/// Returns query keys with percent-decoded values.
|
||||
CaseInsensitiveMultimap parse_query_string() {
|
||||
CaseInsensitiveMultimap parse_query_string() noexcept {
|
||||
return SimpleWeb::QueryString::parse(query_string);
|
||||
}
|
||||
|
||||
private:
|
||||
asio::streambuf streambuf;
|
||||
|
||||
Request(const std::string &remote_endpoint_address = std::string(), unsigned short remote_endpoint_port = 0)
|
||||
Request(const std::string &remote_endpoint_address = std::string(), unsigned short remote_endpoint_port = 0) noexcept
|
||||
: content(streambuf), remote_endpoint_address(remote_endpoint_address), remote_endpoint_port(remote_endpoint_port) {}
|
||||
};
|
||||
|
||||
|
|
@ -202,7 +207,7 @@ namespace SimpleWeb {
|
|||
class Connection : public std::enable_shared_from_this<Connection> {
|
||||
public:
|
||||
template <typename... Args>
|
||||
Connection(std::shared_ptr<ScopeRunner> handler_runner, Args &&... args) : handler_runner(std::move(handler_runner)), socket(new socket_type(std::forward<Args>(args)...)) {}
|
||||
Connection(std::shared_ptr<ScopeRunner> handler_runner, Args &&... args) noexcept : handler_runner(std::move(handler_runner)), socket(new socket_type(std::forward<Args>(args)...)) {}
|
||||
|
||||
std::shared_ptr<ScopeRunner> handler_runner;
|
||||
|
||||
|
|
@ -211,14 +216,14 @@ namespace SimpleWeb {
|
|||
|
||||
std::unique_ptr<asio::deadline_timer> timer;
|
||||
|
||||
void close() {
|
||||
void close() noexcept {
|
||||
error_code ec;
|
||||
std::unique_lock<std::mutex> lock(socket_close_mutex); // The following operations seems to be needed to run sequentially
|
||||
socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec);
|
||||
socket->lowest_layer().close(ec);
|
||||
}
|
||||
|
||||
void set_timeout(long seconds) {
|
||||
void set_timeout(long seconds) noexcept {
|
||||
if(seconds == 0) {
|
||||
timer = nullptr;
|
||||
return;
|
||||
|
|
@ -233,7 +238,7 @@ namespace SimpleWeb {
|
|||
});
|
||||
}
|
||||
|
||||
void cancel_timeout() {
|
||||
void cancel_timeout() noexcept {
|
||||
if(timer)
|
||||
timer->cancel();
|
||||
}
|
||||
|
|
@ -241,7 +246,7 @@ namespace SimpleWeb {
|
|||
|
||||
class Session {
|
||||
public:
|
||||
Session(std::shared_ptr<Connection> connection) : connection(std::move(connection)) {
|
||||
Session(std::shared_ptr<Connection> connection) noexcept : connection(std::move(connection)) {
|
||||
try {
|
||||
auto remote_endpoint = this->connection->socket->lowest_layer().remote_endpoint();
|
||||
request = std::shared_ptr<Request>(new Request(remote_endpoint.address().to_string(), remote_endpoint.port()));
|
||||
|
|
@ -259,7 +264,7 @@ namespace SimpleWeb {
|
|||
class Config {
|
||||
friend class ServerBase<socket_type>;
|
||||
|
||||
Config(unsigned short port) : port(port) {}
|
||||
Config(unsigned short port) noexcept : port(port) {}
|
||||
|
||||
public:
|
||||
/// Port number to use. Defaults to 80 for HTTP and 443 for HTTPS.
|
||||
|
|
@ -287,7 +292,7 @@ namespace SimpleWeb {
|
|||
public:
|
||||
regex_orderable(const char *regex_cstr) : regex::regex(regex_cstr), str(regex_cstr) {}
|
||||
regex_orderable(std::string regex_str) : regex::regex(regex_str), str(std::move(regex_str)) {}
|
||||
bool operator<(const regex_orderable &rhs) const {
|
||||
bool operator<(const regex_orderable &rhs) const noexcept {
|
||||
return str < rhs.str;
|
||||
}
|
||||
};
|
||||
|
|
@ -305,7 +310,7 @@ namespace SimpleWeb {
|
|||
/// If you have your own asio::io_service, store its pointer here before running start().
|
||||
std::shared_ptr<asio::io_service> io_service;
|
||||
|
||||
virtual void start() {
|
||||
virtual void start() noexcept {
|
||||
if(!io_service) {
|
||||
io_service = std::make_shared<asio::io_service>();
|
||||
internal_io_service = true;
|
||||
|
|
@ -349,7 +354,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
/// Stop accepting new requests, and close current connections.
|
||||
void stop() {
|
||||
void stop() noexcept {
|
||||
if(acceptor) {
|
||||
error_code ec;
|
||||
acceptor->close(ec);
|
||||
|
|
@ -366,7 +371,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
}
|
||||
|
||||
virtual ~ServerBase() {
|
||||
virtual ~ServerBase() noexcept {
|
||||
handler_runner->stop();
|
||||
stop();
|
||||
}
|
||||
|
|
@ -382,12 +387,12 @@ namespace SimpleWeb {
|
|||
|
||||
std::shared_ptr<ScopeRunner> handler_runner;
|
||||
|
||||
ServerBase(unsigned short port) : config(port), connections(new std::unordered_set<Connection *>()), connections_mutex(new std::mutex()), handler_runner(new ScopeRunner()) {}
|
||||
ServerBase(unsigned short port) noexcept : config(port), connections(new std::unordered_set<Connection *>()), connections_mutex(new std::mutex()), handler_runner(new ScopeRunner()) {}
|
||||
|
||||
virtual void accept() = 0;
|
||||
virtual void accept() noexcept = 0;
|
||||
|
||||
template <typename... Args>
|
||||
std::shared_ptr<Connection> create_connection(Args &&... args) {
|
||||
std::shared_ptr<Connection> create_connection(Args &&... args) noexcept {
|
||||
auto connections = this->connections;
|
||||
auto connections_mutex = this->connections_mutex;
|
||||
auto connection = std::shared_ptr<Connection>(new Connection(handler_runner, std::forward<Args>(args)...), [connections, connections_mutex](Connection *connection) {
|
||||
|
|
@ -406,7 +411,7 @@ namespace SimpleWeb {
|
|||
return connection;
|
||||
}
|
||||
|
||||
void read_request_and_content(const std::shared_ptr<Session> &session) {
|
||||
void read_request_and_content(const std::shared_ptr<Session> &session) noexcept {
|
||||
session->connection->set_timeout(config.timeout_request);
|
||||
asio::async_read_until(*session->connection->socket, session->request->streambuf, "\r\n\r\n", [this, session](const error_code &ec, size_t bytes_transferred) {
|
||||
session->connection->cancel_timeout();
|
||||
|
|
@ -463,7 +468,7 @@ namespace SimpleWeb {
|
|||
});
|
||||
}
|
||||
|
||||
void find_resource(const std::shared_ptr<Session> &session) {
|
||||
void find_resource(const std::shared_ptr<Session> &session) noexcept {
|
||||
// Upgrade connection
|
||||
if(on_upgrade) {
|
||||
auto it = session->request->header.find("Upgrade");
|
||||
|
|
@ -498,7 +503,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
void write_response(const std::shared_ptr<Session> &session,
|
||||
std::function<void(std::shared_ptr<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) noexcept {
|
||||
session->connection->set_timeout(config.timeout_content);
|
||||
auto response = std::shared_ptr<Response>(new Response(session, config.timeout_content), [this](Response *response_ptr) {
|
||||
auto response = std::shared_ptr<Response>(response_ptr);
|
||||
|
|
@ -547,10 +552,10 @@ namespace SimpleWeb {
|
|||
template <>
|
||||
class Server<HTTP> : public ServerBase<HTTP> {
|
||||
public:
|
||||
Server() : ServerBase<HTTP>::ServerBase(80) {}
|
||||
Server() noexcept : ServerBase<HTTP>::ServerBase(80) {}
|
||||
|
||||
protected:
|
||||
void accept() override {
|
||||
void accept() noexcept override {
|
||||
auto session = std::make_shared<Session>(create_connection(*io_service));
|
||||
|
||||
acceptor->async_accept(*session->connection->socket, [this, session](const error_code &ec) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace SimpleWeb {
|
|||
bool set_session_id_context = false;
|
||||
|
||||
public:
|
||||
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()) noexcept
|
||||
: ServerBase<HTTPS>::ServerBase(443), context(asio::ssl::context::tlsv12) {
|
||||
context.use_certificate_chain_file(cert_file);
|
||||
context.use_private_key_file(private_key_file, asio::ssl::context::pem);
|
||||
|
|
@ -33,7 +33,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
}
|
||||
|
||||
void start() override {
|
||||
void start() noexcept override {
|
||||
if(set_session_id_context) {
|
||||
// Creating session_id_context from address:port but reversed due to small SSL_MAX_SSL_SESSION_ID_LENGTH
|
||||
session_id_context = std::to_string(config.port) + ':';
|
||||
|
|
@ -47,7 +47,7 @@ namespace SimpleWeb {
|
|||
protected:
|
||||
asio::ssl::context context;
|
||||
|
||||
void accept() override {
|
||||
void accept() noexcept override {
|
||||
auto session = std::make_shared<Session>(create_connection(*io_service, context));
|
||||
|
||||
acceptor->async_accept(session->connection->socket->lowest_layer(), [this, session](const error_code &ec) {
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ namespace SimpleWeb {
|
|||
server_error_network_authentication_required
|
||||
};
|
||||
|
||||
const static std::vector<std::pair<StatusCode, std::string>> &status_codes() {
|
||||
const static std::vector<std::pair<StatusCode, std::string>> &status_codes() noexcept {
|
||||
const static std::vector<std::pair<StatusCode, std::string>> status_codes = {
|
||||
{StatusCode::unknown, ""},
|
||||
{StatusCode::information_continue, "100 Continue"},
|
||||
|
|
@ -137,7 +137,7 @@ namespace SimpleWeb {
|
|||
return status_codes;
|
||||
}
|
||||
|
||||
inline StatusCode status_code(const std::string &status_code_str) {
|
||||
inline StatusCode status_code(const std::string &status_code_str) noexcept {
|
||||
for(auto &status_code : status_codes()) {
|
||||
if(status_code.second == status_code_str)
|
||||
return status_code.first;
|
||||
|
|
@ -145,7 +145,7 @@ namespace SimpleWeb {
|
|||
return StatusCode::unknown;
|
||||
}
|
||||
|
||||
inline const std::string &status_code(StatusCode status_code_enum) {
|
||||
inline const std::string &status_code(StatusCode status_code_enum) noexcept {
|
||||
for(auto &status_code : status_codes()) {
|
||||
if(status_code.first == status_code_enum)
|
||||
return status_code.second;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class ServerTest : public ServerBase<HTTP> {
|
|||
public:
|
||||
ServerTest() : ServerBase<HTTP>::ServerBase(8080) {}
|
||||
|
||||
void accept() override {}
|
||||
void accept() noexcept override {}
|
||||
|
||||
void parse_request_test() {
|
||||
auto session = std::make_shared<Session>(create_connection(*io_service));
|
||||
|
|
@ -55,11 +55,11 @@ class ClientTest : public ClientBase<HTTP> {
|
|||
public:
|
||||
ClientTest(const std::string &server_port_path) : ClientBase<HTTP>::ClientBase(server_port_path, 80) {}
|
||||
|
||||
std::shared_ptr<Connection> create_connection() override {
|
||||
std::shared_ptr<Connection> create_connection() noexcept override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void connect(const std::shared_ptr<Session> &) override {}
|
||||
void connect(const std::shared_ptr<Session> &) noexcept override {}
|
||||
|
||||
void constructor_parse_test1() {
|
||||
assert(host == "test.org");
|
||||
|
|
|
|||
34
utility.hpp
34
utility.hpp
|
|
@ -9,7 +9,7 @@
|
|||
#include <unordered_map>
|
||||
|
||||
namespace SimpleWeb {
|
||||
inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) {
|
||||
inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) noexcept {
|
||||
return str1.size() == str2.size() &&
|
||||
std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) {
|
||||
return tolower(a) == tolower(b);
|
||||
|
|
@ -17,14 +17,14 @@ namespace SimpleWeb {
|
|||
}
|
||||
class CaseInsensitiveEqual {
|
||||
public:
|
||||
bool operator()(const std::string &str1, const std::string &str2) const {
|
||||
bool operator()(const std::string &str1, const std::string &str2) const noexcept {
|
||||
return case_insensitive_equal(str1, str2);
|
||||
}
|
||||
};
|
||||
// Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226
|
||||
class CaseInsensitiveHash {
|
||||
public:
|
||||
size_t operator()(const std::string &str) const {
|
||||
size_t operator()(const std::string &str) const noexcept {
|
||||
size_t h = 0;
|
||||
std::hash<int> hash;
|
||||
for(auto c : str)
|
||||
|
|
@ -39,7 +39,7 @@ namespace SimpleWeb {
|
|||
class Percent {
|
||||
public:
|
||||
/// Returns percent-encoded string
|
||||
static std::string encode(const std::string &value) {
|
||||
static std::string encode(const std::string &value) noexcept {
|
||||
static auto hex_chars = "0123456789ABCDEF";
|
||||
|
||||
std::string result;
|
||||
|
|
@ -58,7 +58,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
/// Returns percent-decoded string
|
||||
static std::string decode(const std::string &value) {
|
||||
static std::string decode(const std::string &value) noexcept {
|
||||
std::string result;
|
||||
result.reserve(value.size() / 3 + (value.size() % 3)); // Minimum size of result
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ namespace SimpleWeb {
|
|||
class QueryString {
|
||||
public:
|
||||
/// Returns query string created from given field names and values
|
||||
static std::string create(const CaseInsensitiveMultimap &fields) {
|
||||
static std::string create(const CaseInsensitiveMultimap &fields) noexcept {
|
||||
std::string result;
|
||||
|
||||
bool first = true;
|
||||
|
|
@ -97,7 +97,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
/// Returns query keys with percent-decoded values.
|
||||
static CaseInsensitiveMultimap parse(const std::string &query_string) {
|
||||
static CaseInsensitiveMultimap parse(const std::string &query_string) noexcept {
|
||||
CaseInsensitiveMultimap result;
|
||||
|
||||
if(query_string.empty())
|
||||
|
|
@ -137,7 +137,7 @@ namespace SimpleWeb {
|
|||
class RequestMessage {
|
||||
public:
|
||||
/// Parse request line and header fields
|
||||
static bool parse(std::istream &stream, std::string &method, std::string &path, std::string &query_string, std::string &version, CaseInsensitiveMultimap &header) {
|
||||
static bool parse(std::istream &stream, std::string &method, std::string &path, std::string &query_string, std::string &version, CaseInsensitiveMultimap &header) noexcept {
|
||||
header.clear();
|
||||
std::string line;
|
||||
getline(stream, line);
|
||||
|
|
@ -198,7 +198,7 @@ namespace SimpleWeb {
|
|||
class ResponseMessage {
|
||||
public:
|
||||
/// Parse status line and header fields
|
||||
static bool parse(std::istream &stream, std::string &version, std::string &status_code, CaseInsensitiveMultimap &header) {
|
||||
static bool parse(std::istream &stream, std::string &version, std::string &status_code, CaseInsensitiveMultimap &header) noexcept {
|
||||
header.clear();
|
||||
std::string line;
|
||||
getline(stream, line);
|
||||
|
|
@ -237,17 +237,17 @@ namespace SimpleWeb {
|
|||
#ifdef __SSE2__
|
||||
#include <emmintrin.h>
|
||||
namespace SimpleWeb {
|
||||
inline void spin_loop_pause() { _mm_pause(); }
|
||||
inline void spin_loop_pause() noexcept { _mm_pause(); }
|
||||
} // namespace SimpleWeb
|
||||
// TODO: need verification that the following checks are correct:
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1800 && (defined(_M_X64) || defined(_M_IX86))
|
||||
#include <intrin.h>
|
||||
namespace SimpleWeb {
|
||||
inline void spin_loop_pause() { _mm_pause(); }
|
||||
inline void spin_loop_pause() noexcept { _mm_pause(); }
|
||||
} // namespace SimpleWeb
|
||||
#else
|
||||
namespace SimpleWeb {
|
||||
inline void spin_loop_pause() {}
|
||||
inline void spin_loop_pause() noexcept {}
|
||||
} // namespace SimpleWeb
|
||||
#endif
|
||||
|
||||
|
|
@ -261,20 +261,20 @@ namespace SimpleWeb {
|
|||
class SharedLock {
|
||||
friend class ScopeRunner;
|
||||
std::atomic<long> &count;
|
||||
SharedLock(std::atomic<long> &count) : count(count) {}
|
||||
SharedLock(std::atomic<long> &count) noexcept : count(count) {}
|
||||
SharedLock &operator=(const SharedLock &) = delete;
|
||||
SharedLock(const SharedLock &) = delete;
|
||||
|
||||
public:
|
||||
~SharedLock() {
|
||||
~SharedLock() noexcept {
|
||||
count.fetch_sub(1);
|
||||
}
|
||||
};
|
||||
|
||||
ScopeRunner() : count(0) {}
|
||||
ScopeRunner() noexcept : count(0) {}
|
||||
|
||||
/// Returns nullptr if scope should be exited, or a shared lock otherwise
|
||||
std::unique_ptr<SharedLock> continue_lock() {
|
||||
std::unique_ptr<SharedLock> continue_lock() noexcept {
|
||||
long expected = count;
|
||||
while(expected >= 0 && !count.compare_exchange_weak(expected, expected + 1))
|
||||
spin_loop_pause();
|
||||
|
|
@ -286,7 +286,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
//// Blocks until all shared locks are released, then prevents future shared locks
|
||||
void stop() {
|
||||
void stop() noexcept {
|
||||
long expected = 0;
|
||||
while(!count.compare_exchange_weak(expected, -1)) {
|
||||
if(expected < 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue