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 | |