diff options
author | Mikhail Svetkin <mikhail.svetkin@qt.io> | 2019-01-23 13:34:57 +0100 |
---|---|---|
committer | Mikhail Svetkin <mikhail.svetkin@qt.io> | 2019-03-06 09:41:39 +0000 |
commit | 2459725682de4d69c312aa3c4b96f072f558e8e1 (patch) | |
tree | 0ee83961b0c839f92cff40ce9e983b433c130737 | |
parent | 572e0b1f6c0a8a1c77863a618db3a906d41a3d5f (diff) |
Allow use of custom data structures as router callback arguments
Change-Id: I6dcc66a95b72bb461f237cade0352a0177065227
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Jesus Fernandez <Jesus.Fernandez@qt.io>
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
-rw-r--r-- | src/httpserver/qhttpserverrouter.cpp | 48 | ||||
-rw-r--r-- | src/httpserver/qhttpserverrouter.h | 13 | ||||
-rw-r--r-- | src/httpserver/qhttpserverrouterrule.cpp | 13 | ||||
-rw-r--r-- | tests/auto/qhttpserver/tst_qhttpserver.cpp | 46 |
4 files changed, 114 insertions, 6 deletions
diff --git a/src/httpserver/qhttpserverrouter.cpp b/src/httpserver/qhttpserverrouter.cpp index 8aeca62..1dc924c 100644 --- a/src/httpserver/qhttpserverrouter.cpp +++ b/src/httpserver/qhttpserverrouter.cpp @@ -97,6 +97,44 @@ static const QMap<int, QLatin1String> defaultConverters = { \endcode */ +/*! \fn template <typename Type> bool QHttpServerRouter::addConverter(const QLatin1String ®exp) + + Adds a new converter for type \e Type matching regular expression \a regexp. + + Automatically try to register an implicit converter from QString to \e Type. + If there is already a converter of type \e Type, that converter's regexp + is replaced with \a regexp. + + \code + struct CustomArg { + int data = 10; + + CustomArg() {} ; + CustomArg(const QString &urlArg) : data(urlArg.toInt()) {} + }; + Q_DECLARE_METATYPE(CustomArg); + + QHttpServerRouter router; + router.addConverter<CustomArg>(QLatin1String("[+-]?\\d+")); + + auto pageView = [] (const CustomArg &customArg) { + qDebug("data: %d", customArg.data); + }; + using ViewHandler = decltype(pageView); + + auto rule = new QHttpServerRouterRule( + "/<arg>/<arg>/log", + [&router, &pageView] (QRegularExpressionMatch &match, + const QHttpServerRequest &request, + QTcpSocket *socket) { + // Bind and call viewHandler with match's captured string and quint32: + router.bindCaptured(pageView, match)(); + }); + + router.addRule<ViewHandler>(rule); + \endcode +*/ + /*! \fn template <typename ViewHandler, typename ViewTraits = QHttpServerRouterViewTraits<ViewHandler>> bool QHttpServerRouter::addRule(QHttpServerRouterRule *rule) Adds a new \a rule. @@ -134,14 +172,16 @@ static const QMap<int, QLatin1String> defaultConverters = { \code QHttpServerRouter router; - auto pageView = [] (const QString &page, const quint32 num) { }; + auto pageView = [] (const QString &page, const quint32 num) { + qDebug("page: %s, num: %d", qPrintable(page), num); + }; using ViewHandler = decltype(pageView); auto rule = new QHttpServerRouterRule( "/<arg>/<arg>/log", - [&router] (QRegularExpressionMatch &match, - const QHttpServerRequest &request, - QTcpSocket *socket) { + [&router, &pageView] (QRegularExpressionMatch &match, + const QHttpServerRequest &request, + QTcpSocket *socket) { // Bind and call viewHandler with match's captured string and quint32: router.bindCaptured(pageView, match)(); }); diff --git a/src/httpserver/qhttpserverrouter.h b/src/httpserver/qhttpserverrouter.h index 13b2a09..522562c 100644 --- a/src/httpserver/qhttpserverrouter.h +++ b/src/httpserver/qhttpserverrouter.h @@ -72,6 +72,19 @@ public: QHttpServerRouter(); ~QHttpServerRouter(); + template<typename Type> + bool addConverter(const QLatin1String ®exp) { + static_assert(QMetaTypeId2<Type>::Defined, + "Type is not registered with Qt's meta-object system: " + "please apply Q_DECLARE_METATYPE() to it"); + + if (!QMetaType::registerConverter<QString, Type>()) + return false; + + addConverter(qMetaTypeId<Type>(), regexp); + return true; + } + void addConverter(const int type, const QLatin1String ®exp); void removeConverter(const int); void clearConverters(); diff --git a/src/httpserver/qhttpserverrouterrule.cpp b/src/httpserver/qhttpserverrouterrule.cpp index 032287a..d486218 100644 --- a/src/httpserver/qhttpserverrouterrule.cpp +++ b/src/httpserver/qhttpserverrouterrule.cpp @@ -175,10 +175,19 @@ bool QHttpServerRouterRule::createPathRegexp(const std::initializer_list<int> &m QString pathRegexp = d->pathPattern; const QLatin1String arg("<arg>"); for (auto type : metaTypes) { + if (type >= QMetaType::User + && !QMetaType::hasRegisteredConverterFunction(qMetaTypeId<QString>(), type)) { + qCWarning(lcRouterRule) << QMetaType::typeName(type) + << "has not registered a converter to QString." + << "Use QHttpServerRouter::addConveter<Type>(converter)."; + return false; + } + auto it = converters.constFind(type); if (it == converters.end()) { - qCWarning(lcRouterRule) << "can not find converter for type:" << type; - continue; + qCWarning(lcRouterRule) << "can not find converter for type:" + << QMetaType::typeName(type); + return false; } if (it->isEmpty()) diff --git a/tests/auto/qhttpserver/tst_qhttpserver.cpp b/tests/auto/qhttpserver/tst_qhttpserver.cpp index 41bae53..6193fb5 100644 --- a/tests/auto/qhttpserver/tst_qhttpserver.cpp +++ b/tests/auto/qhttpserver/tst_qhttpserver.cpp @@ -40,6 +40,7 @@ #include <QtCore/qstring.h> #include <QtCore/qlist.h> #include <QtCore/qbytearray.h> +#include <QtCore/qdatetime.h> #include <QtNetwork/qnetworkaccessmanager.h> #include <QtNetwork/qnetworkreply.h> @@ -84,12 +85,20 @@ private slots: void routeGet(); void routePost_data(); void routePost(); + void invalidRouterArguments(); private: QHttpServer httpserver; QString urlBase; }; +struct CustomArg { + int data = 10; + + CustomArg() {} ; + CustomArg(const QString &urlArg) : data(urlArg.toInt()) {} +}; + void tst_QHttpServer::initTestCase() { httpserver.route("/test", [] (QHttpServerResponder &&responder) { @@ -151,6 +160,12 @@ void tst_QHttpServer::initTestCase() }); urlBase = QStringLiteral("http://localhost:%1%2").arg(httpserver.listen()); + + + httpserver.router()->addConverter<CustomArg>(QLatin1String("[+-]?\\d+")); + httpserver.route("/check-custom-type/", [] (const CustomArg &customArg) { + return QString("data = %1").arg(customArg.data); + }); } void tst_QHttpServer::routeGet_data() @@ -278,6 +293,13 @@ void tst_QHttpServer::routeGet_data() << 200 << "text/html" << "Custom router rule: 10, key=12"; + + QTest::addRow("check custom type, data=1") + << "/check-custom-type/1" + << 200 + << "text/html" + << "data = 1"; + } void tst_QHttpServer::routeGet() @@ -333,8 +355,32 @@ void tst_QHttpServer::routePost() QCOMPARE(reply->readAll(), body); } +struct CustomType { + CustomType() {} + CustomType(const QString &) {} +}; + +void tst_QHttpServer::invalidRouterArguments() +{ + QCOMPARE( + httpserver.route("/datetime/", [] (const QDateTime &datetime) { + return QString("datetime: %1").arg(datetime.toString()); + }), + false); + + QCOMPARE( + httpserver.route("/implicit-conversion-to-qstring-has-no-registered/", + [] (const CustomType &) { + return ""; + }), + false); +} + QT_END_NAMESPACE +Q_DECLARE_METATYPE(CustomArg); +Q_DECLARE_METATYPE(CustomType); + QTEST_MAIN(tst_QHttpServer) #include "tst_qhttpserver.moc" |