diff --git a/CMakeLists.txt b/CMakeLists.txt index 8534e90b4..53aa01cd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) endif() # Set required C++ standard -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED TRUE) # Default to build type "Release" unless tests are being built diff --git a/include/crow/http_connection.h b/include/crow/http_connection.h index 7f8a2928e..e3abae8fe 100644 --- a/include/crow/http_connection.h +++ b/include/crow/http_connection.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "crow/http_parser_merged.h" #include "crow/common.h" @@ -31,7 +32,7 @@ namespace crow /// An HTTP connection. template - class Connection + class Connection: public std::enable_shared_from_this> { friend struct crow::response; @@ -64,8 +65,6 @@ namespace crow ~Connection() { - res.complete_request_handler_ = nullptr; - cancel_deadline_timer(); #ifdef CROW_ENABLE_DEBUG connectionCount--; CROW_LOG_DEBUG << "Connection (" << this << ") freed, total: " << connectionCount; @@ -80,18 +79,17 @@ namespace crow void start() { - adaptor_.start([this](const asio::error_code& ec) { + adaptor_.start([self = this->shared_from_this()](const asio::error_code& ec) { if (!ec) { - start_deadline(); - parser_.clear(); + self->start_deadline(); + self->parser_.clear(); - do_read(); + self->do_read(); } else { CROW_LOG_ERROR << "Could not start adaptor: " << ec.message(); - check_destroy(); } }); } @@ -161,9 +159,9 @@ namespace crow need_to_call_after_handlers_ = false; if (!is_invalid_request) { - res.complete_request_handler_ = [] {}; - res.is_alive_helper_ = [this]() -> bool { - return adaptor_.is_open(); + res.complete_request_handler_ = nullptr; + res.is_alive_helper_ = [self = this->shared_from_this()]() -> bool { + return self->adaptor_.is_open(); }; ctx_ = detail::context(); @@ -176,8 +174,8 @@ namespace crow if (!res.completed_) { - res.complete_request_handler_ = [this] { - this->complete_request(); + res.complete_request_handler_ = [self = this->shared_from_this()] { + self->complete_request(); }; need_to_call_after_handlers_ = true; handler_->handle(req_, res, routing_handle_result_); @@ -199,6 +197,7 @@ namespace crow void complete_request() { CROW_LOG_INFO << "Response: " << this << ' ' << req_.raw_url << ' ' << res.code << ' ' << close_connection_; + res.is_alive_helper_ = nullptr; if (need_to_call_after_handlers_) { @@ -267,8 +266,8 @@ namespace crow private: void prepare_buffers() { - //auto self = this->shared_from_this(); res.complete_request_handler_ = nullptr; + res.is_alive_helper_ = nullptr; if (!adaptor_.is_open()) { @@ -384,7 +383,6 @@ namespace crow void do_write_static() { - is_writing = true; asio::write(adaptor_.socket(), buffers_); if (res.file_info.statResult == 0) @@ -400,13 +398,11 @@ namespace crow is.read(buf, sizeof(buf)); } } - is_writing = false; if (close_connection_) { adaptor_.shutdown_readwrite(); adaptor_.close(); CROW_LOG_DEBUG << this << " from write (static)"; - check_destroy(); } res.end(); @@ -433,7 +429,6 @@ namespace crow } else { - is_writing = true; asio::write(adaptor_.socket(), buffers_); // Write the response start / headers cancel_deadline_timer(); if (res.body.length() > 0) @@ -459,13 +454,11 @@ namespace crow buffers.push_back(asio::buffer(buf)); do_write_sync(buffers); } - is_writing = false; if (close_connection_) { adaptor_.shutdown_readwrite(); adaptor_.close(); CROW_LOG_DEBUG << this << " from write (res_stream)"; - check_destroy(); } res.end(); @@ -477,16 +470,14 @@ namespace crow void do_read() { - //auto self = this->shared_from_this(); - is_reading = true; adaptor_.socket().async_read_some( asio::buffer(buffer_), - [this](const asio::error_code& ec, std::size_t bytes_transferred) { + [self = this->shared_from_this()](const asio::error_code& ec, std::size_t bytes_transferred) { bool error_while_reading = true; if (!ec) { - bool ret = parser_.feed(buffer_.data(), bytes_transferred); - if (ret && adaptor_.is_open()) + bool ret = self->parser_.feed(self->buffer_.data(), bytes_transferred); + if (ret && self->adaptor_.is_open()) { error_while_reading = false; } @@ -494,60 +485,51 @@ namespace crow if (error_while_reading) { - cancel_deadline_timer(); - parser_.done(); - adaptor_.shutdown_read(); - adaptor_.close(); - is_reading = false; - CROW_LOG_DEBUG << this << " from read(1) with description: \"" << http_errno_description(static_cast(parser_.http_errno)) << '\"'; - check_destroy(); + self->cancel_deadline_timer(); + self->parser_.done(); + self->adaptor_.shutdown_read(); + self->adaptor_.close(); + CROW_LOG_DEBUG << self << " from read(1) with description: \"" << http_errno_description(static_cast(self->parser_.http_errno)) << '\"'; } - else if (close_connection_) + else if (self->close_connection_) { - cancel_deadline_timer(); - parser_.done(); - is_reading = false; - check_destroy(); + self->cancel_deadline_timer(); + self->parser_.done(); // adaptor will close after write } - else if (!need_to_call_after_handlers_) + else if (!self->need_to_call_after_handlers_) { - start_deadline(); - do_read(); + self->start_deadline(); + self->do_read(); } else { // res will be completed later by user - need_to_start_read_after_complete_ = true; + self->need_to_start_read_after_complete_ = true; } }); } void do_write() { - //auto self = this->shared_from_this(); - is_writing = true; asio::async_write( adaptor_.socket(), buffers_, - [&](const asio::error_code& ec, std::size_t /*bytes_transferred*/) { - is_writing = false; - res.clear(); - res_body_copy_.clear(); - parser_.clear(); + [self = this->shared_from_this()](const asio::error_code& ec, std::size_t /*bytes_transferred*/) { + self->res.clear(); + self->res_body_copy_.clear(); + self->parser_.clear(); if (!ec) { - if (close_connection_) + if (self->close_connection_) { - adaptor_.shutdown_write(); - adaptor_.close(); - CROW_LOG_DEBUG << this << " from write(1)"; - check_destroy(); + self->adaptor_.shutdown_write(); + self->adaptor_.close(); + CROW_LOG_DEBUG << self << " from write(1)"; } } else { - CROW_LOG_DEBUG << this << " from write(2)"; - check_destroy(); + CROW_LOG_DEBUG << self << " from write(2)"; } }); } @@ -564,23 +546,11 @@ namespace crow { CROW_LOG_ERROR << ec << " - happened while sending buffers"; CROW_LOG_DEBUG << this << " from write (sync)(2)"; - check_destroy(); return true; } }); } - void check_destroy() - { - CROW_LOG_DEBUG << this << " is_reading " << is_reading << " is_writing " << is_writing; - if (!is_reading && !is_writing) - { - queue_length_--; - CROW_LOG_DEBUG << this << " delete (idle) (queue length: " << queue_length_ << ')'; - delete this; - } - } - void cancel_deadline_timer() { CROW_LOG_DEBUG << this << " timer cancelled: " << &task_timer_ << ' ' << task_id_; @@ -591,13 +561,13 @@ namespace crow { cancel_deadline_timer(); - task_id_ = task_timer_.schedule([this] { - if (!adaptor_.is_open()) + task_id_ = task_timer_.schedule([self = this->shared_from_this()] { + if (!self->adaptor_.is_open()) { return; } - adaptor_.shutdown_readwrite(); - adaptor_.close(); + self->adaptor_.shutdown_readwrite(); + self->adaptor_.close(); }); CROW_LOG_DEBUG << this << " timer added: " << &task_timer_ << ' ' << task_id_; } @@ -624,8 +594,6 @@ namespace crow detail::task_timer::identifier_type task_id_{}; - bool is_reading{}; - bool is_writing{}; bool need_to_call_after_handlers_{}; bool need_to_start_read_after_complete_{}; bool add_keep_alive_{}; diff --git a/include/crow/http_server.h b/include/crow/http_server.h index 16be4a329..85e88080a 100644 --- a/include/crow/http_server.h +++ b/include/crow/http_server.h @@ -221,7 +221,7 @@ namespace crow task_queue_length_pool_[service_idx]++; CROW_LOG_DEBUG << &is << " {" << service_idx << "} queue length: " << task_queue_length_pool_[service_idx]; - auto p = new Connection( + auto p = std::make_shared>( is, handler_, server_name_, middlewares_, get_cached_date_str_pool_[service_idx], *task_timer_pool_[service_idx], adaptor_ctx_, task_queue_length_pool_[service_idx]); @@ -239,7 +239,6 @@ namespace crow { task_queue_length_pool_[service_idx]--; CROW_LOG_DEBUG << &is << " {" << service_idx << "} queue length: " << task_queue_length_pool_[service_idx]; - delete p; } do_accept(); }); diff --git a/include/crow/routing.h b/include/crow/routing.h index c06575fa3..c0d617d76 100644 --- a/include/crow/routing.h +++ b/include/crow/routing.h @@ -1718,7 +1718,7 @@ namespace crow return; } - res.complete_request_handler_ = [&rule, &ctx, &container, &req, &res, &glob_completion_handler] { + res.complete_request_handler_ = [&rule, &ctx, &container, &req, &res, glob_completion_handler = std::move(glob_completion_handler)] { detail::middleware_call_criteria_dynamic crit_bwd(rule->mw_indices_.indices()); detail::after_handlers_call_helper<