From 2a67efadf1f02671e74ada7fc84bea9009182bc7 Mon Sep 17 00:00:00 2001 From: Mikhail Svetkin Date: Thu, 4 Jun 2020 23:53:12 +0200 Subject: [PATCH] Don't destory socket and request objects while handling a request Task-number: QTBUG-84617 Change-Id: Ibf98fb329c817ae39f66e539cdb30a4194cb3b42 Reviewed-by: Mikhail Svetkin --- src/httpserver/qabstracthttpserver.cpp | 12 ++++++++++-- src/httpserver/qhttpserverrequest_p.h | 1 + src/httpserver/qhttpserverresponse.cpp | 4 ++++ tests/auto/qhttpserver/tst_qhttpserver.cpp | 20 ++++++++++++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/httpserver/qabstracthttpserver.cpp b/src/httpserver/qabstracthttpserver.cpp index 2b699ed..5a6e1e5 100644 --- a/src/httpserver/qabstracthttpserver.cpp +++ b/src/httpserver/qabstracthttpserver.cpp @@ -63,8 +63,12 @@ void QAbstractHttpServerPrivate::handleNewConnections() handleReadyRead(socket, request); }); - QObject::connect(socket, &QTcpSocket::disconnected, &QObject::deleteLater); - QObject::connect(socket, &QObject::destroyed, [request] () { + QObject::connect(socket, &QTcpSocket::disconnected, socket, [request, socket] () { + if (!request->d->handling) + socket->deleteLater(); + }); + + QObject::connect(socket, &QObject::destroyed, socket, [request] () { delete request; }); } @@ -118,8 +122,12 @@ void QAbstractHttpServerPrivate::handleReadyRead(QTcpSocket *socket, } socket->commitTransaction(); + request->d->handling = true; if (!q->handleRequest(*request, socket)) Q_EMIT q->missingHandler(*request, socket); + request->d->handling = false; + if (socket->state() == QAbstractSocket::UnconnectedState) + socket->deleteLater(); } QAbstractHttpServer::QAbstractHttpServer(QObject *parent) diff --git a/src/httpserver/qhttpserverrequest_p.h b/src/httpserver/qhttpserverrequest_p.h index ae0216b..6459cc4 100644 --- a/src/httpserver/qhttpserverrequest_p.h +++ b/src/httpserver/qhttpserverrequest_p.h @@ -88,6 +88,7 @@ public: void clear(); QHostAddress remoteAddress; + bool handling{false}; private: static http_parser_settings httpParserSettings; diff --git a/src/httpserver/qhttpserverresponse.cpp b/src/httpserver/qhttpserverresponse.cpp index 5ed230e..5bd510b 100644 --- a/src/httpserver/qhttpserverresponse.cpp +++ b/src/httpserver/qhttpserverresponse.cpp @@ -37,6 +37,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -353,6 +354,9 @@ QVector QHttpServerResponse::headers(const QByteArray &name) const void QHttpServerResponse::write(QHttpServerResponder &&responder) const { Q_D(const QHttpServerResponse); + if (responder.socket()->state() != QAbstractSocket::ConnectedState) + return; + responder.writeStatusLine(d->statusCode); for (auto &&header : d->headers) diff --git a/tests/auto/qhttpserver/tst_qhttpserver.cpp b/tests/auto/qhttpserver/tst_qhttpserver.cpp index a5feaf9..c7176ff 100644 --- a/tests/auto/qhttpserver/tst_qhttpserver.cpp +++ b/tests/auto/qhttpserver/tst_qhttpserver.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -130,6 +131,7 @@ private slots: void invalidRouterArguments(); void checkRouteLambdaCapture(); void afterRequest(); + void disconnectedInEventLoop(); private: void checkReply(QNetworkReply *reply, const QString &response); @@ -915,6 +917,24 @@ void tst_QHttpServer::checkReply(QNetworkReply *reply, const QString &response) reply->deleteLater(); }; +void tst_QHttpServer::disconnectedInEventLoop() +{ + httpserver.route("/event-loop/", [] () { + QEventLoop loop; + QTimer::singleShot(1000, &loop, &QEventLoop::quit); + loop.exec(); + return QHttpServerResponse::StatusCode::Ok; + }); + + const QUrl requestUrl(urlBase.arg("/event-loop/")); + auto reply = networkAccessManager.get(QNetworkRequest(requestUrl)); + QTimer::singleShot(500, reply, &QNetworkReply::abort); // cancel connection + QEventLoop loop; + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + reply->deleteLater(); +} + QT_END_NAMESPACE Q_DECLARE_METATYPE(CustomArg);