diff --git a/CMakeLists.txt b/CMakeLists.txt index 00871c7..801bd39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ set(INCLUDE_INSTALL_DIR include CACHE STRING "Header installation directory rela set(DOC_INSTALL_DIR share/doc/qhttpengine CACHE STRING "Documentation installation directory relative to the install prefix") set(EXAMPLES_INSTALL_DIR "${LIB_INSTALL_DIR}/qhttpengine/examples" CACHE STRING "Examples installation directory relative to the install prefix") -find_package(Qt5Network 5.4 REQUIRED) +find_package(Qt6Network REQUIRED) set(CMAKE_AUTOMOC ON) @@ -40,7 +40,7 @@ endif() option(BUILD_TESTS "Build the test suite" OFF) if(BUILD_TESTS) - find_package(Qt5Test 5.4 REQUIRED) + find_package(Qt6Test REQUIRED) enable_testing() add_subdirectory(tests) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2f6cef8..99db9ad 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,7 +42,7 @@ endif() add_library(qhttpengine ${HEADERS} ${SRC}) set_target_properties(qhttpengine PROPERTIES - CXX_STANDARD 11 + CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON DEFINE_SYMBOL QT_NO_SIGNALS_SLOTS_KEYWORDS DEFINE_SYMBOL QHTTPENGINE_LIBRARY @@ -57,7 +57,7 @@ target_include_directories(qhttpengine PUBLIC "$" ) -target_link_libraries(qhttpengine Qt5::Network) +target_link_libraries(qhttpengine Qt6::Network) install(TARGETS qhttpengine EXPORT qhttpengine-export RUNTIME DESTINATION "${BIN_INSTALL_DIR}" diff --git a/src/include/qhttpengine/handler.h b/src/include/qhttpengine/handler.h index 9dd3fab..bce5994 100644 --- a/src/include/qhttpengine/handler.h +++ b/src/include/qhttpengine/handler.h @@ -100,7 +100,7 @@ class QHTTPENGINE_EXPORT Handler : public QObject * The destination path may use "%1", "%2", etc. to refer to captured * 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 @@ -109,7 +109,7 @@ class QHTTPENGINE_EXPORT Handler : public QObject * used when the route() method is invoked to determine whether the * 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 diff --git a/src/include/qhttpengine/qobjecthandler.h b/src/include/qhttpengine/qobjecthandler.h index dfbc478..25da68a 100644 --- a/src/include/qhttpengine/qobjecthandler.h +++ b/src/include/qhttpengine/qobjecthandler.h @@ -82,7 +82,7 @@ class QHTTPENGINE_EXPORT QObjectHandler : public Handler /** * @brief Create a new QObject handler */ - explicit QObjectHandler(QObject *parent = 0); + explicit QObjectHandler(QObject *parent = nullptr); /** * @brief Register a method @@ -125,32 +125,34 @@ class QHTTPENGINE_EXPORT QObjectHandler : public Handler typedef QtPrivate::FunctionPointer 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."); + static_assert(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::Value>::value), - "The slot parameters do not match"); + static_assert(std::is_invocable_v::Object*, Socket*>, + "The slot parameters do not match"); // Invoke the implementation - registerMethodImpl(name, receiver, new QtPrivate::QSlotObject(slot), readAll); + registerMethodImpl(name, receiver, [slot, receiver](Socket *socket) { + if constexpr (std::is_member_function_pointer_v) { + (receiver->*slot)(socket); + } else { + slot(socket); + } + }, readAll); } template - inline typename QtPrivate::QEnableIf::value, void>::Type - registerMethod(const QString &name, Func1 slot, bool readAll = true) { - registerMethod(name, Q_NULLPTR, slot, readAll); + inline typename std::enable_if::value, void>::type + registerMethod(const QString &name, Func1 slot, bool readAll = true) { + registerMethod(name, nullptr, slot, readAll); } template - inline typename QtPrivate::QEnableIf::IsPointerToMemberFunction && -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) - !std::is_same::value, -#else - !QtPrivate::is_same::value, -#endif - void>::Type - registerMethod(const QString &name, QObject *context, Func1 slot, bool readAll = true) { + inline typename std::enable_if::IsPointerToMemberFunction && + !std::is_same::value, + 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 @@ -173,19 +175,23 @@ class QHTTPENGINE_EXPORT QObjectHandler : public Handler typedef QtPrivate::FunctionPointer 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."); + static_assert(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::Value>::value), - "The slot parameters do not match"); - - registerMethodImpl(name, context, - new QtPrivate::QFunctorSlotObject(slot), - readAll); + static_assert(std::is_invocable_v, + "The slot parameters do not match"); + + registerMethodImpl(name, context, [slot, context](Socket *socket) { + if constexpr (std::is_member_function_pointer_v) { + (context->*slot)(socket); + } else { + slot(socket); + } + }, readAll); } - void registerMethodImpl(const QString &name, QObject *receiver, QtPrivate::QSlotObjectBase *slotObj, bool readAll); + void registerMethodImpl(const QString &name, QObject *receiver, std::function slot, bool readAll); QObjectHandlerPrivate *const d; friend class QObjectHandlerPrivate; diff --git a/src/src/handler.cpp b/src/src/handler.cpp index c281e1f..6ff1539 100644 --- a/src/src/handler.cpp +++ b/src/src/handler.cpp @@ -45,12 +45,12 @@ void Handler::addMiddleware(Middleware *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)); } -void Handler::addSubHandler(const QRegExp &pattern, Handler *handler) +void Handler::addSubHandler(const QRegularExpression &pattern, Handler *handler) { d->subHandlers.append(SubHandler(pattern, handler)); } @@ -66,10 +66,11 @@ void Handler::route(Socket *socket, const QString &path) // Check each of the redirects for a match foreach (Redirect redirect, d->redirects) { - if (redirect.first.indexIn(path) != -1) { + QRegularExpressionMatch match = redirect.first.match(path); + if (match.hasMatch()) { QString newPath = redirect.second; - foreach (QString replacement, redirect.first.capturedTexts().mid(1)) { - newPath = newPath.arg(replacement); + for (int i = 1; i <= match.lastCapturedIndex(); ++i) { + newPath = newPath.arg(match.captured(i)); } socket->writeRedirect(newPath.toUtf8()); return; @@ -78,8 +79,9 @@ void Handler::route(Socket *socket, const QString &path) // Check each of the sub-handlers for a match foreach (SubHandler subHandler, d->subHandlers) { - if (subHandler.first.indexIn(path) != -1) { - subHandler.second->route(socket, path.mid(subHandler.first.matchedLength())); + QRegularExpressionMatch match = subHandler.first.match(path); + if (match.hasMatch()) { + subHandler.second->route(socket, path.mid(match.capturedLength())); return; } } diff --git a/src/src/handler_p.h b/src/src/handler_p.h index b1d2927..2b39075 100644 --- a/src/src/handler_p.h +++ b/src/src/handler_p.h @@ -26,15 +26,15 @@ #include #include #include -#include +#include #include namespace QHttpEngine { -typedef QPair Redirect; -typedef QPair SubHandler; +typedef QPair Redirect; +typedef QPair SubHandler; class HandlerPrivate : public QObject { diff --git a/src/src/proxysocket.cpp b/src/src/proxysocket.cpp index cbcde7c..db55a9e 100644 --- a/src/src/proxysocket.cpp +++ b/src/src/proxysocket.cpp @@ -38,12 +38,7 @@ ProxySocket::ProxySocket(Socket *socket, const QString &path, const QHostAddress connect(&mUpstreamSocket, &QTcpSocket::connected, this, &ProxySocket::onUpstreamConnected); connect(&mUpstreamSocket, &QTcpSocket::readyRead, this, &ProxySocket::onUpstreamReadyRead); - connect( - &mUpstreamSocket, - static_cast(&QAbstractSocket::error), - this, - &ProxySocket::onUpstreamError - ); + connect(&mUpstreamSocket, &QAbstractSocket::errorOccurred, this, &ProxySocket::onUpstreamError); mUpstreamSocket.connectToHost(address, port); } diff --git a/src/src/qobjecthandler.cpp b/src/src/qobjecthandler.cpp index fdf3330..256fc01 100644 --- a/src/src/qobjecthandler.cpp +++ b/src/src/qobjecthandler.cpp @@ -48,7 +48,7 @@ void QObjectHandlerPrivate::invokeSlot(Socket *socket, Method m) if (m.oldSlot) { // Obtain the slot index - int index = m.receiver->metaObject()->indexOfSlot(m.slot.method + 1); + int index = m.receiver->metaObject()->indexOfSlot(m.method + 1); if (index == -1) { socket->writeError(Socket::InternalServerError); return; @@ -70,11 +70,7 @@ void QObjectHandlerPrivate::invokeSlot(Socket *socket, Method m) return; } } else { - void *args[] = { - Q_NULLPTR, - &socket - }; - m.slot.slotObj->call(m.receiver, args); + m.func(socket); } } @@ -104,7 +100,7 @@ void QObjectHandler::registerMethod(const QString &name, QObject *receiver, cons 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 *receiver, std::function func, bool readAll) { - d->map.insert(name, QObjectHandlerPrivate::Method(receiver, slotObj, readAll)); + d->map.insert(name, QObjectHandlerPrivate::Method(receiver, func, readAll)); } diff --git a/src/src/qobjecthandler_p.h b/src/src/qobjecthandler_p.h index 190f9ee..3895406 100644 --- a/src/src/qobjecthandler_p.h +++ b/src/src/qobjecthandler_p.h @@ -25,11 +25,13 @@ #include #include +#include + +#include namespace QHttpEngine { -class Socket; class QObjectHandler; class QObjectHandlerPrivate : public QObject @@ -37,38 +39,43 @@ class QObjectHandlerPrivate : public QObject Q_OBJECT public: + struct Method { + QObject *receiver; + bool oldSlot; + bool readAll; - explicit QObjectHandlerPrivate(QObjectHandler *handler); + // For old-style slots + const char *method; - // In order to invoke the slot, a "pointer" to it needs to be stored in a - // map that lets us look up information by method name + // For new-style slots + std::function func; - class Method { - public: - Method() {} - Method(QObject *receiver, const char *method, bool readAll) - : receiver(receiver), oldSlot(true), slot(method), readAll(readAll) {} - Method(QObject *receiver, QtPrivate::QSlotObjectBase *slotObj, bool readAll) - : receiver(receiver), oldSlot(false), slot(slotObj), readAll(readAll) {} + // Default constructor + Method() + : receiver(nullptr), oldSlot(false), readAll(false), method(nullptr) + { + } - QObject *receiver; - bool oldSlot; - union slot{ - slot() {} - slot(const char *method) : method(method) {} - slot(QtPrivate::QSlotObjectBase *slotObj) : slotObj(slotObj) {} - const char *method; - QtPrivate::QSlotObjectBase *slotObj; - } slot; - bool readAll; + // Constructor for old-style slots + Method(QObject *receiver, const char *method, bool readAll) + : receiver(receiver), oldSlot(true), readAll(readAll), method(method) + { + } + + // Constructor for new-style slots + Method(QObject *receiver, std::function func, bool readAll) + : receiver(receiver), oldSlot(false), readAll(readAll), func(func) + { + } }; - void invokeSlot(Socket*socket, Method m); + QObjectHandlerPrivate(QObjectHandler *handler); + + void invokeSlot(Socket *socket, Method m); QMap map; private: - QObjectHandler *const q; }; diff --git a/src/src/range.cpp b/src/src/range.cpp index aa9e29e..b759785 100644 --- a/src/src/range.cpp +++ b/src/src/range.cpp @@ -20,7 +20,7 @@ * IN THE SOFTWARE. */ -#include +#include #include @@ -44,13 +44,15 @@ Range::Range() Range::Range(const QString &range, qint64 dataSize) : d(new RangePrivate(this)) { - QRegExp regExp("^(\\d*)-(\\d*)$"); + QRegularExpression regExp("^(\\d*)-(\\d*)$"); int from = 0, to = -1; - if (regExp.indexIn(range.trimmed()) != -1) { - QString fromStr = regExp.cap(1); - QString toStr = regExp.cap(2); + QRegularExpressionMatch match = regExp.match(range.trimmed()); + + if (match.hasMatch()) { + QString fromStr = match.captured(1); + QString toStr = match.captured(2); // If both strings are empty - range is invalid. Setting to out of // bounds range and returning. diff --git a/src/src/server.cpp b/src/src/server.cpp index e27593e..d753d6f 100644 --- a/src/src/server.cpp +++ b/src/src/server.cpp @@ -34,7 +34,7 @@ using namespace QHttpEngine; ServerPrivate::ServerPrivate(Server *httpServer) : QObject(httpServer), q(httpServer), - handler(0) + handler(nullptr) { } @@ -91,8 +91,7 @@ void Server::incomingConnection(qintptr socketDescriptor) }); // If an error occurs, delete the socket - connect(socket, static_cast(&QAbstractSocket::error), - socket, &QSslSocket::deleteLater); + connect(socket, &QAbstractSocket::errorOccurred, socket, &QSslSocket::deleteLater); socket->setSocketDescriptor(socketDescriptor); socket->setSslConfiguration(d->configuration);