From 84455ac966555a5cf81eabc217aecc0a207870ae Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 4 Feb 2020 10:01:49 +0100 Subject: [PATCH] Cleanup of timeout handling: timeouts are no longer reset on partial reads and sends --- client_http.hpp | 38 +++++++++++++------------------------- client_https.hpp | 2 +- server_http.hpp | 18 ++++-------------- 3 files changed, 18 insertions(+), 40 deletions(-) diff --git a/client_http.hpp b/client_http.hpp index 342d64c..711047f 100644 --- a/client_http.hpp +++ b/client_http.hpp @@ -150,11 +150,10 @@ namespace SimpleWeb { class Connection : public std::enable_shared_from_this { public: template - Connection(std::shared_ptr handler_runner_, long timeout, Args &&... args) noexcept - : handler_runner(std::move(handler_runner_)), timeout(timeout), socket(new socket_type(std::forward(args)...)) {} + Connection(std::shared_ptr handler_runner_, Args &&... args) noexcept + : handler_runner(std::move(handler_runner_)), socket(new socket_type(std::forward(args)...)) {} std::shared_ptr handler_runner; - long timeout; std::unique_ptr socket; // Socket must be unique_ptr since asio::ssl::stream is not movable bool in_use = false; @@ -168,9 +167,7 @@ namespace SimpleWeb { socket->lowest_layer().cancel(ec); } - void set_timeout(long seconds = 0) noexcept { - if(seconds == 0) - seconds = timeout; + void set_timeout(long seconds) noexcept { if(seconds == 0) { timer = nullptr; return; @@ -314,10 +311,12 @@ namespace SimpleWeb { auto request_callback = std::make_shared, const error_code &)>>(std::move(request_callback_)); session->callback = [this, session_weak, request_callback](const error_code &ec) { if(auto session = session_weak.lock()) { + if(session->response->content.end) { + session->connection->cancel_timeout(); + session->connection->in_use = false; + } { LockGuard lock(this->connections_mutex); - if(session->response->content.end) - session->connection->in_use = false; // Remove unused connections, but keep one open for HTTP persistent connection: std::size_t unused_connections = 0; @@ -389,10 +388,12 @@ namespace SimpleWeb { auto request_callback = std::make_shared, const error_code &)>>(std::move(request_callback_)); session->callback = [this, session_weak, request_callback](const error_code &ec) { if(auto session = session_weak.lock()) { + if(session->response->content.end) { + session->connection->cancel_timeout(); + session->connection->in_use = false; + } { LockGuard lock(this->connections_mutex); - if(session->response->content.end) - session->connection->in_use = false; // Remove unused connections, but keep one open for HTTP persistent connection: std::size_t unused_connections = 0; @@ -551,9 +552,8 @@ namespace SimpleWeb { } void write(const std::shared_ptr &session) { - session->connection->set_timeout(); + session->connection->set_timeout(config.timeout); 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) return; @@ -569,9 +569,7 @@ namespace SimpleWeb { } void read(const std::shared_ptr &session) { - session->connection->set_timeout(); asio::async_read_until(*session->connection->socket, session->response->streambuf, HeaderEndMatch(), [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) return; @@ -652,9 +650,7 @@ namespace SimpleWeb { } void read_content(const std::shared_ptr &session, std::size_t remaining_length) { - session->connection->set_timeout(); asio::async_read(*session->connection->socket, session->response->streambuf, asio::transfer_exactly(remaining_length), [this, session, remaining_length](const error_code &ec, std::size_t bytes_transferred) { - session->connection->cancel_timeout(); auto lock = session->connection->handler_runner->continue_lock(); if(!lock) return; @@ -675,9 +671,7 @@ namespace SimpleWeb { } void read_content(const std::shared_ptr &session) { - session->connection->set_timeout(); 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) return; @@ -704,9 +698,7 @@ namespace SimpleWeb { } void read_chunked_transfer_encoded(const std::shared_ptr &session, const std::shared_ptr &chunk_size_streambuf) { - session->connection->set_timeout(); asio::async_read_until(*session->connection->socket, *chunk_size_streambuf, "\r\n", [this, session, chunk_size_streambuf](const error_code &ec, size_t bytes_transferred) { - session->connection->cancel_timeout(); auto lock = session->connection->handler_runner->continue_lock(); if(!lock) return; @@ -747,9 +739,7 @@ namespace SimpleWeb { } if((2 + chunk_size) > num_additional_bytes) { - session->connection->set_timeout(); asio::async_read(*session->connection->socket, session->response->streambuf, asio::transfer_exactly(2 + chunk_size - num_additional_bytes), [this, session, chunk_size_streambuf](const error_code &ec, size_t /*bytes_transferred*/) { - session->connection->cancel_timeout(); auto lock = session->connection->handler_runner->continue_lock(); if(!lock) return; @@ -781,9 +771,7 @@ namespace SimpleWeb { } void read_server_sent_event(const std::shared_ptr &session, const std::shared_ptr &events_streambuf) { - session->connection->set_timeout(); asio::async_read_until(*session->connection->socket, *events_streambuf, HeaderEndMatch(), [this, session, events_streambuf](const error_code &ec, std::size_t /*bytes_transferred*/) { - session->connection->cancel_timeout(); auto lock = session->connection->handler_runner->continue_lock(); if(!lock) return; @@ -825,7 +813,7 @@ namespace SimpleWeb { protected: std::shared_ptr create_connection() noexcept override { - return std::make_shared(handler_runner, config.timeout, *io_service); + return std::make_shared(handler_runner, *io_service); } void connect(const std::shared_ptr &session) override { diff --git a/client_https.hpp b/client_https.hpp index 2ff9330..aabca1c 100644 --- a/client_https.hpp +++ b/client_https.hpp @@ -50,7 +50,7 @@ namespace SimpleWeb { asio::ssl::context context; std::shared_ptr create_connection() noexcept override { - return std::make_shared(handler_runner, config.timeout, *io_service, context); + return std::make_shared(handler_runner, *io_service, context); } void connect(const std::shared_ptr &session) override { diff --git a/server_http.hpp b/server_http.hpp index 86ab40f..9afaee2 100644 --- a/server_http.hpp +++ b/server_http.hpp @@ -74,9 +74,7 @@ namespace SimpleWeb { void send_from_queue() REQUIRES(send_queue_mutex) { auto self = this->shared_from_this(); - session->connection->set_timeout(timeout_content); asio::async_write(*self->session->connection->socket, *send_queue.begin()->first, [self](const error_code &ec, std::size_t /*bytes_transferred*/) { - self->session->connection->set_timeout(self->timeout_content); // Set timeout for next send auto lock = self->session->connection->handler_runner->continue_lock(); if(!lock) return; @@ -111,10 +109,8 @@ namespace SimpleWeb { } void send_on_delete(const std::function &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, std::size_t /*bytes_transferred*/) { - self->session->connection->cancel_timeout(); auto lock = self->session->connection->handler_runner->continue_lock(); if(!lock) return; @@ -338,9 +334,9 @@ namespace SimpleWeb { /// If io_service is not set, number of threads that the server will use when start() is called. /// Defaults to 1 thread. std::size_t thread_pool_size = 1; - /// Timeout on request handling. Defaults to 5 seconds. + /// Timeout on request completion. Defaults to 5 seconds. long timeout_request = 5; - /// Timeout on content handling. Defaults to 300 seconds. + /// Timeout on request/response content completion. 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. @@ -522,7 +518,7 @@ namespace SimpleWeb { void read(const std::shared_ptr &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, std::size_t bytes_transferred) { - session->connection->cancel_timeout(); + session->connection->set_timeout(config.timeout_content); auto lock = session->connection->handler_runner->continue_lock(); if(!lock) return; @@ -562,9 +558,7 @@ namespace SimpleWeb { return; } 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, std::size_t /*bytes_transferred*/) { - session->connection->cancel_timeout(); auto lock = session->connection->handler_runner->continue_lock(); if(!lock) return; @@ -599,9 +593,7 @@ namespace SimpleWeb { } void read_chunked_transfer_encoded(const std::shared_ptr &session, const std::shared_ptr &chunk_size_streambuf) { - session->connection->set_timeout(config.timeout_content); asio::async_read_until(*session->connection->socket, *chunk_size_streambuf, "\r\n", [this, session, chunk_size_streambuf](const error_code &ec, size_t bytes_transferred) { - session->connection->cancel_timeout(); auto lock = session->connection->handler_runner->continue_lock(); if(!lock) return; @@ -641,9 +633,7 @@ namespace SimpleWeb { } if((2 + chunk_size) > num_additional_bytes) { - session->connection->set_timeout(config.timeout_content); asio::async_read(*session->connection->socket, session->request->streambuf, asio::transfer_exactly(2 + chunk_size - num_additional_bytes), [this, session, chunk_size_streambuf, chunk_size](const error_code &ec, size_t /*bytes_transferred*/) { - session->connection->cancel_timeout(); auto lock = session->connection->handler_runner->continue_lock(); if(!lock) return; @@ -716,10 +706,10 @@ namespace SimpleWeb { void write(const std::shared_ptr &session, std::function::Response>, std::shared_ptr::Request>)> &resource_function) { - session->connection->set_timeout(config.timeout_content); // Set timeout for first send auto response = std::shared_ptr(new Response(session, config.timeout_content), [this](Response *response_ptr) { auto response = std::shared_ptr(response_ptr); response->send_on_delete([this, response](const error_code &ec) { + response->session->connection->cancel_timeout(); if(!ec) { if(response->close_connection_after_response) return;