mirror of
https://github.com/CrowCpp/Crow.git
synced 2024-06-07 21:10:44 +00:00
Fix memory leaks caused from the http_connection
This memory leak was caused from the fact that we were creating a raw pointers in the do_accept method of the http_server. The initial connection was never released, but all subsequent connection were released without problem. So this commit introduces shared_ptr to manage all the connection and release the memory when the connection is not needed any more. Signed-off-by: Vasileios Anagnostopoulos <anagnwstopoulos@hotmail.com>
This commit is contained in:
parent
3b81e16614
commit
d5e0523602
@ -6,6 +6,7 @@
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "crow/http_parser_merged.h"
|
||||
#include "crow/common.h"
|
||||
@ -31,7 +32,7 @@ namespace crow
|
||||
|
||||
/// An HTTP connection.
|
||||
template<typename Adaptor, typename Handler, typename... Middlewares>
|
||||
class Connection
|
||||
class Connection: public std::enable_shared_from_this<Connection<Adaptor, Handler, Middlewares...>>
|
||||
{
|
||||
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,18 @@ namespace crow
|
||||
|
||||
void start()
|
||||
{
|
||||
adaptor_.start([this](const asio::error_code& ec) {
|
||||
auto self = this->shared_from_this();
|
||||
adaptor_.start([self](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 +160,10 @@ 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;
|
||||
auto self = this->shared_from_this();
|
||||
res.is_alive_helper_ = [self]() -> bool {
|
||||
return self->adaptor_.is_open();
|
||||
};
|
||||
|
||||
ctx_ = detail::context<Middlewares...>();
|
||||
@ -176,8 +176,9 @@ namespace crow
|
||||
|
||||
if (!res.completed_)
|
||||
{
|
||||
res.complete_request_handler_ = [this] {
|
||||
this->complete_request();
|
||||
auto self = this->shared_from_this();
|
||||
res.complete_request_handler_ = [self] {
|
||||
self->complete_request();
|
||||
};
|
||||
need_to_call_after_handlers_ = true;
|
||||
handler_->handle(req_, res, routing_handle_result_);
|
||||
@ -199,6 +200,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 +269,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 +386,6 @@ namespace crow
|
||||
|
||||
void do_write_static()
|
||||
{
|
||||
is_writing = true;
|
||||
asio::write(adaptor_.socket(), buffers_);
|
||||
|
||||
if (res.file_info.statResult == 0)
|
||||
@ -400,13 +401,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 +432,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 +457,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 +473,15 @@ namespace crow
|
||||
|
||||
void do_read()
|
||||
{
|
||||
//auto self = this->shared_from_this();
|
||||
is_reading = true;
|
||||
auto self = this->shared_from_this();
|
||||
adaptor_.socket().async_read_some(
|
||||
asio::buffer(buffer_),
|
||||
[this](const asio::error_code& ec, std::size_t bytes_transferred) {
|
||||
[self](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 +489,52 @@ 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<http_errno>(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<http_errno>(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;
|
||||
auto self = this->shared_from_this();
|
||||
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](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 +551,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 +566,14 @@ namespace crow
|
||||
{
|
||||
cancel_deadline_timer();
|
||||
|
||||
task_id_ = task_timer_.schedule([this] {
|
||||
if (!adaptor_.is_open())
|
||||
auto self = this->shared_from_this();
|
||||
task_id_ = task_timer_.schedule([self] {
|
||||
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 +600,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_{};
|
||||
|
@ -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<Adaptor, Handler, Middlewares...>(
|
||||
auto p = std::make_shared<Connection<Adaptor, Handler, Middlewares...>>(
|
||||
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();
|
||||
});
|
||||
|
@ -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] {
|
||||
detail::middleware_call_criteria_dynamic<true> crit_bwd(rule->mw_indices_.indices());
|
||||
|
||||
detail::after_handlers_call_helper<
|
||||
|
Loading…
Reference in New Issue
Block a user