summaryrefslogtreecommitdiffstats
path: root/http/http_connection.h
diff options
context:
space:
mode:
Diffstat (limited to 'http/http_connection.h')
-rw-r--r--http/http_connection.h105
1 files changed, 50 insertions, 55 deletions
diff --git a/http/http_connection.h b/http/http_connection.h
index 7d24fe7..4ef3bc6 100644
--- a/http/http_connection.h
+++ b/http/http_connection.h
@@ -248,7 +248,8 @@ constexpr unsigned int httpReqBodyLimit =
1024 * 1024 * BMCWEB_HTTP_REQ_BODY_LIMIT_MB;
template <typename Adaptor, typename Handler, typename... Middlewares>
-class Connection
+class Connection : public std::enable_shared_from_this<
+ Connection<Adaptor, Handler, Middlewares...>>
{
public:
Connection(boost::asio::io_context& ioService, Handler* handlerIn,
@@ -474,16 +475,15 @@ class Connection
boost::beast::ssl_stream<
boost::asio::ip::tcp::socket>>)
{
- adaptor.async_handshake(
- boost::asio::ssl::stream_base::server,
- [this](const boost::system::error_code& ec) {
- if (ec)
- {
- checkDestroy();
- return;
- }
- doReadHeaders();
- });
+ adaptor.async_handshake(boost::asio::ssl::stream_base::server,
+ [this, self(shared_from_this())](
+ const boost::system::error_code& ec) {
+ if (ec)
+ {
+ return;
+ }
+ doReadHeaders();
+ });
}
else
{
@@ -561,18 +561,21 @@ class Connection
if (!res.completed)
{
+ needToCallAfterHandlers = true;
+ res.completeRequestHandler = [self(shared_from_this())] {
+ self->completeRequest();
+ };
if (req->isUpgrade() &&
boost::iequals(
req->getHeaderValue(boost::beast::http::field::upgrade),
"websocket"))
{
handler->handleUpgrade(*req, res, std::move(adaptor));
+ // delete lambda with self shared_ptr
+ // to enable connection destruction
+ res.completeRequestHandler = nullptr;
return;
}
- res.completeRequestHandler = [this] {
- this->completeRequest();
- };
- needToCallAfterHandlers = true;
handler->handle(*req, res);
}
else
@@ -638,15 +641,16 @@ class Connection
*middlewares, ctx, *req, res);
}
- // auto self = this->shared_from_this();
- res.completeRequestHandler = res.completeRequestHandler = [] {};
-
if (!isAlive())
{
// BMCWEB_LOG_DEBUG << this << " delete (socket is closed) " <<
// isReading
// << ' ' << isWriting;
// delete this;
+
+ // delete lambda with self shared_ptr
+ // to enable connection destruction
+ res.completeRequestHandler = nullptr;
return;
}
if (res.body().empty() && !res.jsonValue.empty())
@@ -683,21 +687,23 @@ class Connection
res.keepAlive(req->keepAlive());
doWrite();
+
+ // delete lambda with self shared_ptr
+ // to enable connection destruction
+ res.completeRequestHandler = nullptr;
}
private:
void doReadHeaders()
{
- // auto self = this->shared_from_this();
- isReading = true;
BMCWEB_LOG_DEBUG << this << " doReadHeaders";
// Clean up any previous Connection.
boost::beast::http::async_read_header(
adaptor, buffer, *parser,
- [this](const boost::system::error_code& ec,
- std::size_t bytes_transferred) {
- isReading = false;
+ [this,
+ self(shared_from_this())](const boost::system::error_code& ec,
+ std::size_t bytes_transferred) {
BMCWEB_LOG_ERROR << this << " async_read_header "
<< bytes_transferred << " Bytes";
bool errorWhileReading = false;
@@ -722,7 +728,6 @@ class Connection
cancelDeadlineTimer();
close();
BMCWEB_LOG_DEBUG << this << " from read(1)";
- checkDestroy();
return;
}
@@ -740,17 +745,15 @@ class Connection
void doRead()
{
- // auto self = this->shared_from_this();
- isReading = true;
BMCWEB_LOG_DEBUG << this << " doRead";
boost::beast::http::async_read(
adaptor, buffer, *parser,
- [this](const boost::system::error_code& ec,
- std::size_t bytes_transferred) {
+ [this,
+ self(shared_from_this())](const boost::system::error_code& ec,
+ std::size_t bytes_transferred) {
BMCWEB_LOG_DEBUG << this << " async_read " << bytes_transferred
<< " Bytes";
- isReading = false;
bool errorWhileReading = false;
if (ec)
@@ -771,7 +774,6 @@ class Connection
cancelDeadlineTimer();
close();
BMCWEB_LOG_DEBUG << this << " from read(1)";
- checkDestroy();
return;
}
handle();
@@ -780,30 +782,26 @@ class Connection
void doWrite()
{
- // auto self = this->shared_from_this();
- isWriting = true;
BMCWEB_LOG_DEBUG << this << " doWrite";
res.preparePayload();
serializer.emplace(*res.stringResponse);
boost::beast::http::async_write(
adaptor, *serializer,
- [&](const boost::system::error_code& ec,
- std::size_t bytes_transferred) {
- isWriting = false;
+ [this,
+ self(shared_from_this())](const boost::system::error_code& ec,
+ std::size_t bytes_transferred) {
BMCWEB_LOG_DEBUG << this << " async_write " << bytes_transferred
<< " bytes";
if (ec)
{
BMCWEB_LOG_DEBUG << this << " from write(2)";
- checkDestroy();
return;
}
if (!res.keepAlive())
{
close();
BMCWEB_LOG_DEBUG << this << " from write(1)";
- checkDestroy();
return;
}
@@ -820,29 +818,25 @@ class Connection
});
}
- void checkDestroy()
+ void cancelDeadlineTimer()
{
- BMCWEB_LOG_DEBUG << this << " isReading " << isReading << " isWriting "
- << isWriting;
- if (!isReading && !isWriting)
+ if (timerCancelKey)
{
- BMCWEB_LOG_DEBUG << this << " delete (idle) ";
- delete this;
+ BMCWEB_LOG_DEBUG << this << " timer cancelled: " << &timerQueue
+ << ' ' << *timerCancelKey;
+ timerQueue.cancel(*timerCancelKey);
+ timerCancelKey.reset();
}
}
- void cancelDeadlineTimer()
- {
- BMCWEB_LOG_DEBUG << this << " timer cancelled: " << &timerQueue << ' '
- << timerCancelKey;
- timerQueue.cancel(timerCancelKey);
- }
-
void startDeadline()
{
cancelDeadlineTimer();
- timerCancelKey = timerQueue.add([this] {
+ timerCancelKey = timerQueue.add([this, self(shared_from_this())] {
+ // Mark timer as not active to avoid canceling it during
+ // Connection destructor which leads to double free issue
+ timerCancelKey.reset();
if (!isAlive())
{
return;
@@ -850,7 +844,7 @@ class Connection
close();
});
BMCWEB_LOG_DEBUG << this << " timer added: " << &timerQueue << ' '
- << timerCancelKey;
+ << *timerCancelKey;
}
private:
@@ -877,10 +871,8 @@ class Connection
const std::string& serverName;
- size_t timerCancelKey = 0;
+ std::optional<size_t> timerCancelKey;
- bool isReading{};
- bool isWriting{};
bool needToCallAfterHandlers{};
bool needToStartReadAfterComplete{};
@@ -889,5 +881,8 @@ class Connection
std::function<std::string()>& getCachedDateStr;
detail::TimerQueue& timerQueue;
+
+ using std::enable_shared_from_this<
+ Connection<Adaptor, Handler, Middlewares...>>::shared_from_this;
};
} // namespace crow
OpenPOWER on IntegriCloud