Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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()
Expand Down
4 changes: 2 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -57,7 +57,7 @@ target_include_directories(qhttpengine PUBLIC
"$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>"
)

target_link_libraries(qhttpengine Qt5::Network)
target_link_libraries(qhttpengine Qt6::Network)

install(TARGETS qhttpengine EXPORT qhttpengine-export
RUNTIME DESTINATION "${BIN_INSTALL_DIR}"
Expand Down
4 changes: 2 additions & 2 deletions src/include/qhttpengine/handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
58 changes: 32 additions & 26 deletions src/include/qhttpengine/qobjecthandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -125,32 +125,34 @@ class QHTTPENGINE_EXPORT QObjectHandler : public Handler
typedef QtPrivate::FunctionPointer<Func1> 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<Socket*, typename QtPrivate::List_Select<typename SlotType::Arguments, 0>::Value>::value),
"The slot parameters do not match");
static_assert(std::is_invocable_v<Func1, typename QtPrivate::FunctionPointer<Func1>::Object*, Socket*>,
"The slot parameters do not match");

// Invoke the implementation
registerMethodImpl(name, receiver, new QtPrivate::QSlotObject<Func1, typename SlotType::Arguments, void>(slot), readAll);
registerMethodImpl(name, receiver, [slot, receiver](Socket *socket) {
if constexpr (std::is_member_function_pointer_v<Func1>) {
(receiver->*slot)(socket);
} else {
slot(socket);
}
}, readAll);
}

template <typename Func1>
inline typename QtPrivate::QEnableIf<!QtPrivate::AreArgumentsCompatible<Func1, QObject*>::value, void>::Type
registerMethod(const QString &name, Func1 slot, bool readAll = true) {
registerMethod(name, Q_NULLPTR, slot, readAll);
inline typename std::enable_if<!QtPrivate::AreArgumentsCompatible<Func1, QObject*>::value, void>::type
registerMethod(const QString &name, Func1 slot, bool readAll = true) {
registerMethod(name, nullptr, slot, readAll);
}

template <typename Func1>
inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
!std::is_same<const char*, Func1>::value,
#else
!QtPrivate::is_same<const char*, Func1>::value,
#endif
void>::Type
registerMethod(const QString &name, QObject *context, Func1 slot, bool readAll = true) {
inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
!std::is_same<const char*, Func1>::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
Expand All @@ -173,19 +175,23 @@ class QHTTPENGINE_EXPORT QObjectHandler : public Handler
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.");
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<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);
static_assert(std::is_invocable_v<Func1, Socket*>,
"The slot parameters do not match");

registerMethodImpl(name, context, [slot, context](Socket *socket) {
if constexpr (std::is_member_function_pointer_v<Func1>) {
(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<void(Socket*)> slot, bool readAll);

QObjectHandlerPrivate *const d;
friend class QObjectHandlerPrivate;
Expand Down
16 changes: 9 additions & 7 deletions src/src/handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand All @@ -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;
Expand All @@ -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;
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/src/handler_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@
#include <QList>
#include <QObject>
#include <QPair>
#include <QRegExp>
#include <QRegularExpression>

#include <qhttpengine/handler.h>

namespace QHttpEngine
{

typedef QPair<QRegExp, QString> Redirect;
typedef QPair<QRegExp, Handler*> SubHandler;
typedef QPair<QRegularExpression, QString> Redirect;
typedef QPair<QRegularExpression, Handler*> SubHandler;

class HandlerPrivate : public QObject
{
Expand Down
7 changes: 1 addition & 6 deletions src/src/proxysocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<void(QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error),
this,
&ProxySocket::onUpstreamError
);
connect(&mUpstreamSocket, &QAbstractSocket::errorOccurred, this, &ProxySocket::onUpstreamError);

mUpstreamSocket.connectToHost(address, port);
}
Expand Down
12 changes: 4 additions & 8 deletions src/src/qobjecthandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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<void(Socket*)> func, bool readAll)
{
d->map.insert(name, QObjectHandlerPrivate::Method(receiver, slotObj, readAll));
d->map.insert(name, QObjectHandlerPrivate::Method(receiver, func, readAll));
}
53 changes: 30 additions & 23 deletions src/src/qobjecthandler_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,50 +25,57 @@

#include <QMap>
#include <QObject>
#include <functional>

#include <qhttpengine/socket.h>

namespace QHttpEngine
{

class Socket;
class QObjectHandler;

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<void(Socket*)> 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<void(Socket*)> 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<QString, Method> map;

private:

QObjectHandler *const q;
};

Expand Down
12 changes: 7 additions & 5 deletions src/src/range.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
* IN THE SOFTWARE.
*/

#include <QRegExp>
#include <QRegularExpression>

#include <qhttpengine/range.h>

Expand All @@ -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.
Expand Down
5 changes: 2 additions & 3 deletions src/src/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ using namespace QHttpEngine;
ServerPrivate::ServerPrivate(Server *httpServer)
: QObject(httpServer),
q(httpServer),
handler(0)
handler(nullptr)
{
}

Expand Down Expand Up @@ -91,8 +91,7 @@ void Server::incomingConnection(qintptr socketDescriptor)
});

// If an error occurs, delete the socket
connect(socket, static_cast<void(QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error),
socket, &QSslSocket::deleteLater);
connect(socket, &QAbstractSocket::errorOccurred, socket, &QSslSocket::deleteLater);

socket->setSocketDescriptor(socketDescriptor);
socket->setSslConfiguration(d->configuration);
Expand Down