Added noexcept

This commit is contained in:
eidheim 2017-07-22 12:50:40 +02:00
commit 7dd2d2108a
8 changed files with 122 additions and 112 deletions

View file

@ -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::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);

View file

@ -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();

View file

@ -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(),

View file

@ -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::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) {

View file

@ -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) {

View file

@ -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;

View file

@ -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");

View file

@ -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)