mirror of
https://github.com/QuasarApp/qthttpserver.git
synced 2025-04-26 18:34:31 +00:00
Introduce QHttpServerFutureResponse
Provide simple API for asynchronous resoponses Change-Id: Ic0c92cce95751dc8f9d6b0dfa96e39019f5f5e9e Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
2a67efadf1
commit
e49b9a111a
@ -47,3 +47,10 @@ qt_extend_target(HttpServer CONDITION QT_FEATURE_ssl
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::SslServer
|
||||
)
|
||||
|
||||
qt_extend_target(HttpServer CONDITION TARGET Qt::Concurrent
|
||||
SOURCES
|
||||
qhttpserverfutureresponse.cpp qhttpserverfutureresponse.h
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Concurrent
|
||||
)
|
||||
|
@ -37,6 +37,12 @@ SOURCES += \
|
||||
qhttpserverrouter.cpp \
|
||||
qhttpserverrouterrule.cpp
|
||||
|
||||
qtHaveModule(concurrent) {
|
||||
QT += concurrent
|
||||
HEADERS += qhttpserverfutureresponse.h
|
||||
SOURCES += qhttpserverfutureresponse.cpp
|
||||
}
|
||||
|
||||
include(../3rdparty/http-parser.pri)
|
||||
|
||||
load(qt_module)
|
||||
|
@ -59,6 +59,15 @@ class Q_HTTPSERVER_EXPORT QHttpServer final : public QAbstractHttpServer
|
||||
using Type = typename VariadicTypeAt<sizeof ... (Ts) - 1, Ts...>::Type;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
using ResponseType =
|
||||
typename std::conditional<
|
||||
std::is_base_of<QHttpServerResponse, T>::value,
|
||||
T,
|
||||
QHttpServerResponse
|
||||
>::type;
|
||||
|
||||
public:
|
||||
explicit QHttpServer(QObject *parent = nullptr);
|
||||
~QHttpServer();
|
||||
@ -160,7 +169,16 @@ private:
|
||||
const QHttpServerRequest &request,
|
||||
QTcpSocket *socket)
|
||||
{
|
||||
QHttpServerResponse response(boundViewHandler());
|
||||
ResponseType<typename ViewTraits::ReturnType> response(boundViewHandler());
|
||||
sendResponse(std::move(response), request, socket);
|
||||
}
|
||||
|
||||
template<typename ViewTraits, typename T>
|
||||
typename std::enable_if<ViewTraits::Arguments::Last::IsRequest::Value &&
|
||||
ViewTraits::Arguments::PlaceholdersCount == 1, void>::type
|
||||
responseImpl(T &boundViewHandler, const QHttpServerRequest &request, QTcpSocket *socket)
|
||||
{
|
||||
ResponseType<typename ViewTraits::ReturnType> response(boundViewHandler(request));
|
||||
sendResponse(std::move(response), request, socket);
|
||||
}
|
||||
|
||||
@ -172,15 +190,6 @@ private:
|
||||
boundViewHandler(makeResponder(request, socket), request);
|
||||
}
|
||||
|
||||
template<typename ViewTraits, typename T>
|
||||
typename std::enable_if<ViewTraits::Arguments::Last::IsRequest::Value &&
|
||||
ViewTraits::Arguments::PlaceholdersCount == 1, void>::type
|
||||
responseImpl(T &boundViewHandler, const QHttpServerRequest &request, QTcpSocket *socket)
|
||||
{
|
||||
QHttpServerResponse response(boundViewHandler(request));
|
||||
sendResponse(std::move(response), request, socket);
|
||||
}
|
||||
|
||||
template<typename ViewTraits, typename T>
|
||||
typename std::enable_if<ViewTraits::Arguments::Last::IsResponder::Value &&
|
||||
ViewTraits::Arguments::PlaceholdersCount == 2, void>::type
|
||||
|
139
src/httpserver/qhttpserverfutureresponse.cpp
Normal file
139
src/httpserver/qhttpserverfutureresponse.cpp
Normal file
@ -0,0 +1,139 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 Mikhail Svetkin <mikhail.svetkin@gmail.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtHttpServer module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 or (at your option) any later version
|
||||
** approved by the KDE Free Qt Foundation. The licenses are as published by
|
||||
** the Free Software Foundation and appearing in the file LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qhttpserverfutureresponse.h"
|
||||
|
||||
#include <QtCore/qfuture.h>
|
||||
#include <QtCore/qfuturewatcher.h>
|
||||
|
||||
#include <QtNetwork/qtcpsocket.h>
|
||||
|
||||
#include <QtHttpServer/qhttpserverresponder.h>
|
||||
|
||||
#include <private/qhttpserverresponse_p.h>
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*!
|
||||
\class QHttpServerFutureResponse
|
||||
\brief QHttpServerFutureResponse is a simplified API for asynchronous responses.
|
||||
|
||||
\code
|
||||
|
||||
QHttpServer server;
|
||||
|
||||
server.route("/feature/", [] (int id) -> QHttpServerFutureResponse {
|
||||
auto future = QtConcurrent::run([] () {
|
||||
return QHttpServerResponse("the future is coming");
|
||||
});
|
||||
|
||||
return future;
|
||||
});
|
||||
server.listen();
|
||||
|
||||
\endcode
|
||||
*/
|
||||
|
||||
struct QResponseWatcher : public QFutureWatcher<QHttpServerResponse>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QResponseWatcher(QHttpServerResponder &&_responder)
|
||||
: QFutureWatcher<QHttpServerResponse>(),
|
||||
responder(std::move(_responder)) {
|
||||
}
|
||||
|
||||
QHttpServerResponder responder;
|
||||
};
|
||||
|
||||
class QHttpServerFutureResponsePrivate : public QHttpServerResponsePrivate
|
||||
{
|
||||
public:
|
||||
QHttpServerFutureResponsePrivate(const QFuture<QHttpServerResponse> &futureResponse)
|
||||
: QHttpServerResponsePrivate(),
|
||||
futureResp(futureResponse)
|
||||
{
|
||||
}
|
||||
|
||||
QFuture<QHttpServerResponse> futureResp;
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructs a new QHttpServerFutureResponse with the \a future response.
|
||||
*/
|
||||
QHttpServerFutureResponse::QHttpServerFutureResponse(const QFuture<QHttpServerResponse> &futureResp)
|
||||
: QHttpServerFutureResponse(new QHttpServerFutureResponsePrivate{futureResp})
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QHttpServerFutureResponse::QHttpServerFutureResponse(QHttpServerFutureResponsePrivate *d)
|
||||
: QHttpServerResponse(d)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
\reimp
|
||||
*/
|
||||
void QHttpServerFutureResponse::write(QHttpServerResponder &&responder) const
|
||||
{
|
||||
if (!d_ptr->derived) {
|
||||
QHttpServerResponse::write(std::move(responder));
|
||||
return;
|
||||
}
|
||||
|
||||
Q_D(const QHttpServerFutureResponse);
|
||||
|
||||
auto socket = responder.socket();
|
||||
auto futureWatcher = new QResponseWatcher(std::move(responder));
|
||||
|
||||
QObject::connect(socket, &QObject::destroyed,
|
||||
futureWatcher, &QObject::deleteLater);
|
||||
QObject::connect(futureWatcher, &QFutureWatcherBase::finished,
|
||||
socket,
|
||||
[futureWatcher] () mutable {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
auto resp = futureWatcher->future().d.takeResult();
|
||||
#else
|
||||
auto resp = futureWatcher->future().takeResult();
|
||||
#endif
|
||||
resp.write(std::move(futureWatcher->responder));
|
||||
futureWatcher->deleteLater();
|
||||
});
|
||||
|
||||
futureWatcher->setFuture(d->futureResp);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include "qhttpserverfutureresponse.moc"
|
184
src/httpserver/qhttpserverfutureresponse.h
Normal file
184
src/httpserver/qhttpserverfutureresponse.h
Normal file
@ -0,0 +1,184 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 Mikhail Svetkin <mikhail.svetkin@gmail.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtHttpServer module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 or (at your option) any later version
|
||||
** approved by the KDE Free Qt Foundation. The licenses are as published by
|
||||
** the Free Software Foundation and appearing in the file LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QHTTPSERVERFUTURERESPONSE_H
|
||||
#define QHTTPSERVERFUTURERESPONSE_H
|
||||
|
||||
#include <QtHttpServer/qhttpserverresponse.h>
|
||||
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qfuture.h>
|
||||
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
|
||||
template <>
|
||||
class QFutureInterface<QHttpServerResponse> : public QFutureInterfaceBase
|
||||
{
|
||||
public:
|
||||
QFutureInterface(State initialState = NoState)
|
||||
: QFutureInterfaceBase(initialState)
|
||||
{
|
||||
refT();
|
||||
}
|
||||
QFutureInterface(const QFutureInterface &other)
|
||||
: QFutureInterfaceBase(other)
|
||||
{
|
||||
refT();
|
||||
}
|
||||
~QFutureInterface()
|
||||
{
|
||||
if (!derefT())
|
||||
resultStoreBase().template clear<QHttpServerResponse>();
|
||||
}
|
||||
|
||||
static QFutureInterface canceledResult()
|
||||
{ return QFutureInterface(State(Started | Finished | Canceled)); }
|
||||
|
||||
QFutureInterface &operator=(const QFutureInterface &other)
|
||||
{
|
||||
other.refT();
|
||||
if (!derefT())
|
||||
resultStoreBase().template clear<QHttpServerResponse>();
|
||||
QFutureInterfaceBase::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QFuture<QHttpServerResponse> future()
|
||||
{
|
||||
return QFuture<QHttpServerResponse>(this);
|
||||
}
|
||||
|
||||
void reportAndMoveResult(QHttpServerResponse &&result, int index = -1)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
std::lock_guard<QMutex> locker{*mutex()};
|
||||
#else
|
||||
std::lock_guard<QMutex> locker{mutex(0)};
|
||||
#endif
|
||||
if (queryState(Canceled) || queryState(Finished))
|
||||
return;
|
||||
|
||||
QtPrivate::ResultStoreBase &store = resultStoreBase();
|
||||
|
||||
const int oldResultCount = store.count();
|
||||
const int insertIndex = store.addResult(
|
||||
index, static_cast<void *>(new QHttpServerResponse(std::move_if_noexcept(result))));
|
||||
if (!store.filterMode() || oldResultCount < store.count()) // Let's make sure it's not in pending results.
|
||||
reportResultsReady(insertIndex, store.count());
|
||||
}
|
||||
|
||||
void reportFinished()
|
||||
{
|
||||
QFutureInterfaceBase::reportFinished();
|
||||
}
|
||||
|
||||
QHttpServerResponse takeResult()
|
||||
{
|
||||
if (isCanceled()) {
|
||||
exceptionStore().throwPossibleException();
|
||||
return QHttpServerResponse::StatusCode::NotFound;
|
||||
}
|
||||
|
||||
// Note: we wait for all, this is intentional,
|
||||
// not to mess with other unready results.
|
||||
waitForResult(-1);
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
std::lock_guard<QMutex> locker{*mutex()};
|
||||
#else
|
||||
std::lock_guard<QMutex> locker{mutex(0)};
|
||||
#endif
|
||||
QtPrivate::ResultIteratorBase position = resultStoreBase().resultAt(0);
|
||||
auto ret = std::move_if_noexcept(
|
||||
*const_cast<QHttpServerResponse *>(position.pointer<QHttpServerResponse>()));
|
||||
resultStoreBase().template clear<QHttpServerResponse>();
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
|
||||
namespace QtConcurrent {
|
||||
|
||||
template <>
|
||||
class RunFunctionTask<QHttpServerResponse> : public RunFunctionTaskBase<QHttpServerResponse>
|
||||
{
|
||||
public:
|
||||
void run() override
|
||||
{
|
||||
if (this->isCanceled()) {
|
||||
this->reportFinished();
|
||||
return;
|
||||
}
|
||||
#ifndef QT_NO_EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
this->runFunctor();
|
||||
#ifndef QT_NO_EXCEPTIONS
|
||||
} catch (QException &e) {
|
||||
QFutureInterface<QHttpServerResponse>::reportException(e);
|
||||
} catch (...) {
|
||||
QFutureInterface<QHttpServerResponse>::reportException(QUnhandledException());
|
||||
}
|
||||
#endif
|
||||
this->reportAndMoveResult(std::move_if_noexcept(result));
|
||||
this->reportFinished();
|
||||
}
|
||||
|
||||
QHttpServerResponse result{QHttpServerResponse::StatusCode::NotFound};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class QHttpServerFutureResponsePrivate;
|
||||
class Q_HTTPSERVER_EXPORT QHttpServerFutureResponse : public QHttpServerResponse
|
||||
{
|
||||
Q_DECLARE_PRIVATE(QHttpServerFutureResponse)
|
||||
|
||||
public:
|
||||
using QHttpServerResponse::QHttpServerResponse;
|
||||
|
||||
QHttpServerFutureResponse(const QFuture<QHttpServerResponse> &futureResponse);
|
||||
|
||||
virtual void write(QHttpServerResponder &&responder) const override;
|
||||
|
||||
protected:
|
||||
QHttpServerFutureResponse(QHttpServerFutureResponsePrivate *d);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QHTTPSERVERFUTURERESPONSE_H
|
@ -41,6 +41,16 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QHttpServerResponsePrivate::QHttpServerResponsePrivate(
|
||||
QByteArray &&d, const QHttpServerResponse::StatusCode sc)
|
||||
: data(std::move(d)),
|
||||
statusCode(sc)
|
||||
{ }
|
||||
|
||||
QHttpServerResponsePrivate::QHttpServerResponsePrivate(const QHttpServerResponse::StatusCode sc)
|
||||
: statusCode(sc)
|
||||
{ }
|
||||
|
||||
QHttpServerResponse::QHttpServerResponse(QHttpServerResponse &&other) noexcept
|
||||
: d_ptr(other.d_ptr.take())
|
||||
{
|
||||
@ -100,35 +110,33 @@ QHttpServerResponse::QHttpServerResponse(const QJsonArray &data)
|
||||
QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType,
|
||||
const QByteArray &data,
|
||||
const StatusCode status)
|
||||
: QHttpServerResponse(mimeType,
|
||||
new QHttpServerResponsePrivate{data, status, {}})
|
||||
: d_ptr(new QHttpServerResponsePrivate(QByteArray(data), status))
|
||||
{
|
||||
setHeader(QHttpServerLiterals::contentTypeHeader(), mimeType);
|
||||
}
|
||||
|
||||
QHttpServerResponse::QHttpServerResponse(QByteArray &&mimeType,
|
||||
const QByteArray &data,
|
||||
const StatusCode status)
|
||||
: QHttpServerResponse(std::move(mimeType),
|
||||
new QHttpServerResponsePrivate{data, status, {}})
|
||||
: d_ptr(new QHttpServerResponsePrivate(QByteArray(data), status))
|
||||
{
|
||||
setHeader(QHttpServerLiterals::contentTypeHeader(), std::move(mimeType));
|
||||
}
|
||||
|
||||
QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType,
|
||||
QByteArray &&data,
|
||||
const StatusCode status)
|
||||
: QHttpServerResponse(
|
||||
mimeType,
|
||||
new QHttpServerResponsePrivate{std::move(data), status, {}})
|
||||
: d_ptr(new QHttpServerResponsePrivate(std::move(data), status))
|
||||
{
|
||||
setHeader(QHttpServerLiterals::contentTypeHeader(), mimeType);
|
||||
}
|
||||
|
||||
QHttpServerResponse::QHttpServerResponse(QByteArray &&mimeType,
|
||||
QByteArray &&data,
|
||||
const StatusCode status)
|
||||
: QHttpServerResponse(
|
||||
std::move(mimeType),
|
||||
new QHttpServerResponsePrivate{std::move(data), status, {}})
|
||||
: d_ptr(new QHttpServerResponsePrivate(std::move(data), status))
|
||||
{
|
||||
setHeader(QHttpServerLiterals::contentTypeHeader(), std::move(mimeType));
|
||||
}
|
||||
|
||||
QHttpServerResponse::~QHttpServerResponse()
|
||||
@ -146,19 +154,10 @@ QHttpServerResponse QHttpServerResponse::fromFile(const QString &fileName)
|
||||
return QHttpServerResponse(mimeType, data);
|
||||
}
|
||||
|
||||
QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType,
|
||||
QHttpServerResponsePrivate *d)
|
||||
QHttpServerResponse::QHttpServerResponse(QHttpServerResponsePrivate *d)
|
||||
: d_ptr(d)
|
||||
{
|
||||
setHeader(QHttpServerLiterals::contentTypeHeader(), mimeType);
|
||||
}
|
||||
|
||||
QHttpServerResponse::QHttpServerResponse(QByteArray &&mimeType,
|
||||
QHttpServerResponsePrivate *d)
|
||||
: d_ptr(d)
|
||||
{
|
||||
setHeader(QHttpServerLiterals::contentTypeHeader(),
|
||||
std::move(mimeType));
|
||||
d->derived = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -118,12 +118,8 @@ public:
|
||||
|
||||
virtual void write(QHttpServerResponder &&responder) const;
|
||||
|
||||
private:
|
||||
QHttpServerResponse(const QByteArray &mimeType,
|
||||
QHttpServerResponsePrivate *d);
|
||||
|
||||
QHttpServerResponse(QByteArray &&mimeType,
|
||||
QHttpServerResponsePrivate *d);
|
||||
protected:
|
||||
QHttpServerResponse(QHttpServerResponsePrivate *d);
|
||||
|
||||
QScopedPointer<QHttpServerResponsePrivate> d_ptr;
|
||||
};
|
||||
|
@ -59,10 +59,16 @@ class QHttpServerResponsePrivate
|
||||
};
|
||||
|
||||
public:
|
||||
explicit QHttpServerResponsePrivate() = default;
|
||||
virtual ~QHttpServerResponsePrivate() = default;
|
||||
|
||||
QHttpServerResponsePrivate(QByteArray &&d, const QHttpServerResponse::StatusCode sc);
|
||||
QHttpServerResponsePrivate(const QHttpServerResponse::StatusCode sc);
|
||||
|
||||
QByteArray data;
|
||||
QHttpServerResponse::StatusCode statusCode;
|
||||
|
||||
std::unordered_multimap<QByteArray, QByteArray, HashHelper> headers;
|
||||
bool derived{false};
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -151,6 +151,7 @@ template <typename ViewHandler, bool DisableStaticAssert = false>
|
||||
struct QHttpServerRouterViewTraits
|
||||
{
|
||||
using Helpers = typename QtPrivate::RouterViewTraitsHelper<ViewHandler, DisableStaticAssert>;
|
||||
using ReturnType = typename Helpers::FunctionTraits::ReturnType;
|
||||
using Arguments = decltype(Helpers::Arguments::eval(typename Helpers::ArgumentIndexes{}));
|
||||
using BindableType = decltype(
|
||||
Helpers::template BindType<Arguments::CapturableCount>::eval(
|
||||
|
@ -31,6 +31,10 @@
|
||||
#include <QtHttpServer/qhttpserverrequest.h>
|
||||
#include <QtHttpServer/qhttpserverrouterrule.h>
|
||||
|
||||
#if QT_CONFIG(concurrent)
|
||||
# include <QtHttpServer/qhttpserverfutureresponse.h>
|
||||
#endif
|
||||
|
||||
#include <private/qhttpserverrouterrule_p.h>
|
||||
#include <private/qhttpserverliterals_p.h>
|
||||
|
||||
@ -296,6 +300,20 @@ void tst_QHttpServer::initTestCase()
|
||||
return std::move(resp);
|
||||
});
|
||||
|
||||
#if QT_CONFIG(concurrent)
|
||||
httpserver.route("/future/", [] (int id) -> QHttpServerFutureResponse {
|
||||
if (id == 0)
|
||||
return QHttpServerResponse::StatusCode::NotFound;
|
||||
|
||||
auto future = QtConcurrent::run([] () {
|
||||
QTest::qSleep(500);
|
||||
return QHttpServerResponse("future is coming");
|
||||
});
|
||||
|
||||
return future;
|
||||
});
|
||||
#endif
|
||||
|
||||
quint16 port = httpserver.listen();
|
||||
if (!port)
|
||||
qCritical() << "Http server listen failed";
|
||||
@ -526,6 +544,20 @@ void tst_QHttpServer::routeGet_data()
|
||||
<< "text/plain"
|
||||
<< "part 1 of the message, part 2 of the message";
|
||||
|
||||
#if QT_CONFIG(concurrent)
|
||||
QTest::addRow("future")
|
||||
<< urlBase.arg("/future/1")
|
||||
<< 200
|
||||
<< "text/plain"
|
||||
<< "future is coming";
|
||||
|
||||
QTest::addRow("future-not-found")
|
||||
<< urlBase.arg("/future/0")
|
||||
<< 404
|
||||
<< "application/x-empty"
|
||||
<< "";
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
|
||||
QTest::addRow("hello world, ssl")
|
||||
|
Loading…
x
Reference in New Issue
Block a user