summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikhail Svetkin <mikhail.svetkin@qt.io>2019-03-12 15:26:33 +0100
committerMikhail Svetkin <mikhail.svetkin@qt.io>2019-04-04 20:50:09 +0000
commitbe06bd66b8c8613498df06026dd8f10164dbd4ff (patch)
tree1888ef9236986d4e07e9ed9bacae71f20e0a7c3d
parent6f7e8d28b46dea47c9179f4a69bc693e844f4d1b (diff)
Accept a string as request method in QHttpServer::route()
Allow writing simpler source code. For example: httpserver.route("/", "GET|POST", [] () { return ""; }) Instead of: httpserver.route("/", QHttpServerRequest::Method::Post | QHttpServerRequest::Method::Get, [] () { return ""; }) Change-Id: Id0a754eccaba6b5f9f3be6a3b975383eb94840a0 Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
-rw-r--r--src/httpserver/qhttpserverrequest.h13
-rw-r--r--src/httpserver/qhttpserverrouter.cpp2
-rw-r--r--src/httpserver/qhttpserverrouterrule.cpp60
-rw-r--r--src/httpserver/qhttpserverrouterrule.h5
-rw-r--r--tests/auto/qhttpserver/tst_qhttpserver.cpp93
-rw-r--r--tests/auto/qhttpserverrouter/tst_qhttpserverrouter.cpp2
6 files changed, 170 insertions, 5 deletions
diff --git a/src/httpserver/qhttpserverrequest.h b/src/httpserver/qhttpserverrequest.h
index 0aeb1d8..c0afbce 100644
--- a/src/httpserver/qhttpserverrequest.h
+++ b/src/httpserver/qhttpserverrequest.h
@@ -63,7 +63,18 @@ public:
Post = 0x0008,
Head = 0x0010,
Options = 0x0020,
- Patch = 0x0040
+ Patch = 0x0040,
+
+ All = Get | Put | Delete | Post | Head | Options | Patch,
+
+ // Include upper-case aliases for the sake of parsing from strings:
+ GET = Get,
+ PUT = Put,
+ DELETE = Delete,
+ POST = Post,
+ HEAD = Head,
+ OPTIONS = Options,
+ PATCH = Patch
};
Q_ENUM(Method)
Q_DECLARE_FLAGS(Methods, Method)
diff --git a/src/httpserver/qhttpserverrouter.cpp b/src/httpserver/qhttpserverrouter.cpp
index 1dc924c..e28d5cf 100644
--- a/src/httpserver/qhttpserverrouter.cpp
+++ b/src/httpserver/qhttpserverrouter.cpp
@@ -281,7 +281,7 @@ bool QHttpServerRouter::addRuleImpl(QHttpServerRouterRule *rule,
{
Q_D(QHttpServerRouter);
- if (!rule->createPathRegexp(types, d->converters)) {
+ if (!rule->hasValidMethods() || !rule->createPathRegexp(types, d->converters)) {
delete rule;
return false;
}
diff --git a/src/httpserver/qhttpserverrouterrule.cpp b/src/httpserver/qhttpserverrouterrule.cpp
index d486218..151e411 100644
--- a/src/httpserver/qhttpserverrouterrule.cpp
+++ b/src/httpserver/qhttpserverrouterrule.cpp
@@ -30,7 +30,9 @@
#include <QtHttpServer/qhttpserverrouterrule.h>
#include <private/qhttpserverrouterrule_p.h>
+#include <private/qhttpserverrequest_p.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qregularexpression.h>
#include <QtCore/qdebug.h>
@@ -39,6 +41,27 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcRouterRule, "qt.httpserver.router.rule")
+static QHttpServerRequest::Methods strToMethods(const char *strMethods)
+{
+ QHttpServerRequest::Methods methods;
+
+ static const auto index = QHttpServerRequest::staticMetaObject.indexOfEnumerator("Method");
+ if (index == -1) {
+ qCWarning(lcRouterRule, "Can not find QMetaEnum for enum Method");
+ return methods;
+ }
+
+ static const QMetaEnum en = QHttpServerRequest::staticMetaObject.enumerator(index);
+ bool ok = false;
+ const int val = en.keysToValue(strMethods, &ok);
+ if (ok)
+ methods = static_cast<decltype(methods)>(val);
+ else
+ qCWarning(lcRouterRule, "Can not convert %s to QHttpServerRequest::Method", strMethods);
+
+ return methods;
+}
+
/*!
\class QHttpServerRouterRule
\brief The QHttpServerRouterRule is the base class for QHttpServerRouter rules.
@@ -94,12 +117,14 @@ Q_LOGGING_CATEGORY(lcRouterRule, "qt.httpserver.router.rule")
/*!
Constructs a rule with pathPattern \a pathPattern, and routerHandler \a routerHandler.
- The rule accepts any HTTP method.
+ The rule accepts all HTTP methods by default.
+
+ \sq QHttpServerRequest::Method
*/
QHttpServerRouterRule::QHttpServerRouterRule(const QString &pathPattern,
RouterHandler &&routerHandler)
: QHttpServerRouterRule(pathPattern,
- QHttpServerRequest::Methods(),
+ QHttpServerRequest::Method::All,
std::forward<RouterHandler>(routerHandler))
{
}
@@ -107,6 +132,10 @@ QHttpServerRouterRule::QHttpServerRouterRule(const QString &pathPattern,
/*!
Constructs a rule with pathPattern \a pathPattern, methods \a methods
and routerHandler \a routerHandler.
+
+ The rule accepts any combinations of available HTTP methods.
+
+ \sa QHttpServerRequest::Method
*/
QHttpServerRouterRule::QHttpServerRouterRule(const QString &pathPattern,
const QHttpServerRequest::Methods methods,
@@ -119,6 +148,24 @@ QHttpServerRouterRule::QHttpServerRouterRule(const QString &pathPattern,
}
/*!
+ Constructs a rule with pathPattern \a pathPattern, methods \a methods
+ and routerHandler \a routerHandler.
+
+ \note \a methods shall be joined with | as separator (not spaces or commas)
+ and that either the upper-case or the capitalised form may be used.
+
+ \sa QMetaEnum::keysToValue
+*/
+QHttpServerRouterRule::QHttpServerRouterRule(const QString &pathPattern,
+ const char *methods,
+ RouterHandler &&routerHandler)
+ : QHttpServerRouterRule(pathPattern,
+ strToMethods(methods),
+ std::forward<RouterHandler>(routerHandler))
+{
+}
+
+/*!
\internal
*/
QHttpServerRouterRule::QHttpServerRouterRule(QHttpServerRouterRulePrivate *d)
@@ -134,6 +181,15 @@ QHttpServerRouterRule::~QHttpServerRouterRule()
}
/*!
+ Returns true if the methods is valid
+*/
+bool QHttpServerRouterRule::hasValidMethods() const
+{
+ Q_D(const QHttpServerRouterRule);
+ return d->methods & QHttpServerRequest::Method::All;
+}
+
+/*!
This function is called by QHttpServerRouter when a new request is received.
*/
bool QHttpServerRouterRule::exec(const QHttpServerRequest &request,
diff --git a/src/httpserver/qhttpserverrouterrule.h b/src/httpserver/qhttpserverrouterrule.h
index 235e982..2b168b4 100644
--- a/src/httpserver/qhttpserverrouterrule.h
+++ b/src/httpserver/qhttpserverrouterrule.h
@@ -56,6 +56,9 @@ public:
explicit QHttpServerRouterRule(const QString &pathPattern,
const QHttpServerRequest::Methods methods,
RouterHandler &&routerHandler);
+ explicit QHttpServerRouterRule(const QString &pathPattern,
+ const char * methods,
+ RouterHandler &&routerHandler);
QHttpServerRouterRule(QHttpServerRouterRule &&other) = delete;
QHttpServerRouterRule &operator=(QHttpServerRouterRule &&other) = delete;
@@ -65,6 +68,8 @@ public:
protected:
bool exec(const QHttpServerRequest &request, QTcpSocket *socket) const;
+ bool hasValidMethods() const;
+
bool createPathRegexp(const std::initializer_list<int> &metaTypes,
const QMap<int, QLatin1String> &converters);
diff --git a/tests/auto/qhttpserver/tst_qhttpserver.cpp b/tests/auto/qhttpserver/tst_qhttpserver.cpp
index 2934dc0..aeb3a92 100644
--- a/tests/auto/qhttpserver/tst_qhttpserver.cpp
+++ b/tests/auto/qhttpserver/tst_qhttpserver.cpp
@@ -41,6 +41,7 @@
#include <QtCore/qlist.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qdatetime.h>
+#include <QtCore/qmetaobject.h>
#include <QtNetwork/qnetworkaccessmanager.h>
#include <QtNetwork/qnetworkreply.h>
@@ -85,6 +86,8 @@ private slots:
void routeGet();
void routePost_data();
void routePost();
+ void routeDelete_data();
+ void routeDelete();
void invalidRouterArguments();
private:
@@ -113,6 +116,24 @@ void tst_QHttpServer::initTestCase()
return "Hello world post";
});
+ httpserver.route("/post-and-get", "GET|POST", [] (const QHttpServerRequest &request) {
+ if (request.method() == QHttpServerRequest::Method::Get)
+ return "Hello world get";
+ else if (request.method() == QHttpServerRequest::Method::Post)
+ return "Hello world post";
+
+ return "This should not work";
+ });
+
+ httpserver.route("/any", "All", [] (const QHttpServerRequest &request) {
+ static const int index = QHttpServerRequest::staticMetaObject.indexOfEnumerator("Method");
+ if (index == -1)
+ return "Error: Could not find enum Method";
+
+ static const QMetaEnum en = QHttpServerRequest::staticMetaObject.enumerator(index);
+ return en.valueToKey(static_cast<int>(request.method()));
+ });
+
httpserver.route("/page/", [] (const qint32 number) {
return QString("page: %1").arg(number);
});
@@ -300,12 +321,29 @@ void tst_QHttpServer::routeGet_data()
<< "text/html"
<< "Custom router rule: 10, key=12";
+ QTest::addRow("post-and-get, get")
+ << "/post-and-get"
+ << 200
+ << "text/html"
+ << "Hello world get";
+
+ QTest::addRow("invalid-rule-method, get")
+ << "/invalid-rule-method"
+ << 404
+ << "text/html"
+ << "";
+
QTest::addRow("check custom type, data=1")
<< "/check-custom-type/1"
<< 200
<< "text/html"
<< "data = 1";
+ QTest::addRow("any, get")
+ << "/any"
+ << 200
+ << "text/html"
+ << "Get";
}
void tst_QHttpServer::routeGet()
@@ -396,6 +434,43 @@ void tst_QHttpServer::routePost()
QCOMPARE(reply->readAll(), body);
}
+void tst_QHttpServer::routeDelete_data()
+{
+ QTest::addColumn<QString>("url");
+ QTest::addColumn<int>("code");
+ QTest::addColumn<QString>("type");
+ QTest::addColumn<QString>("data");
+
+ QTest::addRow("post-and-get, delete")
+ << "/post-and-get"
+ << 404
+ << "text/html"
+ << "";
+
+ QTest::addRow("any, delete")
+ << "/any"
+ << 200
+ << "text/html"
+ << "Delete";
+}
+
+void tst_QHttpServer::routeDelete()
+{
+ QFETCH(QString, url);
+ QFETCH(int, code);
+ QFETCH(QString, type);
+ QFETCH(QString, data);
+
+ QNetworkAccessManager networkAccessManager;
+ const QUrl requestUrl(urlBase.arg(url));
+ auto reply = networkAccessManager.deleteResource(QNetworkRequest(requestUrl));
+
+ QTRY_VERIFY(reply->isFinished());
+
+ QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), type);
+ QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), code);
+}
+
struct CustomType {
CustomType() {}
CustomType(const QString &) {}
@@ -410,6 +485,24 @@ void tst_QHttpServer::invalidRouterArguments()
false);
QCOMPARE(
+ httpserver.route("/invalid-rule-method", "GeT", [] () {
+ return "";
+ }),
+ false);
+
+ QCOMPARE(
+ httpserver.route("/invalid-rule-method", "Garbage", [] () {
+ return "";
+ }),
+ false);
+
+ QCOMPARE(
+ httpserver.route("/invalid-rule-method", "Unknown", [] () {
+ return "";
+ }),
+ false);
+
+ QCOMPARE(
httpserver.route("/implicit-conversion-to-qstring-has-no-registered/",
[] (const CustomType &) {
return "";
diff --git a/tests/auto/qhttpserverrouter/tst_qhttpserverrouter.cpp b/tests/auto/qhttpserverrouter/tst_qhttpserverrouter.cpp
index 593ffb2..61d4e19 100644
--- a/tests/auto/qhttpserverrouter/tst_qhttpserverrouter.cpp
+++ b/tests/auto/qhttpserverrouter/tst_qhttpserverrouter.cpp
@@ -71,7 +71,7 @@ struct HttpServer : QAbstractHttpServer {
template<typename ViewHandler>
void route(const char *path, ViewHandler &&viewHandler)
{
- route(path, QHttpServerRequest::Methods(nullptr), std::forward<ViewHandler>(viewHandler));
+ route(path, QHttpServerRequest::Method::All, std::forward<ViewHandler>(viewHandler));
}
bool handleRequest(const QHttpServerRequest &request, QTcpSocket *socket) override {