This commit is contained in:
eidheim 2017-09-30 12:06:15 +02:00
commit 99cc6d9ad3
5 changed files with 53 additions and 46 deletions

View file

@ -6,6 +6,8 @@
#include <random>
#include <unordered_set>
#include <vector>
#include <limits>
#include <cstddef>
#ifdef USE_STANDALONE_ASIO
#include <asio.hpp>
@ -42,7 +44,7 @@ namespace SimpleWeb {
friend class ClientBase<socket_type>;
public:
size_t size() noexcept {
std::size_t size() noexcept {
return streambuf.size();
}
/// Convenience function to return std::string. The stream buffer is consumed.
@ -68,7 +70,7 @@ namespace SimpleWeb {
asio::streambuf streambuf;
Response(size_t max_response_streambuf_size) noexcept : streambuf(max_response_streambuf_size), content(streambuf) {}
Response(std::size_t max_response_streambuf_size) noexcept : streambuf(max_response_streambuf_size), content(streambuf) {}
public:
std::string http_version, status_code;
@ -91,7 +93,7 @@ namespace SimpleWeb {
long timeout_connect = 0;
/// Maximum size of response stream buffer. Defaults to architecture maximum.
/// Reaching this limit will result in a message_size error code.
size_t max_response_streambuf_size = static_cast<size_t>(-1);
std::size_t max_response_streambuf_size = std::numeric_limits<std::size_t>::max();
/// Set proxy server (server:port)
std::string proxy_server;
};
@ -140,7 +142,7 @@ namespace SimpleWeb {
class Session {
public:
Session(size_t max_response_streambuf_size, std::shared_ptr<Connection> connection, std::unique_ptr<asio::streambuf> request_streambuf) noexcept
Session(std::size_t max_response_streambuf_size, std::shared_ptr<Connection> connection, std::unique_ptr<asio::streambuf> request_streambuf) noexcept
: connection(std::move(connection)), request_streambuf(std::move(request_streambuf)), response(new Response(max_response_streambuf_size)) {}
std::shared_ptr<Connection> connection;
@ -230,7 +232,7 @@ namespace SimpleWeb {
connection->in_use = false;
// Remove unused connections, but keep one open for HTTP persistent connection:
size_t unused_connections = 0;
std::size_t unused_connections = 0;
for(auto it = this->connections.begin(); it != this->connections.end();) {
if(ec && connection == *it)
it = this->connections.erase(it);
@ -289,7 +291,7 @@ namespace SimpleWeb {
connection->in_use = false;
// Remove unused connections, but keep one open for HTTP persistent connection:
size_t unused_connections = 0;
std::size_t unused_connections = 0;
for(auto it = this->connections.begin(); it != this->connections.end();) {
if(ec && connection == *it)
it = this->connections.erase(it);
@ -356,7 +358,7 @@ namespace SimpleWeb {
std::shared_ptr<ScopeRunner> handler_runner;
size_t concurrent_synchronous_requests = 0;
std::size_t concurrent_synchronous_requests = 0;
std::mutex concurrent_synchronous_requests_mutex;
ClientBase(const std::string &host_port, unsigned short default_port) noexcept : handler_runner(new ScopeRunner()) {
@ -420,7 +422,7 @@ namespace SimpleWeb {
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(':');
std::size_t host_end = host_port.find(':');
if(host_end == std::string::npos) {
parsed_host_port.first = host_port;
parsed_host_port.second = default_port;
@ -434,7 +436,7 @@ namespace SimpleWeb {
void write(const std::shared_ptr<Session> &session) {
session->connection->set_timeout();
asio::async_write(*session->connection->socket, session->request_streambuf->data(), [this, session](const error_code &ec, size_t /*bytes_transferred*/) {
asio::async_write(*session->connection->socket, session->request_streambuf->data(), [this, session](const error_code &ec, std::size_t /*bytes_transferred*/) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)
@ -448,7 +450,7 @@ namespace SimpleWeb {
void read(const std::shared_ptr<Session> &session) {
session->connection->set_timeout();
asio::async_read_until(*session->connection->socket, session->response->streambuf, "\r\n\r\n", [this, session](const error_code &ec, size_t bytes_transferred) {
asio::async_read_until(*session->connection->socket, session->response->streambuf, "\r\n\r\n", [this, session](const error_code &ec, std::size_t bytes_transferred) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)
@ -459,7 +461,7 @@ namespace SimpleWeb {
}
if(!ec) {
session->connection->attempt_reconnect = true;
size_t num_additional_bytes = session->response->streambuf.size() - bytes_transferred;
std::size_t num_additional_bytes = session->response->streambuf.size() - bytes_transferred;
if(!ResponseMessage::parse(session->response->content, session->response->http_version, session->response->status_code, session->response->header)) {
session->callback(session->connection, make_error_code::make_error_code(errc::protocol_error));
@ -471,7 +473,7 @@ namespace SimpleWeb {
auto content_length = stoull(header_it->second);
if(content_length > num_additional_bytes) {
session->connection->set_timeout();
asio::async_read(*session->connection->socket, session->response->streambuf, asio::transfer_exactly(content_length - num_additional_bytes), [this, session](const error_code &ec, size_t /*bytes_transferred*/) {
asio::async_read(*session->connection->socket, session->response->streambuf, asio::transfer_exactly(content_length - num_additional_bytes), [this, session](const error_code &ec, std::size_t /*bytes_transferred*/) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)
@ -496,7 +498,7 @@ namespace SimpleWeb {
}
else if(session->response->http_version < "1.1" || ((header_it = session->response->header.find("Session")) != session->response->header.end() && header_it->second == "close")) {
session->connection->set_timeout();
asio::async_read(*session->connection->socket, session->response->streambuf, [this, session](const error_code &ec, size_t /*bytes_transferred*/) {
asio::async_read(*session->connection->socket, session->response->streambuf, [this, session](const error_code &ec, std::size_t /*bytes_transferred*/) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)
@ -552,7 +554,7 @@ namespace SimpleWeb {
chunked_stream << &session->response->streambuf;
}
session->connection->set_timeout();
asio::async_read_until(*session->connection->socket, *chunked_streambuf, "\r\n", [this, session, chunked_streambuf, tmp_streambuf](const error_code &ec, size_t bytes_transferred) {
asio::async_read_until(*session->connection->socket, *chunked_streambuf, "\r\n", [this, session, chunked_streambuf, tmp_streambuf](const error_code &ec, std::size_t bytes_transferred) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)
@ -605,7 +607,7 @@ namespace SimpleWeb {
if((2 + length) > num_additional_bytes) {
session->connection->set_timeout();
asio::async_read(*session->connection->socket, *chunked_streambuf, asio::transfer_exactly(2 + length - num_additional_bytes), [this, session, chunked_streambuf, post_process](const error_code &ec, size_t /*bytes_transferred*/) {
asio::async_read(*session->connection->socket, *chunked_streambuf, asio::transfer_exactly(2 + length - num_additional_bytes), [this, session, chunked_streambuf, post_process](const error_code &ec, std::size_t /*bytes_transferred*/) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)

View file

@ -2,6 +2,7 @@
#define CLIENT_HTTPS_HPP
#include "client_http.hpp"
#include <cstddef>
#ifdef USE_STANDALONE_ASIO
#include <asio/ssl.hpp>
@ -70,7 +71,7 @@ namespace SimpleWeb {
write_stream << "CONNECT " + host_port + " HTTP/1.1\r\n"
<< "Host: " << host_port << "\r\n\r\n";
session->connection->set_timeout(this->config.timeout_connect);
asio::async_write(session->connection->socket->next_layer(), *write_buffer, [this, session, write_buffer](const error_code &ec, size_t /*bytes_transferred*/) {
asio::async_write(session->connection->socket->next_layer(), *write_buffer, [this, session, write_buffer](const error_code &ec, std::size_t /*bytes_transferred*/) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)
@ -78,7 +79,7 @@ namespace SimpleWeb {
if(!ec) {
std::shared_ptr<Response> response(new Response(this->config.max_response_streambuf_size));
session->connection->set_timeout(this->config.timeout_connect);
asio::async_read_until(session->connection->socket->next_layer(), response->streambuf, "\r\n\r\n", [this, session, response](const error_code &ec, size_t /*bytes_transferred*/) {
asio::async_read_until(session->connection->socket->next_layer(), response->streambuf, "\r\n\r\n", [this, session, response](const error_code &ec, std::size_t /*bytes_transferred*/) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)

View file

@ -9,6 +9,8 @@
#include <sstream>
#include <thread>
#include <unordered_set>
#include <limits>
#include <cstddef>
#ifdef USE_STANDALONE_ASIO
#include <asio.hpp>
@ -82,7 +84,7 @@ namespace SimpleWeb {
}
public:
size_t size() noexcept {
std::size_t size() noexcept {
return streambuf.size();
}
@ -90,7 +92,7 @@ namespace SimpleWeb {
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*/) {
asio::async_write(*session->connection->socket, streambuf, [self, callback](const error_code &ec, std::size_t /*bytes_transferred*/) {
self->session->connection->cancel_timeout();
auto lock = self->session->connection->handler_runner->continue_lock();
if(!lock)
@ -156,7 +158,7 @@ namespace SimpleWeb {
friend class ServerBase<socket_type>;
public:
size_t size() noexcept {
std::size_t size() noexcept {
return streambuf.size();
}
/// Convenience function to return std::string. The stream buffer is consumed.
@ -182,7 +184,7 @@ namespace SimpleWeb {
friend class Session;
asio::streambuf streambuf;
Request(size_t max_request_streambuf_size, const std::string &remote_endpoint_address = std::string(), unsigned short remote_endpoint_port = 0) noexcept
Request(std::size_t max_request_streambuf_size, const std::string &remote_endpoint_address = std::string(), unsigned short remote_endpoint_port = 0) noexcept
: streambuf(max_request_streambuf_size), content(streambuf), remote_endpoint_address(remote_endpoint_address), remote_endpoint_port(remote_endpoint_port) {}
public:
@ -248,7 +250,7 @@ namespace SimpleWeb {
class Session {
public:
Session(size_t max_request_streambuf_size, std::shared_ptr<Connection> connection) noexcept : connection(std::move(connection)) {
Session(std::size_t max_request_streambuf_size, 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(max_request_streambuf_size, remote_endpoint.address().to_string(), remote_endpoint.port()));
@ -273,14 +275,14 @@ namespace SimpleWeb {
unsigned short port;
/// If io_service is not set, number of threads that the server will use when start() is called.
/// Defaults to 1 thread.
size_t thread_pool_size = 1;
std::size_t thread_pool_size = 1;
/// Timeout on request handling. Defaults to 5 seconds.
long timeout_request = 5;
/// Timeout on content handling. Defaults to 300 seconds.
long timeout_content = 300;
/// Maximum size of request stream buffer. Defaults to architecture maximum.
/// Reaching this limit will result in a message_size error code.
size_t max_request_streambuf_size = static_cast<size_t>(-1);
std::size_t max_request_streambuf_size = std::numeric_limits<std::size_t>::max();
/// IPv4 address in dotted decimal form or IPv6 address in hexadecimal notation.
/// If empty, the address will be any address.
std::string address;
@ -342,7 +344,7 @@ namespace SimpleWeb {
if(internal_io_service) {
// If thread_pool_size>1, start m_io_service.run() in (thread_pool_size-1) threads for thread-pooling
threads.clear();
for(size_t c = 1; c < config.thread_pool_size; c++) {
for(std::size_t c = 1; c < config.thread_pool_size; c++) {
threads.emplace_back([this]() {
this->io_service->run();
});
@ -418,7 +420,7 @@ namespace SimpleWeb {
void read_request_and_content(const std::shared_ptr<Session> &session) {
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) {
asio::async_read_until(*session->connection->socket, session->request->streambuf, "\r\n\r\n", [this, session](const error_code &ec, std::size_t bytes_transferred) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)
@ -436,7 +438,7 @@ namespace SimpleWeb {
// "After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
// The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
// streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
size_t num_additional_bytes = session->request->streambuf.size() - bytes_transferred;
std::size_t num_additional_bytes = session->request->streambuf.size() - bytes_transferred;
if(!RequestMessage::parse(session->request->content, session->request->method, session->request->path,
session->request->query_string, session->request->http_version, session->request->header)) {
@ -459,7 +461,7 @@ namespace SimpleWeb {
}
if(content_length > num_additional_bytes) {
session->connection->set_timeout(config.timeout_content);
asio::async_read(*session->connection->socket, session->request->streambuf, asio::transfer_exactly(content_length - num_additional_bytes), [this, session](const error_code &ec, size_t /*bytes_transferred*/) {
asio::async_read(*session->connection->socket, session->request->streambuf, asio::transfer_exactly(content_length - num_additional_bytes), [this, session](const error_code &ec, std::size_t /*bytes_transferred*/) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)

View file

@ -10,6 +10,7 @@
#endif
#include <algorithm>
#include <cstddef>
#include <openssl/ssl.h>
namespace SimpleWeb {
@ -39,7 +40,7 @@ namespace SimpleWeb {
session_id_context = std::to_string(config.port) + ':';
session_id_context.append(config.address.rbegin(), config.address.rend());
SSL_CTX_set_session_id_context(context.native_handle(), reinterpret_cast<const unsigned char *>(session_id_context.data()),
std::min<size_t>(session_id_context.size(), SSL_MAX_SSL_SESSION_ID_LENGTH));
std::min<std::size_t>(session_id_context.size(), SSL_MAX_SSL_SESSION_ID_LENGTH));
}
ServerBase::start();
}

View file

@ -7,6 +7,7 @@
#include <memory>
#include <string>
#include <unordered_map>
#include <cstddef>
namespace SimpleWeb {
inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) noexcept {
@ -24,8 +25,8 @@ namespace SimpleWeb {
// 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 noexcept {
size_t h = 0;
std::size_t operator()(const std::string &str) const noexcept {
std::size_t h = 0;
std::hash<int> hash;
for(auto c : str)
h ^= hash(tolower(c)) + 0x9e3779b9 + (h << 6) + (h >> 2);
@ -62,7 +63,7 @@ namespace SimpleWeb {
std::string result;
result.reserve(value.size() / 3 + (value.size() % 3)); // Minimum size of result
for(size_t i = 0; i < value.size(); ++i) {
for(std::size_t i = 0; i < value.size(); ++i) {
auto &chr = value[i];
if(chr == '%' && i + 2 < value.size()) {
auto hex = value.substr(i + 1, 2);
@ -103,10 +104,10 @@ namespace SimpleWeb {
if(query_string.empty())
return result;
size_t name_pos = 0;
std::size_t name_pos = 0;
auto name_end_pos = std::string::npos;
auto value_pos = std::string::npos;
for(size_t c = 0; c < query_string.size(); ++c) {
for(std::size_t c = 0; c < query_string.size(); ++c) {
if(query_string[c] == '&') {
auto name = query_string.substr(name_pos, (name_end_pos == std::string::npos ? c : name_end_pos) - name_pos);
if(!name.empty()) {
@ -141,9 +142,9 @@ namespace SimpleWeb {
CaseInsensitiveMultimap result;
std::string line;
getline(stream, line);
size_t param_end;
std::size_t param_end;
while((param_end = line.find(':')) != std::string::npos) {
size_t value_start = param_end + 1;
std::size_t value_start = param_end + 1;
if(value_start < line.size()) {
if(line[value_start] == ' ')
value_start++;
@ -164,13 +165,13 @@ namespace SimpleWeb {
header.clear();
std::string line;
getline(stream, line);
size_t method_end;
std::size_t method_end;
if((method_end = line.find(' ')) != std::string::npos) {
method = line.substr(0, method_end);
size_t query_start = std::string::npos;
size_t path_and_query_string_end = std::string::npos;
for(size_t i = method_end + 1; i < line.size(); ++i) {
std::size_t query_start = std::string::npos;
std::size_t path_and_query_string_end = std::string::npos;
for(std::size_t i = method_end + 1; i < line.size(); ++i) {
if(line[i] == '?' && (i + 1) < line.size())
query_start = i + 1;
else if(line[i] == ' ') {
@ -186,7 +187,7 @@ namespace SimpleWeb {
else
path = line.substr(method_end + 1, path_and_query_string_end - method_end - 1);
size_t protocol_end;
std::size_t protocol_end;
if((protocol_end = line.find('/', path_and_query_string_end + 1)) != std::string::npos) {
if(line.compare(path_and_query_string_end + 1, protocol_end - path_and_query_string_end - 1, "HTTP") != 0)
return false;
@ -213,7 +214,7 @@ namespace SimpleWeb {
header.clear();
std::string line;
getline(stream, line);
size_t version_end = line.find(' ');
std::size_t version_end = line.find(' ');
if(version_end != std::string::npos) {
if(5 < line.size())
version = line.substr(5, version_end - 5);
@ -239,10 +240,10 @@ namespace SimpleWeb {
static CaseInsensitiveMultimap parse(const std::string &line) {
CaseInsensitiveMultimap result;
size_t para_start_pos = 0;
size_t para_end_pos = std::string::npos;
size_t value_start_pos = std::string::npos;
for(size_t c = 0; c < line.size(); ++c) {
std::size_t para_start_pos = 0;
std::size_t para_end_pos = std::string::npos;
std::size_t value_start_pos = std::string::npos;
for(std::size_t c = 0; c < line.size(); ++c) {
if(para_start_pos != std::string::npos) {
if(para_end_pos == std::string::npos) {
if(line[c] == ';') {