Skip to content

Commit

Permalink
Fix crash for passing lambda with captures to QHttpServer::route
Browse files Browse the repository at this point in the history
QHttpServer::route accepted the lambda by universal reference, but did
not pass it to QHttpServerRouter::addRule by std::forward.

We can not initialize lambda captures with C++11.
So we always need to copy the lambda by value.

Task-number: QTBUG-74882
Change-Id: I3e2dc6003624414d0ff45ba2e2f1af472e219ff1
Reviewed-by: Mårten Nordheim <[email protected]>
  • Loading branch information
msvetkin committed May 15, 2019
1 parent 3a811fc commit e2c6356
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 15 deletions.
16 changes: 9 additions & 7 deletions src/httpserver/qhttpserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,17 @@ class Q_HTTPSERVER_EXPORT QHttpServer final : public QAbstractHttpServer
template<typename Rule, typename ViewHandler, typename ViewTraits, typename ... Args>
bool routeImpl(Args &&...args, ViewHandler &&viewHandler)
{
return router()->addRule<ViewHandler, ViewTraits>(
new Rule(std::forward<Args>(args)..., [this, &viewHandler] (
QRegularExpressionMatch &match,
const QHttpServerRequest &request,
QTcpSocket *socket) {
auto routerHandler = [this, viewHandler] (
QRegularExpressionMatch &match,
const QHttpServerRequest &request,
QTcpSocket *socket) mutable {
auto boundViewHandler = router()->bindCaptured<ViewHandler, ViewTraits>(
std::forward<ViewHandler>(viewHandler), match);
std::move(viewHandler), match);
responseImpl<ViewTraits>(boundViewHandler, request, socket);
}));
};

return router()->addRule<ViewHandler, ViewTraits>(
new Rule(std::forward<Args>(args)..., std::move(routerHandler)));
}

template<typename ViewTraits, typename T>
Expand Down
44 changes: 36 additions & 8 deletions tests/auto/qhttpserver/tst_qhttpserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ private slots:
void routeDelete_data();
void routeDelete();
void invalidRouterArguments();
void checkRouteLambdaCapture();

private:
void checkReply(QNetworkReply *reply, const QString &response);

private:
QHttpServer httpserver;
Expand Down Expand Up @@ -377,14 +381,6 @@ void tst_QHttpServer::routeKeepAlive()
QNetworkRequest request(urlBase.arg("/keep-alive"));
request.setRawHeader(QByteArray("Connection"), QByteArray("keep-alive"));

auto checkReply = [] (QNetworkReply *reply, const QString &response) {
QTRY_VERIFY(reply->isFinished());

QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), "text/plain");
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QCOMPARE(reply->readAll(), response);
};

checkReply(networkAccessManager.get(request),
QString("header: , query: , body: , method: %1")
.arg(static_cast<int>(QHttpServerRequest::Method::Get)));
Expand Down Expand Up @@ -564,6 +560,38 @@ void tst_QHttpServer::invalidRouterArguments()
false);
}

void tst_QHttpServer::checkRouteLambdaCapture()
{
httpserver.route("/capture-this/", [this] () {
return urlBase;
});

QString msg = urlBase + "/pod";
httpserver.route("/capture-non-pod-data/", [&msg] () {
return msg;
});

QNetworkAccessManager networkAccessManager;
checkReply(networkAccessManager.get(QNetworkRequest(QUrl(urlBase.arg("/capture-this/")))),
urlBase);
if (QTest::currentTestFailed())
return;

checkReply(networkAccessManager.get(
QNetworkRequest(QUrl(urlBase.arg("/capture-non-pod-data/")))),
msg);
if (QTest::currentTestFailed())
return;
}

void tst_QHttpServer::checkReply(QNetworkReply *reply, const QString &response) {
QTRY_VERIFY(reply->isFinished());

QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), "text/plain");
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QCOMPARE(reply->readAll(), response);
};

QT_END_NAMESPACE

Q_DECLARE_METATYPE(CustomArg);
Expand Down

0 comments on commit e2c6356

Please sign in to comment.