mirror of
https://github.com/QuasarApp/qthttpserver.git
synced 2025-05-08 23:59:34 +00:00
Introduce QHttpServerRouter
Provide simple API for routing, parsing, capture and call callback Change-Id: Ibd7c37282d00bd56f96d841db92b473a65a2bf5c Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Paul Wicking <paul.wicking@qt.io> Reviewed-by: Jesus Fernandez <Jesus.Fernandez@qt.io>
This commit is contained in:
parent
74b22d36f8
commit
a856556784
@ -9,15 +9,23 @@ HEADERS += \
|
||||
qthttpserverglobal.h \
|
||||
qabstracthttpserver.h \
|
||||
qabstracthttpserver_p.h \
|
||||
qhttpserverhelpers.h \
|
||||
qhttpserverrequest.h \
|
||||
qhttpserverrequest_p.h \
|
||||
qhttpserverresponder.h \
|
||||
qhttpserverresponder_p.h \
|
||||
qhttpserverrequest.h \
|
||||
qhttpserverrequest_p.h
|
||||
qhttpserverrouter.h \
|
||||
qhttpserverrouter_p.h \
|
||||
qhttpserverrouterrule.h \
|
||||
qhttpserverrouterrule_p.h \
|
||||
qhttpserverrouterviewtraits.h
|
||||
|
||||
SOURCES += \
|
||||
qabstracthttpserver.cpp \
|
||||
qhttpserverrequest.cpp \
|
||||
qhttpserverresponder.cpp \
|
||||
qhttpserverrequest.cpp
|
||||
qhttpserverrouter.cpp \
|
||||
qhttpserverrouterrule.cpp
|
||||
|
||||
include(../3rdparty/http-parser.pri)
|
||||
|
||||
|
74
src/httpserver/qhttpserverhelpers.h
Normal file
74
src/httpserver/qhttpserverhelpers.h
Normal file
@ -0,0 +1,74 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtHttpServer module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QHTTPSERVERHELPERS_H
|
||||
#define QHTTPSERVERHELPERS_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists for the convenience
|
||||
// of QHttpServer. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QHttpServerHelpers {
|
||||
|
||||
template<int> struct Placeholder {};
|
||||
|
||||
} // namespace QHttpServerHelpers
|
||||
|
||||
namespace std {
|
||||
|
||||
template<int N>
|
||||
struct is_placeholder<QHttpServerHelpers::Placeholder<N>> : integral_constant<int, N + 1> {};
|
||||
|
||||
} // namespace std
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QHTTPSERVERHELPERS_H
|
@ -59,21 +59,24 @@ class Q_HTTPSERVER_EXPORT QHttpServerRequest : public QObjectUserData
|
||||
friend class QAbstractHttpServerPrivate;
|
||||
friend class QHttpServerResponse;
|
||||
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
~QHttpServerRequest() override;
|
||||
|
||||
enum class Method
|
||||
{
|
||||
Unknown = -1,
|
||||
|
||||
Get,
|
||||
Put,
|
||||
Delete,
|
||||
Post,
|
||||
Head,
|
||||
Options,
|
||||
Patch
|
||||
Unknown = 0x0000,
|
||||
Get = 0x0001,
|
||||
Put = 0x0002,
|
||||
Delete = 0x0004,
|
||||
Post = 0x0008,
|
||||
Head = 0x0010,
|
||||
Options = 0x0020,
|
||||
Patch = 0x0040
|
||||
};
|
||||
Q_DECLARE_FLAGS(Methods, Method);
|
||||
Q_FLAG(Methods)
|
||||
|
||||
QString value(const QString &key) const;
|
||||
QUrl url() const;
|
||||
@ -96,6 +99,4 @@ private:
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QHttpServerRequest::Method)
|
||||
|
||||
#endif // QHTTPSERVERREQUEST_H
|
||||
|
283
src/httpserver/qhttpserverrouter.cpp
Normal file
283
src/httpserver/qhttpserverrouter.cpp
Normal file
@ -0,0 +1,283 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qhttpserverrouter_p.h"
|
||||
|
||||
#include <QtHttpServer/qhttpserverrouter.h>
|
||||
#include <QtHttpServer/qhttpserverrouterrule.h>
|
||||
#include <QtHttpServer/qhttpserverrequest.h>
|
||||
|
||||
#include <private/qhttpserverrouterrule_p.h>
|
||||
|
||||
#include <QtCore/qmetatype.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcRouter, "qt.httpserver.router")
|
||||
|
||||
namespace {
|
||||
|
||||
const QMap<int, QLatin1String> defaultConverters = {
|
||||
{ QMetaType::Int, QLatin1String("[+-]?\\d+") },
|
||||
{ QMetaType::Long, QLatin1String("[+-]?\\d+") },
|
||||
{ QMetaType::LongLong, QLatin1String("[+-]?\\d+") },
|
||||
{ QMetaType::Short, QLatin1String("[+-]?\\d+") },
|
||||
|
||||
{ QMetaType::UInt, QLatin1String("[+]?\\d+") },
|
||||
{ QMetaType::ULong, QLatin1String("[+]?\\d+") },
|
||||
{ QMetaType::ULongLong, QLatin1String("[+]?\\d+") },
|
||||
{ QMetaType::UShort, QLatin1String("[+]?\\d+") },
|
||||
|
||||
{ QMetaType::Double, QLatin1String("[+-]?(?:[0-9]+(?:[.][0-9]*)?|[.][0-9]+)") },
|
||||
{ QMetaType::Float, QLatin1String("[+-]?(?:[0-9]+(?:[.][0-9]*)?|[.][0-9]+)") },
|
||||
|
||||
{ QMetaType::QString, QLatin1String("[^/]+") },
|
||||
{ QMetaType::QByteArray, QLatin1String("[^/]+") },
|
||||
|
||||
{ QMetaType::QUrl, QLatin1String(".*") },
|
||||
|
||||
{ QMetaType::Void, QLatin1String("") },
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QHttpServerRouter
|
||||
\brief Provides functions to bind a URL to a \c ViewHandler.
|
||||
|
||||
You can register \c ViewHandler as a callback for requests to a specific URL.
|
||||
Variable parts in the route can be specified by the arguments in ViewHandler.
|
||||
|
||||
\note This is a low-level routing API for an HTTP server.
|
||||
|
||||
See the following example:
|
||||
|
||||
\code
|
||||
auto pageView = [] (const quint64 page) {
|
||||
qDebug() << "page" << page;
|
||||
};
|
||||
using ViewHandler = decltype(pageView);
|
||||
|
||||
QHttpServerRouter router;
|
||||
|
||||
// register callback pageView on request "/page/<number>"
|
||||
// for example: "/page/10", "/page/15"
|
||||
router.addRoute<ViewHandler>(
|
||||
new QHttpServerRouterRule("/page/", [=] (QRegularExpressionMatch &match,
|
||||
const QHttpServerRequest &,
|
||||
QTcpSocket *) {
|
||||
auto boundView = router.bindCaptured(pageView, match);
|
||||
|
||||
// it calls pageView
|
||||
boundView();
|
||||
}));
|
||||
\endcode
|
||||
*/
|
||||
|
||||
/*! \fn template <typename ViewHandler, typename ViewTraits = QHttpServerRouterViewTraits<ViewHandler>> bool QHttpServerRouter::addRule(QHttpServerRouterRule *rule)
|
||||
|
||||
Adds a new \a rule.
|
||||
|
||||
Inside addRule, we determine ViewHandler arguments and generate a list of
|
||||
their QMetaType::Type ids. Then we parse the URL and replace each \c <arg>
|
||||
with a regexp for its type from the list.
|
||||
|
||||
\code
|
||||
QHttpServerRouter router;
|
||||
|
||||
using ViewHandler = decltype([] (const QString &page, const quint32 num) { });
|
||||
|
||||
auto rule = new QHttpServerRouterRule(
|
||||
"/<arg>/<arg>/log",
|
||||
[] (QRegularExpressionMatch &match,
|
||||
const QHttpServerRequest &request,
|
||||
QTcpSocket *socket) {
|
||||
});
|
||||
|
||||
router.addRule<ViewHandler>(rule);
|
||||
\endcode
|
||||
|
||||
\note This function takes over ownership of \a rule.
|
||||
*/
|
||||
|
||||
/*! \fn template<typename ViewHandler, typename ViewTraits = QHttpServerRouterViewTraits<ViewHandler>> auto bindCaptured(ViewHandler &&handler, QRegularExpressionMatch &match) const -> typename ViewTraits::BindableType
|
||||
|
||||
Supplies the \a handler with arguments derived from a URL.
|
||||
Returns the bound function that accepts whatever remaining arguments the handler may take,
|
||||
supplying them to the handler after the URL-derived values.
|
||||
Each match of the regex applied to the URL (as a string) is converted to the type
|
||||
of the handler's parameter at its position, so that passing it works.
|
||||
|
||||
\code
|
||||
QHttpServerRouter router;
|
||||
|
||||
auto pageView = [] (const QString &page, const quint32 num) { };
|
||||
using ViewHandler = decltype(pageView);
|
||||
|
||||
auto rule = new QHttpServerRouterRule(
|
||||
"/<arg>/<arg>/log",
|
||||
[&router] (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
|
||||
*/
|
||||
|
||||
QHttpServerRouterPrivate::QHttpServerRouterPrivate()
|
||||
: converters(defaultConverters)
|
||||
{}
|
||||
|
||||
/*!
|
||||
Creates a QHttpServerRouter object with \c defaultConverters.
|
||||
|
||||
\sa defaultConverters()
|
||||
*/
|
||||
QHttpServerRouter::QHttpServerRouter()
|
||||
: d_ptr(new QHttpServerRouterPrivate)
|
||||
{}
|
||||
|
||||
/*!
|
||||
Destroys a QHttpServerRouter.
|
||||
*/
|
||||
QHttpServerRouter::~QHttpServerRouter()
|
||||
{}
|
||||
|
||||
/*!
|
||||
Adds a new converter for type \a type matching regular expression \a regexp.
|
||||
|
||||
If there is already a converter of type \a type, that converter's regexp
|
||||
is replaced with \a regexp.
|
||||
*/
|
||||
void QHttpServerRouter::addConverter(const int type, const QLatin1String ®exp)
|
||||
{
|
||||
Q_D(QHttpServerRouter);
|
||||
d->converters[type] = regexp;
|
||||
}
|
||||
|
||||
/*!
|
||||
Removes the converter for type \a type.
|
||||
*/
|
||||
void QHttpServerRouter::removeConverter(const int type)
|
||||
{
|
||||
Q_D(QHttpServerRouter);
|
||||
d->converters.remove(type);
|
||||
}
|
||||
|
||||
/*!
|
||||
Removes all converters.
|
||||
|
||||
\note clearConverters() does not set up \c defaultConverters.
|
||||
|
||||
\sa defaultConverters()
|
||||
*/
|
||||
void QHttpServerRouter::clearConverters()
|
||||
{
|
||||
Q_D(QHttpServerRouter);
|
||||
d->converters.clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a map of converter type and regexp.
|
||||
*/
|
||||
const QMap<int, QLatin1String> &QHttpServerRouter::converters() const
|
||||
{
|
||||
Q_D(const QHttpServerRouter);
|
||||
return d->converters;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a map of default converter type and regexp.
|
||||
The following converters are available by default:
|
||||
|
||||
\value QMetaType::Int
|
||||
\value QMetaType::Long
|
||||
\value QMetaType::LongLong
|
||||
\value QMetaType::Short
|
||||
\value QMetaType::UInt
|
||||
\value QMetaType::ULong
|
||||
\value QMetaType::ULongLong
|
||||
\value QMetaType::UShort
|
||||
\value QMetaType::Double
|
||||
\value QMetaType::Float
|
||||
\value QMetaType::QString
|
||||
\value QMetaType::QByteArray
|
||||
\value QMetaType::QUrl
|
||||
\value QMetaType::Void An empty converter.
|
||||
*/
|
||||
const QMap<int, QLatin1String> &QHttpServerRouter::defaultConverters()
|
||||
{
|
||||
return ::defaultConverters;
|
||||
}
|
||||
|
||||
bool QHttpServerRouter::addRuleImpl(QHttpServerRouterRule *rule,
|
||||
const std::initializer_list<int> &types)
|
||||
{
|
||||
Q_D(QHttpServerRouter);
|
||||
|
||||
if (!rule->createPathRegexp(types, d->converters)) {
|
||||
delete rule;
|
||||
return false;
|
||||
}
|
||||
|
||||
d->rules.emplace_back(rule);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Handles each new request for the HTTP server.
|
||||
|
||||
Iterates through the list of rules to find the first that matches,
|
||||
then executes this rule, returning \c true. Returns \c false if no rule
|
||||
matches the request.
|
||||
*/
|
||||
bool QHttpServerRouter::handleRequest(const QHttpServerRequest &request,
|
||||
QTcpSocket *socket) const
|
||||
{
|
||||
Q_D(const QHttpServerRouter);
|
||||
for (const auto &rule : qAsConst(d->rules)) {
|
||||
if (rule->exec(request, socket))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
126
src/httpserver/qhttpserverrouter.h
Normal file
126
src/httpserver/qhttpserverrouter.h
Normal file
@ -0,0 +1,126 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtHttpServer module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QHTTPSERVERROUTER_H
|
||||
#define QHTTPSERVERROUTER_H
|
||||
|
||||
#include <QtHttpServer/qthttpserverglobal.h>
|
||||
#include <QtHttpServer/qhttpserverhelpers.h>
|
||||
#include <QtHttpServer/qhttpserverrouterviewtraits.h>
|
||||
|
||||
#include <QtCore/qscopedpointer.h>
|
||||
#include <QtCore/qmetatype.h>
|
||||
#include <QtCore/qregularexpression.h>
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QTcpSocket;
|
||||
class QHttpServerRequest;
|
||||
class QHttpServerRouterRule;
|
||||
|
||||
class QHttpServerRouterPrivate;
|
||||
class Q_HTTPSERVER_EXPORT QHttpServerRouter
|
||||
{
|
||||
Q_DECLARE_PRIVATE(QHttpServerRouter)
|
||||
|
||||
public:
|
||||
QHttpServerRouter();
|
||||
~QHttpServerRouter();
|
||||
|
||||
void addConverter(const int type, const QLatin1String ®exp);
|
||||
void removeConverter(const int);
|
||||
void clearConverters();
|
||||
const QMap<int, QLatin1String> &converters() const;
|
||||
|
||||
static const QMap<int, QLatin1String> &defaultConverters();
|
||||
|
||||
template<typename ViewHandler, typename ViewTraits = QHttpServerRouterViewTraits<ViewHandler>>
|
||||
bool addRule(QHttpServerRouterRule *rule)
|
||||
{
|
||||
return addRuleHelper<ViewTraits>(
|
||||
rule,
|
||||
typename QtPrivate::Indexes<ViewTraits::ArgumentCount>::Value{});
|
||||
}
|
||||
|
||||
template<typename ViewHandler, typename ViewTraits = QHttpServerRouterViewTraits<ViewHandler>>
|
||||
auto bindCaptured(ViewHandler &&handler,
|
||||
QRegularExpressionMatch &match) const -> typename ViewTraits::BindableType
|
||||
{
|
||||
return bindCapturedImpl<ViewHandler, ViewTraits>(
|
||||
std::forward<ViewHandler>(handler),
|
||||
match,
|
||||
typename QtPrivate::Indexes<ViewTraits::ArgumentCapturableCount>::Value{},
|
||||
typename QtPrivate::Indexes<ViewTraits::ArgumentPlaceholdersCount>::Value{});
|
||||
}
|
||||
|
||||
bool handleRequest(const QHttpServerRequest &request,
|
||||
QTcpSocket *socket) const;
|
||||
|
||||
private:
|
||||
template<typename ViewTraits, int ... Idx>
|
||||
bool addRuleHelper(QHttpServerRouterRule *rule,
|
||||
QtPrivate::IndexesList<Idx...>)
|
||||
{
|
||||
const std::initializer_list<int> types = {ViewTraits::template Arg<Idx>::metaTypeId()...};
|
||||
return addRuleImpl(rule, types);
|
||||
}
|
||||
|
||||
bool addRuleImpl(QHttpServerRouterRule *rule,
|
||||
const std::initializer_list<int> &metaTypes);
|
||||
|
||||
template<typename ViewHandler, typename ViewTraits, int ... Cx, int ... Px>
|
||||
auto bindCapturedImpl(ViewHandler &&handler,
|
||||
QRegularExpressionMatch &match,
|
||||
QtPrivate::IndexesList<Cx...>,
|
||||
QtPrivate::IndexesList<Px...>) const -> typename ViewTraits::BindableType
|
||||
{
|
||||
return std::bind(
|
||||
std::forward<ViewHandler>(handler),
|
||||
QVariant(match.captured(Cx + 1)).value<typename ViewTraits::template Arg<Cx>::Type>()...,
|
||||
QHttpServerHelpers::Placeholder<Px>{}...);
|
||||
}
|
||||
|
||||
QScopedPointer<QHttpServerRouterPrivate> d_ptr;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QHTTPSERVERROUTER_H
|
74
src/httpserver/qhttpserverrouter_p.h
Normal file
74
src/httpserver/qhttpserverrouter_p.h
Normal file
@ -0,0 +1,74 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtHttpServer module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QHTTPSERVERROUTER_P_H
|
||||
#define QHTTPSERVERROUTER_P_H
|
||||
|
||||
#include <QtHttpServer/qhttpserverrouter.h>
|
||||
#include <QtHttpServer/qhttpserverrouterrule.h>
|
||||
|
||||
#include <QtCore/qmap.h>
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qstring.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists for the convenience
|
||||
// of QHttpServer. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
struct QHttpServerRouterPrivate
|
||||
{
|
||||
QHttpServerRouterPrivate();
|
||||
|
||||
QMap<int, QLatin1String> converters;
|
||||
std::list<std::unique_ptr<QHttpServerRouterRule>> rules;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QHTTPSERVERROUTER_P_H
|
222
src/httpserver/qhttpserverrouterrule.cpp
Normal file
222
src/httpserver/qhttpserverrouterrule.cpp
Normal file
@ -0,0 +1,222 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtHttpServer/qhttpserverrouterrule.h>
|
||||
|
||||
#include <private/qhttpserverrouterrule_p.h>
|
||||
|
||||
#include <QtCore/qregularexpression.h>
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcRouterRule, "qt.httpserver.router.rule")
|
||||
|
||||
/*!
|
||||
\class QHttpServerRouterRule
|
||||
\brief The QHttpServerRouterRule is the base class for QHttpServerRouter rules.
|
||||
|
||||
Use QHttpServerRouterRule to specify expected request parameters:
|
||||
|
||||
\value path QUrl::path()
|
||||
\value HTTP methods QHttpServerRequest::Methods
|
||||
\value callback User-defined response callback
|
||||
|
||||
\note This is a low level API, see QHttpServer for higher level alternatives.
|
||||
|
||||
Example of QHttpServerRouterRule and QHttpServerRouter usage:
|
||||
|
||||
\code
|
||||
template<typename ViewHandler>
|
||||
void route(const char *path, const QHttpServerRequest::Methods methods, ViewHandler &&viewHandler)
|
||||
{
|
||||
auto rule = new QHttpServerRouterRule(
|
||||
path, methods, [this, &viewHandler] (QRegularExpressionMatch &match,
|
||||
const QHttpServerRequest &request,
|
||||
QTcpSocket *const socket) {
|
||||
auto boundViewHandler = router.bindCaptured<ViewHandler>(
|
||||
std::forward<ViewHandler>(viewHandler), match);
|
||||
// call viewHandler
|
||||
boundViewHandler();
|
||||
});
|
||||
|
||||
// QHttpServerRouter
|
||||
router.addRule<ViewHandler>(rule);
|
||||
}
|
||||
|
||||
// Valid:
|
||||
route("/user/", [] (qint64 id) { } ); // "/user/1"
|
||||
// "/user/3"
|
||||
//
|
||||
route("/user/<arg>/history", [] (qint64 id) { } ); // "/user/1/history"
|
||||
// "/user/2/history"
|
||||
//
|
||||
route("/user/<arg>/history/", [] (qint64 id, qint64 page) { } ); // "/user/1/history/1"
|
||||
// "/user/2/history/2"
|
||||
|
||||
// Invalid:
|
||||
route("/user/<arg>", [] () { } ); // ERROR: path pattern has <arg>, but ViewHandler does not have any arguments
|
||||
route("/user/\\d+", [] () { } ); // ERROR: path pattern does not support manual regexp
|
||||
\endcode
|
||||
|
||||
\note Regular expressions in the path pattern are not supported, but
|
||||
can be registered (to match a use of "<val>" to a specific type) using
|
||||
QHttpServerRouter::addConverter().
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs a rule with pathPattern \a pathPattern, and routerHandler \a routerHandler.
|
||||
|
||||
The rule accepts any HTTP method.
|
||||
*/
|
||||
QHttpServerRouterRule::QHttpServerRouterRule(const QString &pathPattern,
|
||||
RouterHandler &&routerHandler)
|
||||
: QHttpServerRouterRule(pathPattern,
|
||||
QHttpServerRequest::Methods(),
|
||||
std::forward<RouterHandler>(routerHandler))
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a rule with pathPattern \a pathPattern, methods \a methods
|
||||
and routerHandler \a routerHandler.
|
||||
*/
|
||||
QHttpServerRouterRule::QHttpServerRouterRule(const QString &pathPattern,
|
||||
const QHttpServerRequest::Methods methods,
|
||||
RouterHandler &&routerHandler)
|
||||
: QHttpServerRouterRule(
|
||||
new QHttpServerRouterRulePrivate{pathPattern,
|
||||
methods,
|
||||
std::forward<RouterHandler>(routerHandler), {}})
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QHttpServerRouterRule::QHttpServerRouterRule(QHttpServerRouterRulePrivate *d)
|
||||
: d_ptr(d)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys a QHttpServerRouterRule.
|
||||
*/
|
||||
QHttpServerRouterRule::~QHttpServerRouterRule()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
This function is called by QHttpServerRouter when a new request is received.
|
||||
*/
|
||||
bool QHttpServerRouterRule::exec(const QHttpServerRequest &request,
|
||||
QTcpSocket *socket) const
|
||||
{
|
||||
Q_D(const QHttpServerRouterRule);
|
||||
|
||||
QRegularExpressionMatch match;
|
||||
if (!matches(request, &match))
|
||||
return false;
|
||||
|
||||
d->routerHandler(match, request, socket);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
This virtual function is called by exec() to check if request matches the rule.
|
||||
*/
|
||||
bool QHttpServerRouterRule::matches(const QHttpServerRequest &request,
|
||||
QRegularExpressionMatch *match) const
|
||||
{
|
||||
Q_D(const QHttpServerRouterRule);
|
||||
|
||||
if (d->methods && !(d->methods & request.method()))
|
||||
return false;
|
||||
|
||||
*match = d->pathRegexp.match(request.url().path());
|
||||
return (match->hasMatch() && d->pathRegexp.captureCount() == match->lastCapturedIndex());
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
bool QHttpServerRouterRule::createPathRegexp(const std::initializer_list<int> &metaTypes,
|
||||
const QMap<int, QLatin1String> &converters)
|
||||
{
|
||||
Q_D(QHttpServerRouterRule);
|
||||
|
||||
QString pathRegexp = d->pathPattern;
|
||||
const QLatin1String arg("<arg>");
|
||||
for (auto type : metaTypes) {
|
||||
auto it = converters.constFind(type);
|
||||
if (it == converters.end()) {
|
||||
qCWarning(lcRouterRule) << "can not find converter for type:" << type;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (it->isEmpty())
|
||||
continue;
|
||||
|
||||
const auto index = pathRegexp.indexOf(arg);
|
||||
const QString ®exp = QLatin1Char('(') % *it % QLatin1Char(')');
|
||||
if (index == -1)
|
||||
pathRegexp.append(regexp);
|
||||
else
|
||||
pathRegexp.replace(index, arg.size(), regexp);
|
||||
}
|
||||
|
||||
if (pathRegexp.indexOf(arg) != -1) {
|
||||
qCWarning(lcRouterRule) << "not enough types or one of the types is not supported, regexp:"
|
||||
<< pathRegexp
|
||||
<< ", pattern:" << d->pathPattern
|
||||
<< ", types:" << metaTypes;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pathRegexp.startsWith(QLatin1Char('^')))
|
||||
pathRegexp = QLatin1Char('^') % pathRegexp;
|
||||
if (!pathRegexp.endsWith(QLatin1Char('$')))
|
||||
pathRegexp += QLatin1String("$");
|
||||
|
||||
qCDebug(lcRouterRule) << "url pathRegexp:" << pathRegexp;
|
||||
|
||||
d->pathRegexp.setPattern(pathRegexp);
|
||||
d->pathRegexp.optimize();
|
||||
return true;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
95
src/httpserver/qhttpserverrouterrule.h
Normal file
95
src/httpserver/qhttpserverrouterrule.h
Normal file
@ -0,0 +1,95 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtHttpServer module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QHTTPSERVERROUTERRULE_H
|
||||
#define QHTTPSERVERROUTERRULE_H
|
||||
|
||||
#include <QtHttpServer/qhttpserverrequest.h>
|
||||
|
||||
#include <QtCore/qmap.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QString;
|
||||
class QHttpServerRequest;
|
||||
class QTcpSocket;
|
||||
class QRegularExpressionMatch;
|
||||
class QHttpServerRouter;
|
||||
|
||||
class QHttpServerRouterRulePrivate;
|
||||
class Q_HTTPSERVER_EXPORT QHttpServerRouterRule
|
||||
{
|
||||
Q_DECLARE_PRIVATE(QHttpServerRouterRule)
|
||||
|
||||
public:
|
||||
using RouterHandler = std::function<void(QRegularExpressionMatch &,
|
||||
const QHttpServerRequest &,
|
||||
QTcpSocket *)>;
|
||||
|
||||
explicit QHttpServerRouterRule(const QString &pathPattern, RouterHandler &&routerHandler);
|
||||
explicit QHttpServerRouterRule(const QString &pathPattern,
|
||||
const QHttpServerRequest::Methods methods,
|
||||
RouterHandler &&routerHandler);
|
||||
|
||||
QHttpServerRouterRule(QHttpServerRouterRule &&other) = delete;
|
||||
QHttpServerRouterRule &operator=(QHttpServerRouterRule &&other) = delete;
|
||||
|
||||
virtual ~QHttpServerRouterRule();
|
||||
|
||||
protected:
|
||||
bool exec(const QHttpServerRequest &request, QTcpSocket *socket) const;
|
||||
|
||||
bool createPathRegexp(const std::initializer_list<int> &metaTypes,
|
||||
const QMap<int, QLatin1String> &converters);
|
||||
|
||||
virtual bool matches(const QHttpServerRequest &request,
|
||||
QRegularExpressionMatch *match) const;
|
||||
|
||||
QHttpServerRouterRule(QHttpServerRouterRulePrivate *d);
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QHttpServerRouterRule);
|
||||
QScopedPointer<QHttpServerRouterRulePrivate> d_ptr;
|
||||
|
||||
friend class QHttpServerRouter;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QHTTPSERVERROUTERRULE_H
|
71
src/httpserver/qhttpserverrouterrule_p.h
Normal file
71
src/httpserver/qhttpserverrouterrule_p.h
Normal file
@ -0,0 +1,71 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtHttpServer module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QHTTPSERVERROUTERRULE_P_H
|
||||
#define QHTTPSERVERROUTERRULE_P_H
|
||||
|
||||
#include <QtHttpServer/qhttpserverrouterrule.h>
|
||||
|
||||
#include <QtCore/qregularexpression.h>
|
||||
#include <QtCore/qstring.h>
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists for the convenience
|
||||
// of QHttpServer. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
struct Q_HTTPSERVER_EXPORT QHttpServerRouterRulePrivate
|
||||
{
|
||||
QString pathPattern;
|
||||
QHttpServerRequest::Methods methods;
|
||||
QHttpServerRouterRule::RouterHandler routerHandler;
|
||||
|
||||
QRegularExpression pathRegexp;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QHTTPSERVERROUTERRULE_P_H
|
136
src/httpserver/qhttpserverrouterviewtraits.h
Normal file
136
src/httpserver/qhttpserverrouterviewtraits.h
Normal file
@ -0,0 +1,136 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtHttpServer module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QHTTPSERVERROUTERVIEWTRAITS_H
|
||||
#define QHTTPSERVERROUTERVIEWTRAITS_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qnamespace.h>
|
||||
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QHttpServerRequest;
|
||||
class QHttpServerResponder;
|
||||
|
||||
template <typename ViewHandler>
|
||||
struct QHttpServerRouterViewTraits : QHttpServerRouterViewTraits<decltype(&ViewHandler::operator())> {};
|
||||
|
||||
template <typename ClassType, typename Ret, typename ... Args>
|
||||
struct QHttpServerRouterViewTraits<Ret(ClassType::*)(Args...) const>
|
||||
{
|
||||
static constexpr const auto ArgumentCount = sizeof ... (Args);
|
||||
|
||||
template <int I>
|
||||
struct Arg {
|
||||
using OriginalType = typename std::tuple_element<I, std::tuple<Args...>>::type;
|
||||
using Type = typename QtPrivate::RemoveConstRef<OriginalType>::Type;
|
||||
|
||||
static constexpr int metaTypeId() noexcept {
|
||||
return qMetaTypeId<
|
||||
typename std::conditional<
|
||||
!QMetaTypeId2<Type>::Defined,
|
||||
void,
|
||||
Type>::type>();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
// Tools used to compute ArgumentCapturableCount
|
||||
template<typename T>
|
||||
static constexpr typename std::enable_if<QMetaTypeId2<T>::Defined, int>::type
|
||||
capturable()
|
||||
{ return 1; }
|
||||
|
||||
template<typename T>
|
||||
static constexpr typename std::enable_if<!QMetaTypeId2<T>::Defined, int>::type
|
||||
capturable()
|
||||
{ return 0; }
|
||||
|
||||
static constexpr std::size_t sum() noexcept { return 0; }
|
||||
|
||||
template<typename ... N>
|
||||
static constexpr std::size_t sum(const std::size_t it, N ... n) noexcept
|
||||
{ return it + sum(n...); }
|
||||
|
||||
public:
|
||||
static constexpr const auto ArgumentCapturableCount =
|
||||
sum(capturable<typename QtPrivate::RemoveConstRef<Args>::Type>()...);
|
||||
static constexpr const auto ArgumentPlaceholdersCount = ArgumentCount - ArgumentCapturableCount;
|
||||
|
||||
private:
|
||||
// Tools used to get BindableType
|
||||
template<typename Return, typename ... ArgsX>
|
||||
struct BindTypeHelper {
|
||||
using Type = std::function<Return(ArgsX...)>;
|
||||
};
|
||||
|
||||
template<int ... Idx>
|
||||
static constexpr auto bindTypeHelper(QtPrivate::IndexesList<Idx...>) ->
|
||||
BindTypeHelper<Ret, typename Arg<ArgumentCapturableCount + Idx>::OriginalType...>;
|
||||
|
||||
public:
|
||||
// C++11 does not allow use of "auto" as a function return type.
|
||||
// BindableType is an emulation of "auto" for QHttpServerRouter::bindCapture.
|
||||
using BindableType = typename decltype(
|
||||
bindTypeHelper(typename QtPrivate::Indexes<ArgumentPlaceholdersCount>::Value{}))::Type;
|
||||
};
|
||||
|
||||
template <typename ClassType, typename Ret>
|
||||
struct QHttpServerRouterViewTraits<Ret(ClassType::*)() const>
|
||||
{
|
||||
static constexpr const int ArgumentCount = 0;
|
||||
|
||||
template <int I>
|
||||
struct Arg {
|
||||
using Type = void;
|
||||
};
|
||||
|
||||
static constexpr const auto ArgumentCapturableCount = 0;
|
||||
static constexpr const auto ArgumentPlaceholdersCount = 0;
|
||||
|
||||
using BindableType = decltype(std::function<Ret()>{});
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QHTTPSERVERROUTERVIEWTRAITS_H
|
@ -3,4 +3,5 @@ TEMPLATE = subdirs
|
||||
SUBDIRS = \
|
||||
cmake \
|
||||
qabstracthttpserver \
|
||||
qhttpserverresponder
|
||||
qhttpserverresponder \
|
||||
qhttpserverrouter
|
||||
|
5
tests/auto/qhttpserverrouter/qhttpserverrouter.pro
Normal file
5
tests/auto/qhttpserverrouter/qhttpserverrouter.pro
Normal file
@ -0,0 +1,5 @@
|
||||
CONFIG += testcase
|
||||
TARGET = tst_qhttpserverrouter
|
||||
SOURCES += tst_qhttpserverrouter.cpp
|
||||
|
||||
QT = httpserver testlib
|
225
tests/auto/qhttpserverrouter/tst_qhttpserverrouter.cpp
Normal file
225
tests/auto/qhttpserverrouter/tst_qhttpserverrouter.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtHttpServer/qhttpserverresponder.h>
|
||||
#include <QtHttpServer/qabstracthttpserver.h>
|
||||
#include <QtHttpServer/qhttpserverrouter.h>
|
||||
#include <QtHttpServer/qhttpserverrouterrule.h>
|
||||
|
||||
#include <QtTest/qsignalspy.h>
|
||||
#include <QtTest/qtest.h>
|
||||
#include <QtNetwork/qnetworkaccessmanager.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QNetworkAccessManager::Operation);
|
||||
|
||||
struct HttpServer : QAbstractHttpServer {
|
||||
QHttpServerRouter router;
|
||||
|
||||
HttpServer()
|
||||
: QAbstractHttpServer()
|
||||
{
|
||||
connect(this, &QAbstractHttpServer::missingHandler,
|
||||
[] (const QHttpServerRequest &request, QTcpSocket *socket) {
|
||||
makeResponder(request, socket).write(QHttpServerResponder::StatusCode::NotFound);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename ViewHandler>
|
||||
void route(const char *path, const QHttpServerRequest::Methods methods, ViewHandler &&viewHandler)
|
||||
{
|
||||
auto rule = new QHttpServerRouterRule(
|
||||
path, methods, [this, &viewHandler] (QRegularExpressionMatch &match,
|
||||
const QHttpServerRequest &request,
|
||||
QTcpSocket *socket) {
|
||||
auto boundViewHandler = router.bindCaptured<ViewHandler>(
|
||||
std::forward<ViewHandler>(viewHandler), match);
|
||||
boundViewHandler(makeResponder(request, socket));
|
||||
});
|
||||
|
||||
router.addRule<ViewHandler>(rule);
|
||||
}
|
||||
|
||||
template<typename ViewHandler>
|
||||
void route(const char *path, ViewHandler &&viewHandler)
|
||||
{
|
||||
route(path, QHttpServerRequest::Methods(nullptr), std::forward<ViewHandler>(viewHandler));
|
||||
}
|
||||
|
||||
bool handleRequest(const QHttpServerRequest &request, QTcpSocket *socket) override {
|
||||
return router.handleRequest(request, socket);
|
||||
}
|
||||
};
|
||||
|
||||
class tst_QHttpServerRouter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void routerRule_data();
|
||||
void routerRule();
|
||||
|
||||
private:
|
||||
HttpServer httpserver;
|
||||
QString urlBase;
|
||||
};
|
||||
|
||||
void tst_QHttpServerRouter::initTestCase()
|
||||
{
|
||||
httpserver.route("/page/", [] (const quint64 &page, QHttpServerResponder &&responder) {
|
||||
responder.write(QString("page: %1").arg(page).toUtf8(), "text/plain");
|
||||
});
|
||||
|
||||
httpserver.route("/post-only", QHttpServerRequest::Method::Post,
|
||||
[] (QHttpServerResponder &&responder) {
|
||||
responder.write(QString("post-test").toUtf8(), "text/plain");
|
||||
});
|
||||
|
||||
httpserver.route("/get-only", QHttpServerRequest::Method::Get,
|
||||
[] (QHttpServerResponder &&responder) {
|
||||
responder.write(QString("get-test").toUtf8(), "text/plain");
|
||||
});
|
||||
|
||||
urlBase = QStringLiteral("http://localhost:%1%2").arg(httpserver.listen());
|
||||
}
|
||||
|
||||
void tst_QHttpServerRouter::routerRule_data()
|
||||
{
|
||||
QTest::addColumn<QString>("url");
|
||||
QTest::addColumn<int>("code");
|
||||
QTest::addColumn<QString>("type");
|
||||
QTest::addColumn<QString>("body");
|
||||
QTest::addColumn<QNetworkAccessManager::Operation>("replyType");
|
||||
|
||||
QTest::addRow("/page/1")
|
||||
<< "/page/1"
|
||||
<< 200
|
||||
<< "text/plain"
|
||||
<< "page: 1"
|
||||
<< QNetworkAccessManager::GetOperation;
|
||||
|
||||
QTest::addRow("/page/-1")
|
||||
<< "/page/-1"
|
||||
<< 404
|
||||
<< "application/x-empty"
|
||||
<< ""
|
||||
<< QNetworkAccessManager::GetOperation;
|
||||
|
||||
QTest::addRow("/post-only [GET]")
|
||||
<< "/post-only"
|
||||
<< 404
|
||||
<< "application/x-empty"
|
||||
<< ""
|
||||
<< QNetworkAccessManager::GetOperation;
|
||||
|
||||
QTest::addRow("/post-only [DELETE]")
|
||||
<< "/post-only"
|
||||
<< 404
|
||||
<< "application/x-empty"
|
||||
<< ""
|
||||
<< QNetworkAccessManager::DeleteOperation;
|
||||
|
||||
QTest::addRow("/post-only [POST]")
|
||||
<< "/post-only"
|
||||
<< 200
|
||||
<< "text/plain"
|
||||
<< "post-test"
|
||||
<< QNetworkAccessManager::PostOperation;
|
||||
|
||||
QTest::addRow("/get-only [GET]")
|
||||
<< "/get-only"
|
||||
<< 200
|
||||
<< "text/plain"
|
||||
<< "get-test"
|
||||
<< QNetworkAccessManager::GetOperation;
|
||||
|
||||
QTest::addRow("/get-only [POST]")
|
||||
<< "/get-only"
|
||||
<< 404
|
||||
<< "application/x-empty"
|
||||
<< ""
|
||||
<< QNetworkAccessManager::PostOperation;
|
||||
|
||||
QTest::addRow("/get-only [DELETE]")
|
||||
<< "/get-only"
|
||||
<< 404
|
||||
<< "application/x-empty"
|
||||
<< ""
|
||||
<< QNetworkAccessManager::DeleteOperation;
|
||||
}
|
||||
|
||||
void tst_QHttpServerRouter::routerRule()
|
||||
{
|
||||
QFETCH(QString, url);
|
||||
QFETCH(int, code);
|
||||
QFETCH(QString, type);
|
||||
QFETCH(QString, body);
|
||||
QFETCH(QNetworkAccessManager::Operation, replyType);
|
||||
|
||||
QNetworkAccessManager networkAccessManager;
|
||||
QNetworkReply *reply;
|
||||
QNetworkRequest request(QUrl(urlBase.arg(url)));
|
||||
|
||||
switch (replyType) {
|
||||
case QNetworkAccessManager::GetOperation:
|
||||
reply = networkAccessManager.get(request);
|
||||
break;
|
||||
case QNetworkAccessManager::PostOperation:
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, type);
|
||||
reply = networkAccessManager.post(request, QByteArray("post body"));
|
||||
break;
|
||||
case QNetworkAccessManager::DeleteOperation:
|
||||
reply = networkAccessManager.deleteResource(request);
|
||||
break;
|
||||
default:
|
||||
QFAIL("The replyType does not supported");
|
||||
}
|
||||
|
||||
QTRY_VERIFY(reply->isFinished());
|
||||
|
||||
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), code);
|
||||
QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), type);
|
||||
QCOMPARE(reply->readAll(), body);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QTEST_MAIN(tst_QHttpServerRouter)
|
||||
|
||||
#include "tst_qhttpserverrouter.moc"
|
Loading…
x
Reference in New Issue
Block a user