Fixes for TirugaDashboard
This commit is contained in:
@@ -24,11 +24,10 @@
|
|||||||
#define QHTTPENGINE_HANDLER_H
|
#define QHTTPENGINE_HANDLER_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "qhttpengine_export.h"
|
#include "qhttpengine_export.h"
|
||||||
|
|
||||||
class QRegExp;
|
|
||||||
|
|
||||||
namespace QHttpEngine
|
namespace QHttpEngine
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -49,24 +48,24 @@ class QHTTPENGINE_EXPORT HandlerPrivate;
|
|||||||
* match.
|
* match.
|
||||||
*
|
*
|
||||||
* To add a redirect, use the addRedirect() method. The first parameter is a
|
* To add a redirect, use the addRedirect() method. The first parameter is a
|
||||||
* QRegExp pattern that the request path will be tested against. If it
|
* QRegularExpression pattern that the request path will be tested against. If it
|
||||||
* matches, an HTTP 302 redirect will be written to the socket and the request
|
* matches, an HTTP 302 redirect will be written to the socket and the request
|
||||||
* closed. For example, to have the root path "/" redirect to "/index.html":
|
* closed. For example, to have the root path "/" redirect to "/index.html":
|
||||||
*
|
*
|
||||||
* @code
|
* @code
|
||||||
* QHttpEngine::Handler handler;
|
* QHttpEngine::Handler handler;
|
||||||
* handler.addRedirect(QRegExp("^$"), "/index.html");
|
* handler.addRedirect(QRegularExpression("^$"), "/index.html");
|
||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* To add a sub-handler, use the addSubHandler() method. Again, the first
|
* To add a sub-handler, use the addSubHandler() method. Again, the first
|
||||||
* parameter is a QRegExp pattern. If the pattern matches, the portion of the
|
* parameter is a QRegularExpression pattern. If the pattern matches, the portion of the
|
||||||
* path that matched the pattern is removed from the path and it is passed to
|
* path that matched the pattern is removed from the path and it is passed to
|
||||||
* the sub-handler's route() method. For example, to have a sub-handler
|
* the sub-handler's route() method. For example, to have a sub-handler
|
||||||
* invoked when the path begins with "/api/":
|
* invoked when the path begins with "/api/":
|
||||||
*
|
*
|
||||||
* @code
|
* @code
|
||||||
* QHttpEngine::Handler handler, subHandler;
|
* QHttpEngine::Handler handler, subHandler;
|
||||||
* handler.addSubHandler(QRegExp("^api/"), &subHandler);
|
* handler.addSubHandler(QRegularExpression("^api/"), &subHandler);
|
||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* If the request doesn't match any redirect or sub-handler patterns, it is
|
* If the request doesn't match any redirect or sub-handler patterns, it is
|
||||||
@@ -100,7 +99,7 @@ public:
|
|||||||
* The destination path may use "%1", "%2", etc. to refer to captured
|
* The destination path may use "%1", "%2", etc. to refer to captured
|
||||||
* parts of the pattern. The client will receive an HTTP 302 redirect.
|
* parts of the pattern. The client will receive an HTTP 302 redirect.
|
||||||
*/
|
*/
|
||||||
void addRedirect(const QRegExp &pattern, const QString &path);
|
void addRedirect(const QRegularExpression &pattern, const QString &path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add a handler for a specific pattern
|
* @brief Add a handler for a specific pattern
|
||||||
@@ -109,7 +108,7 @@ public:
|
|||||||
* used when the route() method is invoked to determine whether the
|
* used when the route() method is invoked to determine whether the
|
||||||
* request matches any patterns. The order of the list is preserved.
|
* request matches any patterns. The order of the list is preserved.
|
||||||
*/
|
*/
|
||||||
void addSubHandler(const QRegExp &pattern, Handler *handler);
|
void addSubHandler(const QRegularExpression &pattern, Handler *handler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Route an incoming request
|
* @brief Route an incoming request
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#include <qhttpengine/handler.h>
|
#include <qhttpengine/handler.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "qhttpengine_export.h"
|
#include "qhttpengine_export.h"
|
||||||
|
|
||||||
namespace QHttpEngine
|
namespace QHttpEngine
|
||||||
@@ -56,10 +58,7 @@ class QHTTPENGINE_EXPORT QObjectHandlerPrivate;
|
|||||||
*
|
*
|
||||||
* QHttpEngine::QObjectHandler handler;
|
* QHttpEngine::QObjectHandler handler;
|
||||||
* Object object;
|
* Object object;
|
||||||
* // Old connection syntax
|
|
||||||
* handler.registerMethod("something", &object, SLOT(something(QHttpEngine::Socket*)));
|
* handler.registerMethod("something", &object, SLOT(something(QHttpEngine::Socket*)));
|
||||||
* // New connection syntax
|
|
||||||
* handler.registerMethod("something", &object, &Object::something);
|
|
||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* It is also possible to use this class with a functor, eliminating the need
|
* It is also possible to use this class with a functor, eliminating the need
|
||||||
@@ -85,79 +84,39 @@ public:
|
|||||||
explicit QObjectHandler(QObject *parent = 0);
|
explicit QObjectHandler(QObject *parent = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register a method
|
* @brief Register a method using slot macro (Qt5/6 compatible)
|
||||||
*
|
|
||||||
* This overload uses the traditional connection syntax with macros.
|
|
||||||
*
|
|
||||||
* The readAll parameter determines whether all data must be received by
|
|
||||||
* the socket before invoking the slot.
|
|
||||||
*/
|
*/
|
||||||
void registerMethod(const QString &name, QObject *receiver, const char *method, bool readAll = true);
|
void registerMethod(const QString &name, QObject *receiver, const char *method, bool readAll = true);
|
||||||
|
|
||||||
#ifdef DOXYGEN
|
|
||||||
/**
|
/**
|
||||||
* @brief Register a method
|
* @brief Register a method using member function pointer
|
||||||
*
|
|
||||||
* This overload uses the new connection syntax with member pointers.
|
|
||||||
*/
|
*/
|
||||||
void registerMethod(const QString &name, QObject *receiver, PointerToMemberFunction method, bool readAll = true);
|
template <typename Func>
|
||||||
|
void registerMethod(const QString &name,
|
||||||
/**
|
typename QtPrivate::FunctionPointer<Func>::Object *receiver,
|
||||||
* @brief Register a method
|
Func slot,
|
||||||
*
|
|
||||||
* This overload uses the new functor syntax (without context).
|
|
||||||
*/
|
|
||||||
void registerMethod(const QString &name, Functor functor, bool readAll = true);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Register a method
|
|
||||||
*
|
|
||||||
* This overload uses the new functor syntax (with context).
|
|
||||||
*/
|
|
||||||
void registerMethod(const QString &name, QObject *receiver, Functor functor, bool readAll = true);
|
|
||||||
#else
|
|
||||||
template <typename Func1>
|
|
||||||
inline void registerMethod(const QString &name,
|
|
||||||
typename QtPrivate::FunctionPointer<Func1>::Object *receiver,
|
|
||||||
Func1 slot,
|
|
||||||
bool readAll = true) {
|
bool readAll = true) {
|
||||||
|
// Wrap the member function call
|
||||||
typedef QtPrivate::FunctionPointer<Func1> SlotType;
|
registerMethodImpl(name, receiver, [receiver, slot](Socket *socket) {
|
||||||
|
(receiver->*slot)(socket);
|
||||||
// Ensure the slot doesn't have too many arguments
|
}, readAll);
|
||||||
Q_STATIC_ASSERT_X(int(SlotType::ArgumentCount) == 1,
|
|
||||||
"The slot must have exactly one argument.");
|
|
||||||
|
|
||||||
// Ensure the argument is of the correct type
|
|
||||||
Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<Socket*, typename QtPrivate::List_Select<typename SlotType::Arguments, 0>::Value>::value),
|
|
||||||
"The slot parameters do not match");
|
|
||||||
|
|
||||||
// Invoke the implementation
|
|
||||||
registerMethodImpl(name, receiver, new QtPrivate::QSlotObject<Func1, typename SlotType::Arguments, void>(slot), readAll);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Func1>
|
/**
|
||||||
inline typename std::enable_if<!QtPrivate::AreArgumentsCompatible<Func1, QObject*>::value, void>::type
|
* @brief Register a method using functor (Qt6 compatible)
|
||||||
registerMethod(const QString &name, Func1 slot, bool readAll = true) {
|
*/
|
||||||
registerMethod(name, Q_NULLPTR, slot, readAll);
|
template <typename Func>
|
||||||
|
void registerMethod(const QString &name, Func slot, bool readAll = true) {
|
||||||
|
registerMethodImpl(name, Q_NULLPTR, slot, readAll);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Func1>
|
/**
|
||||||
inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
|
* @brief Register a method using functor with context
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
|
*/
|
||||||
!std::is_same<const char*, Func1>::value,
|
template <typename Func>
|
||||||
#else
|
void registerMethod(const QString &name, QObject *context, Func slot, bool readAll = true) {
|
||||||
!QtPrivate::is_same<const char*, Func1>::value,
|
registerMethodImpl(name, context, slot, readAll);
|
||||||
#endif
|
|
||||||
void>::type
|
|
||||||
registerMethod(const QString &name, QObject *context, Func1 slot, bool readAll = true) {
|
|
||||||
|
|
||||||
// There is an easier way to do this but then the header wouldn't
|
|
||||||
// compile on non-C++11 compilers
|
|
||||||
return registerMethod_functor(name, context, slot, &Func1::operator(), readAll);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -168,25 +127,9 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
template <typename Func1, typename Func1Operator>
|
// Store callbacks using std::function for Qt6 compatibility
|
||||||
inline void registerMethod_functor(const QString &name, QObject *context, Func1 slot, Func1Operator, bool readAll) {
|
void registerMethodImpl(const QString &name, QObject *context,
|
||||||
|
std::function<void(Socket*)> callback, bool readAll);
|
||||||
typedef QtPrivate::FunctionPointer<Func1Operator> SlotType;
|
|
||||||
|
|
||||||
// Ensure the slot doesn't have too many arguments
|
|
||||||
Q_STATIC_ASSERT_X(int(SlotType::ArgumentCount) == 1,
|
|
||||||
"The slot must have exactly one argument.");
|
|
||||||
|
|
||||||
// Ensure the argument is of the correct type
|
|
||||||
Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<Socket*, typename QtPrivate::List_Select<typename SlotType::Arguments, 0>::Value>::value),
|
|
||||||
"The slot parameters do not match");
|
|
||||||
|
|
||||||
registerMethodImpl(name, context,
|
|
||||||
new QtPrivate::QFunctorSlotObject<Func1, 1, typename SlotType::Arguments, void>(slot),
|
|
||||||
readAll);
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerMethodImpl(const QString &name, QObject *receiver, QtPrivate::QSlotObjectBase *slotObj, bool readAll);
|
|
||||||
|
|
||||||
QObjectHandlerPrivate *const d;
|
QObjectHandlerPrivate *const d;
|
||||||
friend class QObjectHandlerPrivate;
|
friend class QObjectHandlerPrivate;
|
||||||
|
|||||||
@@ -45,12 +45,12 @@ void Handler::addMiddleware(Middleware *middleware)
|
|||||||
d->middleware.append(middleware);
|
d->middleware.append(middleware);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Handler::addRedirect(const QRegExp &pattern, const QString &path)
|
void Handler::addRedirect(const QRegularExpression &pattern, const QString &path)
|
||||||
{
|
{
|
||||||
d->redirects.append(Redirect(pattern, path));
|
d->redirects.append(Redirect(pattern, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Handler::addSubHandler(const QRegExp &pattern, Handler *handler)
|
void Handler::addSubHandler(const QRegularExpression &pattern, Handler *handler)
|
||||||
{
|
{
|
||||||
d->subHandlers.append(SubHandler(pattern, handler));
|
d->subHandlers.append(SubHandler(pattern, handler));
|
||||||
}
|
}
|
||||||
@@ -58,18 +58,20 @@ void Handler::addSubHandler(const QRegExp &pattern, Handler *handler)
|
|||||||
void Handler::route(Socket *socket, const QString &path)
|
void Handler::route(Socket *socket, const QString &path)
|
||||||
{
|
{
|
||||||
// Run through each of the middleware
|
// Run through each of the middleware
|
||||||
foreach (Middleware *middleware, d->middleware) {
|
for (Middleware *middleware : d->middleware) {
|
||||||
if (!middleware->process(socket)) {
|
if (!middleware->process(socket)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check each of the redirects for a match
|
// Check each of the redirects for a match
|
||||||
foreach (Redirect redirect, d->redirects) {
|
for (Redirect &redirect : d->redirects) {
|
||||||
if (redirect.first.indexIn(path) != -1) {
|
QRegularExpressionMatch match = redirect.first.match(path);
|
||||||
|
if (match.hasMatch()) {
|
||||||
QString newPath = redirect.second;
|
QString newPath = redirect.second;
|
||||||
foreach (QString replacement, redirect.first.capturedTexts().mid(1)) {
|
QStringList captured = match.capturedTexts();
|
||||||
newPath = newPath.arg(replacement);
|
for (int i = 1; i < captured.size(); ++i) {
|
||||||
|
newPath = newPath.arg(captured.at(i));
|
||||||
}
|
}
|
||||||
socket->writeRedirect(newPath.toUtf8());
|
socket->writeRedirect(newPath.toUtf8());
|
||||||
return;
|
return;
|
||||||
@@ -77,9 +79,10 @@ void Handler::route(Socket *socket, const QString &path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check each of the sub-handlers for a match
|
// Check each of the sub-handlers for a match
|
||||||
foreach (SubHandler subHandler, d->subHandlers) {
|
for (SubHandler &subHandler : d->subHandlers) {
|
||||||
if (subHandler.first.indexIn(path) != -1) {
|
QRegularExpressionMatch match = subHandler.first.match(path);
|
||||||
subHandler.second->route(socket, path.mid(subHandler.first.matchedLength()));
|
if (match.hasMatch()) {
|
||||||
|
subHandler.second->route(socket, path.mid(match.capturedLength()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,15 +26,15 @@
|
|||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
#include <QRegExp>
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include <qhttpengine/handler.h>
|
#include <qhttpengine/handler.h>
|
||||||
|
|
||||||
namespace QHttpEngine
|
namespace QHttpEngine
|
||||||
{
|
{
|
||||||
|
|
||||||
typedef QPair<QRegExp, QString> Redirect;
|
typedef QPair<QRegularExpression, QString> Redirect;
|
||||||
typedef QPair<QRegExp, Handler*> SubHandler;
|
typedef QPair<QRegularExpression, Handler*> SubHandler;
|
||||||
|
|
||||||
class HandlerPrivate : public QObject
|
class HandlerPrivate : public QObject
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ void QObjectHandlerPrivate::invokeSlot(Socket *socket, Method m)
|
|||||||
if (m.oldSlot) {
|
if (m.oldSlot) {
|
||||||
|
|
||||||
// Obtain the slot index
|
// Obtain the slot index
|
||||||
int index = m.receiver->metaObject()->indexOfSlot(m.slot.method + 1);
|
int index = m.receiver->metaObject()->indexOfMethod(m.slotMethod + 1);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
socket->writeError(Socket::InternalServerError);
|
socket->writeError(Socket::InternalServerError);
|
||||||
return;
|
return;
|
||||||
@@ -64,17 +64,17 @@ void QObjectHandlerPrivate::invokeSlot(Socket *socket, Method m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke the method
|
// Invoke the method
|
||||||
if (!m.receiver->metaObject()->method(index).invoke(
|
if (!method.invoke(m.receiver, Q_ARG(Socket*, socket))) {
|
||||||
m.receiver, Q_ARG(Socket*, socket))) {
|
|
||||||
socket->writeError(Socket::InternalServerError);
|
socket->writeError(Socket::InternalServerError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
void *args[] = {
|
// Call the std::function callback
|
||||||
Q_NULLPTR,
|
if (m.callback) {
|
||||||
&socket
|
m.callback(socket);
|
||||||
};
|
} else {
|
||||||
m.slot.slotObj->call(m.receiver, args);
|
socket->writeError(Socket::InternalServerError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +104,8 @@ void QObjectHandler::registerMethod(const QString &name, QObject *receiver, cons
|
|||||||
d->map.insert(name, QObjectHandlerPrivate::Method(receiver, method, readAll));
|
d->map.insert(name, QObjectHandlerPrivate::Method(receiver, method, readAll));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QObjectHandler::registerMethodImpl(const QString &name, QObject *receiver, QtPrivate::QSlotObjectBase *slotObj, bool readAll)
|
void QObjectHandler::registerMethodImpl(const QString &name, QObject *context,
|
||||||
|
std::function<void(Socket*)> callback, bool readAll)
|
||||||
{
|
{
|
||||||
d->map.insert(name, QObjectHandlerPrivate::Method(receiver, slotObj, readAll));
|
d->map.insert(name, QObjectHandlerPrivate::Method(callback, readAll));
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace QHttpEngine
|
namespace QHttpEngine
|
||||||
{
|
{
|
||||||
@@ -47,23 +48,18 @@ public:
|
|||||||
public:
|
public:
|
||||||
Method() {}
|
Method() {}
|
||||||
Method(QObject *receiver, const char *method, bool readAll)
|
Method(QObject *receiver, const char *method, bool readAll)
|
||||||
: receiver(receiver), oldSlot(true), slot(method), readAll(readAll) {}
|
: receiver(receiver), oldSlot(true), slotMethod(method), readAll(readAll) {}
|
||||||
Method(QObject *receiver, QtPrivate::QSlotObjectBase *slotObj, bool readAll)
|
Method(std::function<void(Socket*)> callback, bool readAll)
|
||||||
: receiver(receiver), oldSlot(false), slot(slotObj), readAll(readAll) {}
|
: receiver(nullptr), oldSlot(false), callback(callback), readAll(readAll) {}
|
||||||
|
|
||||||
QObject *receiver;
|
QObject *receiver = nullptr;
|
||||||
bool oldSlot;
|
bool oldSlot;
|
||||||
union slot{
|
const char *slotMethod = nullptr;
|
||||||
slot() {}
|
std::function<void(Socket*)> callback;
|
||||||
slot(const char *method) : method(method) {}
|
|
||||||
slot(QtPrivate::QSlotObjectBase *slotObj) : slotObj(slotObj) {}
|
|
||||||
const char *method;
|
|
||||||
QtPrivate::QSlotObjectBase *slotObj;
|
|
||||||
} slot;
|
|
||||||
bool readAll;
|
bool readAll;
|
||||||
};
|
};
|
||||||
|
|
||||||
void invokeSlot(Socket*socket, Method m);
|
void invokeSlot(Socket *socket, Method m);
|
||||||
|
|
||||||
QMap<QString, Method> map;
|
QMap<QString, Method> map;
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QRegExp>
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include <qhttpengine/range.h>
|
#include <qhttpengine/range.h>
|
||||||
|
|
||||||
@@ -44,13 +44,14 @@ Range::Range()
|
|||||||
Range::Range(const QString &range, qint64 dataSize)
|
Range::Range(const QString &range, qint64 dataSize)
|
||||||
: d(new RangePrivate(this))
|
: d(new RangePrivate(this))
|
||||||
{
|
{
|
||||||
QRegExp regExp("^(\\d*)-(\\d*)$");
|
QRegularExpression regExp("^(\\d*)-(\\d*)$");
|
||||||
|
|
||||||
int from = 0, to = -1;
|
int from = 0, to = -1;
|
||||||
|
|
||||||
if (regExp.indexIn(range.trimmed()) != -1) {
|
QRegularExpressionMatch match = regExp.match(range.trimmed());
|
||||||
QString fromStr = regExp.cap(1);
|
if (match.hasMatch()) {
|
||||||
QString toStr = regExp.cap(2);
|
QString fromStr = match.captured(1);
|
||||||
|
QString toStr = match.captured(2);
|
||||||
|
|
||||||
// If both strings are empty - range is invalid. Setting to out of
|
// If both strings are empty - range is invalid. Setting to out of
|
||||||
// bounds range and returning.
|
// bounds range and returning.
|
||||||
|
|||||||
Reference in New Issue
Block a user