| 1 | // Copyright (C) 2019 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
| 3 | |
| 4 | #ifndef QHTTPSERVERROUTERRULE_H |
| 5 | #define QHTTPSERVERROUTERRULE_H |
| 6 | |
| 7 | #include <QtHttpServer/qhttpserverrequest.h> |
| 8 | #include <QtHttpServer/qhttpserverresponder.h> |
| 9 | #include <QtHttpServer/qhttpserverrouterviewtraits.h> |
| 10 | |
| 11 | #include <QtCore/qcontainerfwd.h> |
| 12 | #include <QtCore/qregularexpression.h> |
| 13 | |
| 14 | #include <initializer_list> |
| 15 | #include <memory> |
| 16 | |
| 17 | QT_BEGIN_NAMESPACE |
| 18 | |
| 19 | class QString; |
| 20 | class QHttpServerRequest; |
| 21 | class QHttpServerResponder; |
| 22 | class QRegularExpressionMatch; |
| 23 | class QHttpServerRouter; |
| 24 | |
| 25 | class QHttpServerRouterRulePrivate; |
| 26 | class Q_HTTPSERVER_EXPORT QHttpServerRouterRule |
| 27 | { |
| 28 | Q_DECLARE_PRIVATE(QHttpServerRouterRule) |
| 29 | Q_DISABLE_COPY_MOVE(QHttpServerRouterRule) |
| 30 | |
| 31 | private: |
| 32 | using RouterHandlerPrototype = void (*)(const QRegularExpressionMatch &, |
| 33 | const QHttpServerRequest &, QHttpServerResponder &); |
| 34 | |
| 35 | template <typename T> |
| 36 | using if_routerhandler_prototype_compatible = typename std::enable_if< |
| 37 | QtPrivate::AreFunctionsCompatible<RouterHandlerPrototype, T>::value, bool>::type; |
| 38 | |
| 39 | QHttpServerRouterRule(const QString &pathPattern, const QHttpServerRequest::Methods methods, |
| 40 | const QObject *context, QtPrivate::QSlotObjectBase *slotObjRaw); |
| 41 | |
| 42 | public: |
| 43 | #ifdef Q_QDOC |
| 44 | template <typename Functor> |
| 45 | QHttpServerRouterRule( |
| 46 | const QString &pathPattern, const QHttpServerRequest::Methods methods, |
| 47 | const QObject *receiver, |
| 48 | Functor &&slot); |
| 49 | |
| 50 | template <typename Functor> |
| 51 | QHttpServerRouterRule( |
| 52 | const QString &pathPattern, |
| 53 | const QObject *receiver, |
| 54 | Functor &&slot); |
| 55 | #else |
| 56 | template <typename Handler, if_routerhandler_prototype_compatible<Handler> = true> |
| 57 | QHttpServerRouterRule( |
| 58 | const QString &pathPattern, |
| 59 | const typename QtPrivate::ContextTypeForFunctor<Handler>::ContextType *context, |
| 60 | Handler &&func) |
| 61 | : QHttpServerRouterRule( |
| 62 | pathPattern, QHttpServerRequest::Method::AnyKnown, context, |
| 63 | QtPrivate::makeCallableObject<RouterHandlerPrototype>(std::forward<Handler>(func))) |
| 64 | { |
| 65 | } |
| 66 | |
| 67 | template <typename Handler, if_routerhandler_prototype_compatible<Handler> = true> |
| 68 | QHttpServerRouterRule( |
| 69 | const QString &pathPattern, const QHttpServerRequest::Methods methods, |
| 70 | const typename QtPrivate::ContextTypeForFunctor<Handler>::ContextType *context, |
| 71 | Handler &&func) |
| 72 | : QHttpServerRouterRule( |
| 73 | pathPattern, methods, context, |
| 74 | QtPrivate::makeCallableObject<RouterHandlerPrototype>(std::forward<Handler>(func))) |
| 75 | { |
| 76 | } |
| 77 | #endif |
| 78 | |
| 79 | #ifdef Q_QDOC |
| 80 | template <typename Functor, typename ViewTraits = QHttpServerRouterViewTraits<Functor>> |
| 81 | static typename ViewTraits::BindableType bindCaptured( |
| 82 | QObject *receiver, |
| 83 | Functor &&slot, |
| 84 | const QRegularExpressionMatch &match) const; |
| 85 | # else |
| 86 | template<typename ViewHandler, typename ViewTraits = QHttpServerRouterViewTraits<ViewHandler>> |
| 87 | static typename ViewTraits::BindableType bindCaptured( |
| 88 | const typename QtPrivate::ContextTypeForFunctor<ViewHandler>::ContextType *context, |
| 89 | ViewHandler &&handler, |
| 90 | const QRegularExpressionMatch &match) |
| 91 | { |
| 92 | return bindCapturedImpl<ViewHandler, ViewTraits>( |
| 93 | context, std::forward<ViewHandler>(handler), match, |
| 94 | typename ViewTraits::Arguments::CapturableIndexes{}); |
| 95 | } |
| 96 | #endif |
| 97 | |
| 98 | const QObject *contextObject() const; |
| 99 | |
| 100 | virtual ~QHttpServerRouterRule(); |
| 101 | |
| 102 | protected: |
| 103 | bool exec(const QHttpServerRequest &request, QHttpServerResponder &responder) const; |
| 104 | |
| 105 | bool hasValidMethods() const; |
| 106 | |
| 107 | bool createPathRegexp(std::initializer_list<QMetaType> metaTypes, |
| 108 | const QHash<QMetaType, QString> &converters); |
| 109 | |
| 110 | virtual bool matches(const QHttpServerRequest &request, |
| 111 | QRegularExpressionMatch *match) const; |
| 112 | |
| 113 | QHttpServerRouterRule(QHttpServerRouterRulePrivate *d); |
| 114 | |
| 115 | // Implementation of C++20 std::bind_front() in C++17 |
| 116 | template<typename F, typename... Args> |
| 117 | static auto bind_front(F &&f, Args &&...args) |
| 118 | { |
| 119 | return [f = std::forward<F>(f), |
| 120 | args = std::make_tuple(std::forward<Args>(args)...)](auto &&...callArgs) { |
| 121 | return std::apply(f, |
| 122 | std::tuple_cat(args, |
| 123 | std::forward_as_tuple(std::forward<decltype(callArgs)>( |
| 124 | callArgs)...))); |
| 125 | }; |
| 126 | } |
| 127 | |
| 128 | template<typename ViewHandler, typename ViewTraits, int... Cx> |
| 129 | static typename ViewTraits::BindableType bindCapturedImpl( |
| 130 | const typename QtPrivate::ContextTypeForFunctor<ViewHandler>::ContextType *context, |
| 131 | ViewHandler &&handler, |
| 132 | const QRegularExpressionMatch &match, |
| 133 | QtPrivate::IndexesList<Cx...>) |
| 134 | { |
| 135 | if constexpr (std::is_member_function_pointer_v<ViewHandler>) { |
| 136 | return bind_front( |
| 137 | handler, const_cast<typename QtPrivate::ContextTypeForFunctor<ViewHandler>::ContextType*>(context), |
| 138 | QVariant(match.captured(nth: Cx + 1)) |
| 139 | .value<typename ViewTraits::Arguments::template Arg<Cx>::CleanType>()...); |
| 140 | } else { |
| 141 | Q_UNUSED(context); |
| 142 | return bind_front( |
| 143 | handler, |
| 144 | QVariant(match.captured(nth: Cx + 1)) |
| 145 | .value<typename ViewTraits::Arguments::template Arg<Cx>::CleanType>()...); |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | private: |
| 150 | std::unique_ptr<QHttpServerRouterRulePrivate> d_ptr; |
| 151 | |
| 152 | friend class QHttpServerRouter; |
| 153 | }; |
| 154 | |
| 155 | QT_END_NAMESPACE |
| 156 | |
| 157 | #endif // QHTTPSERVERROUTERRULE_H |
| 158 | |