diff --git a/client_http.hpp b/client_http.hpp index ee36ac2..1e21d29 100644 --- a/client_http.hpp +++ b/client_http.hpp @@ -126,19 +126,11 @@ namespace SimpleWeb { long timeout; std::unique_ptr socket; // Socket must be unique_ptr since asio::ssl::stream is not movable - std::mutex socket_close_mutex; bool in_use = false; bool attempt_reconnect = true; std::unique_ptr timer; - void close() { - error_code ec; - std::unique_lock 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 = 0) { if(seconds == 0) seconds = timeout; @@ -150,8 +142,10 @@ namespace SimpleWeb { timer->expires_from_now(boost::posix_time::seconds(seconds)); auto self = this->shared_from_this(); timer->async_wait([self](const error_code &ec) { - if(!ec) - self->close(); + if(!ec) { + error_code ec; + self->socket->lowest_layer().cancel(ec); + } }); } @@ -176,7 +170,7 @@ namespace SimpleWeb { std::shared_ptr connection; std::unique_ptr request_buffer; std::shared_ptr response; - std::function callback; + std::function &, const error_code &)> callback; }; public: @@ -252,10 +246,9 @@ namespace SimpleWeb { void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap &header, std::function, const error_code &)> &&request_callback_) { auto session = std::make_shared(get_connection(), create_request_header(method, path, header)); - auto connection = session->connection; auto response = session->response; auto request_callback = std::make_shared, const error_code &)>>(std::move(request_callback_)); - session->callback = [this, connection, response, request_callback](const error_code &ec) { + session->callback = [this, response, request_callback](const std::shared_ptr &connection, const error_code &ec) { { std::unique_lock lock(this->connections_mutex); connection->in_use = false; @@ -263,7 +256,9 @@ namespace SimpleWeb { // Remove unused connections, but keep one open for HTTP persistent connection: size_t unused_connections = 0; for(auto it = this->connections.begin(); it != this->connections.end();) { - if((*it)->in_use) + if(ec && connection == *it) + it = this->connections.erase(it); + else if((*it)->in_use) ++it; else { ++unused_connections; @@ -310,10 +305,9 @@ namespace SimpleWeb { void request(const std::string &method, const std::string &path, std::istream &content, const CaseInsensitiveMultimap &header, std::function, const error_code &)> &&request_callback_) { auto session = std::make_shared(get_connection(), create_request_header(method, path, header)); - auto connection = session->connection; auto response = session->response; auto request_callback = std::make_shared, const error_code &)>>(std::move(request_callback_)); - session->callback = [this, connection, response, request_callback](const error_code &ec) { + session->callback = [this, response, request_callback](const std::shared_ptr &connection, const error_code &ec) { { std::unique_lock lock(this->connections_mutex); connection->in_use = false; @@ -321,7 +315,9 @@ namespace SimpleWeb { // Remove unused connections, but keep one open for HTTP persistent connection: size_t unused_connections = 0; for(auto it = this->connections.begin(); it != this->connections.end();) { - if((*it)->in_use) + if(ec && connection == *it) + it = this->connections.erase(it); + else if((*it)->in_use) ++it; else { ++unused_connections; @@ -360,8 +356,8 @@ namespace SimpleWeb { void stop() { std::unique_lock lock(connections_mutex); for(auto it = connections.begin(); it != connections.end();) { - (*it)->attempt_reconnect = false; - (*it)->close(); + error_code ec; + (*it)->socket->lowest_layer().cancel(ec); it = connections.erase(it); } } @@ -478,7 +474,7 @@ namespace SimpleWeb { if(!ec) this->read(session); else - this->close(session, ec); + session->callback(session->connection, ec); }); } @@ -507,13 +503,13 @@ namespace SimpleWeb { if(cancel_pair.first) return; if(!ec) - session->callback(ec); + session->callback(session->connection, ec); else - this->close(session, ec); + session->callback(session->connection, ec); }); } else - session->callback(ec); + session->callback(session->connection, ec); } else if((header_it = session->response->header.find("Transfer-Encoding")) != session->response->header.end() && header_it->second == "chunked") { auto tmp_streambuf = std::make_shared(); @@ -527,21 +523,20 @@ namespace SimpleWeb { if(cancel_pair.first) return; if(!ec) - session->callback(ec); + session->callback(session->connection, ec); else - close(session, ec == asio::error::eof ? error_code() : ec); + session->callback(session->connection, ec == asio::error::eof ? error_code() : ec); }); } else - session->callback(ec); + session->callback(session->connection, ec); } else { - if(session->connection->attempt_reconnect) { + if(session->connection->attempt_reconnect && ec != asio::error::operation_aborted) { std::unique_lock lock(connections_mutex); auto it = connections.find(session->connection); if(it != connections.end()) { connections.erase(it); - session->connection->close(); session->connection = create_connection(); session->connection->attempt_reconnect = false; session->connection->in_use = true; @@ -549,10 +544,10 @@ namespace SimpleWeb { this->connect(session); } else - this->close(session, ec); + session->callback(session->connection, ec); } else - this->close(session, ec); + session->callback(session->connection, ec); } }); } @@ -591,7 +586,7 @@ namespace SimpleWeb { std::ostream response_stream(&session->response->content_buffer); response_stream << tmp_stream.rdbuf(); error_code ec; - session->callback(ec); + session->callback(session->connection, ec); } }; @@ -605,25 +600,16 @@ namespace SimpleWeb { if(!ec) post_process(); else - this->close(session, ec); + session->callback(session->connection, ec); }); } else post_process(); } else - this->close(session, ec); + session->callback(session->connection, ec); }); } - - void close(const std::shared_ptr &session, const error_code &ec) { - session->connection->close(); - { - std::lock_guard lock(connections_mutex); - connections.erase(session->connection); - } - session->callback(ec); - } }; template @@ -664,11 +650,11 @@ namespace SimpleWeb { this->write(session); } else - this->close(session, ec); + session->callback(session->connection, ec); }); } else - this->close(session, ec); + session->callback(session->connection, ec); }); } else diff --git a/client_https.hpp b/client_https.hpp index cdb1c20..b58788a 100644 --- a/client_https.hpp +++ b/client_https.hpp @@ -86,27 +86,27 @@ namespace SimpleWeb { if(!ec) { response->parse_header(); if(response->status_code.empty() || response->status_code.compare(0, 3, "200") != 0) - this->close(session, make_error_code::make_error_code(errc::permission_denied)); + session->callback(session->connection, make_error_code::make_error_code(errc::permission_denied)); else this->handshake(session); } else - this->close(session, ec); + session->callback(session->connection, ec); }); } else - this->close(session, ec); + session->callback(session->connection, ec); }); } else this->handshake(session); } else - this->close(session, ec); + session->callback(session->connection, ec); }); } else - this->close(session, ec); + session->callback(session->connection, ec); }); } else @@ -123,7 +123,7 @@ namespace SimpleWeb { if(!ec) this->write(session); else - this->close(session, ec); + session->callback(session->connection, ec); }); } };