summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikhail Svetkin <mikhail.svetkin@qt.io>2019-01-23 13:34:57 +0100
committerMikhail Svetkin <mikhail.svetkin@qt.io>2019-03-06 09:41:39 +0000
commit2459725682de4d69c312aa3c4b96f072f558e8e1 (patch)
tree0ee83961b0c839f92cff40ce9e983b433c130737
parent572e0b1f6c0a8a1c77863a618db3a906d41a3d5f (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.cpp48
-rw-r--r--src/httpserver/qhttpserverrouter.h13
-rw-r--r--src/httpserver/qhttpserverrouterrule.cpp13
-rw-r--r--tests/auto/qhttpserver/tst_qhttpserver.cpp46
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 &regexp)
+
+ 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 &regexp) {
+ 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 &regexp);
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"