/* * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifndef QHTTPENGINE_QOBJECTHANDLER_H #define QHTTPENGINE_QOBJECTHANDLER_H #include #include "qhttpengine_global.h" class QHttpSocket; class QJsonDocument; class QHTTPENGINE_EXPORT QObjectHandlerPrivate; /** * @brief Handler for invoking slots * @headerfile qobjecthandler.h QHttpEngine/QObjectHandler * * This handler enables incoming requests to be processed by slots in a * QObject-derived class or functor. Methods are registered by providing a * name and slot to invoke. The slot may take a pointer to the QHttpSocket for * the request as an argument. * * To use this class, simply create an instance and call the appropriate * registerMethod() overload. For example: * * @code * class Object : public QObject * { * Q_OBJECT * public slots: * void something(QHttpSocket *socket); * }; * * QObjectHandler handler; * Object object; * // Old connection syntax * handler.registerMethod("something", &object, SLOT(something(QHttpSocket*))); * // New connection syntax * handler.registerMethod("something", &object, &Object::something); * @endcode * * It is also possible to use this class with a functor, eliminating the need * to create a class and slot: * * @code * QObjectHandler handler; * handler.registerMethod("something", [](QHttpSocket *socket) { * // do something * }); * @endcode */ class QHTTPENGINE_EXPORT QObjectHandler : public QHttpHandler { Q_OBJECT public: /** * @brief Create a new QObject handler */ explicit QObjectHandler(QObject *parent = 0); /** * @brief Register a method * * 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); #ifdef DOXYGEN /** * @brief Register a method * * This overload uses the new connection syntax with member pointers. */ void registerMethod(const QString &name, QObject *receiver, PointerToMemberFunction method, bool readAll = true); /** * @brief Register a method * * 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 inline void registerMethod(const QString &name, typename QtPrivate::FunctionPointer::Object *receiver, Func1 slot, bool readAll = true) { 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."); // Ensure the argument is of the correct type Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible::Value>::value), "The slot parameters do not match"); // Invoke the implementation registerMethodImpl(name, receiver, new QtPrivate::QSlotObject(slot), readAll); } template inline typename QtPrivate::QEnableIf::value, void>::Type registerMethod(const QString &name, Func1 slot, bool readAll = true) { registerMethod(name, Q_NULLPTR, slot, readAll); } template inline typename QtPrivate::QEnableIf::IsPointerToMemberFunction && !QtPrivate::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 return registerMethod_functor(name, context, slot, &Func1::operator(), readAll); } #endif /** * @brief Read the request data from the socket as a JSON document * * If an error occurs reading the request, an error is automatically * written to the socket. */ static bool readJson(QHttpSocket *socket, QJsonDocument &document); protected: /** * @brief Reimplementation of QHttpHandler::process() */ virtual void process(QHttpSocket *socket, const QString &path); private: template inline void registerMethod_functor(const QString &name, QObject *context, Func1 slot, Func1Operator, bool readAll) { 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."); // 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); } void registerMethodImpl(const QString &name, QObject *receiver, QtPrivate::QSlotObjectBase *slotObj, bool readAll); QObjectHandlerPrivate *const d; friend class QObjectHandlerPrivate; }; #endif // QHTTPENGINE_QOBJECTHANDLER_H