1 | // Copyright (C) 2020 Mikhail Svetkin <mikhail.svetkin@gmail.com> |
2 | // Copyright (C) 2019 The Qt Company Ltd. |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
4 | |
5 | #ifndef QHTTPSERVER_H |
6 | #define QHTTPSERVER_H |
7 | |
8 | #include <QtHttpServer/qabstracthttpserver.h> |
9 | #include <QtHttpServer/qhttpserverrouter.h> |
10 | #include <QtHttpServer/qhttpserverrouterrule.h> |
11 | #include <QtHttpServer/qhttpserverresponse.h> |
12 | #include <QtHttpServer/qhttpserverrouterviewtraits.h> |
13 | |
14 | #if QT_CONFIG(future) |
15 | # include <QtCore/qfuture.h> |
16 | #endif |
17 | |
18 | #include <functional> |
19 | #include <tuple> |
20 | |
21 | QT_BEGIN_NAMESPACE |
22 | |
23 | class QHttpServerRequest; |
24 | |
25 | class QHttpServerPrivate; |
26 | class Q_HTTPSERVER_EXPORT QHttpServer final : public QAbstractHttpServer |
27 | { |
28 | Q_OBJECT |
29 | Q_DECLARE_PRIVATE(QHttpServer) |
30 | |
31 | template <typename...> |
32 | static constexpr bool dependent_false_v = false; |
33 | |
34 | template<typename T> |
35 | using ResponseType = |
36 | #if QT_CONFIG(future) |
37 | std::conditional_t< |
38 | std::is_same_v<QFuture<QHttpServerResponse>, T>, |
39 | QFuture<QHttpServerResponse>, |
40 | QHttpServerResponse |
41 | >; |
42 | #else |
43 | QHttpServerResponse; |
44 | #endif |
45 | |
46 | using MissingHandlerPrototype = void (*)(const QHttpServerRequest &request, |
47 | QHttpServerResponder &responder); |
48 | template <typename T> |
49 | using if_missinghandler_prototype_compatible = typename std::enable_if< |
50 | QtPrivate::AreFunctionsCompatible<MissingHandlerPrototype, T>::value, bool>::type; |
51 | |
52 | using AfterRequestPrototype = void (*)(const QHttpServerRequest &request, |
53 | QHttpServerResponse &responder); |
54 | template <typename T> |
55 | using if_after_request_prototype_compatible = typename std::enable_if< |
56 | QtPrivate::AreFunctionsCompatible<AfterRequestPrototype, T>::value, bool>::type; |
57 | |
58 | public: |
59 | explicit QHttpServer(QObject *parent = nullptr); |
60 | ~QHttpServer() override; |
61 | |
62 | QHttpServerRouter *router(); |
63 | const QHttpServerRouter *router() const; |
64 | |
65 | #ifdef Q_QDOC |
66 | template <typename Rule = QHttpServerRouterRule, typename Functor> |
67 | Rule *route(const QString &pathPattern, QHttpServerRequest::Methods method, |
68 | const QObject *receiver, |
69 | Functor &&slot); |
70 | |
71 | template <typename Rule = QHttpServerRouterRule, typename Functor> |
72 | Rule *route(const QString &pathPattern, |
73 | const QObject *receiver, |
74 | Functor &&slot); |
75 | |
76 | template <typename Rule = QHttpServerRouterRule, typename Functor> |
77 | Rule *route(const QString &pathPattern, QHttpServerRequest::Methods method, |
78 | Functor &&handler); |
79 | |
80 | template <typename Rule = QHttpServerRouterRule, typename Functor> |
81 | Rule *route(const QString &pathPattern, |
82 | Functor &&handler); |
83 | #else |
84 | template<typename Rule = QHttpServerRouterRule, typename ViewHandler> |
85 | Rule *route(const QString &pathPattern, QHttpServerRequest::Methods method, |
86 | const typename QtPrivate::ContextTypeForFunctor<ViewHandler>::ContextType *context, |
87 | ViewHandler &&viewHandler) |
88 | { |
89 | using ViewTraits = QHttpServerRouterViewTraits<ViewHandler>; |
90 | static_assert(ViewTraits::Arguments::StaticAssert, |
91 | "ViewHandler arguments are in the wrong order or not supported" ); |
92 | return routeImpl<Rule, ViewHandler, ViewTraits>(pathPattern, method, context, |
93 | std::forward<ViewHandler>(viewHandler)); |
94 | } |
95 | |
96 | template<typename Rule = QHttpServerRouterRule, typename ViewHandler> |
97 | Rule *route(const QString &pathPattern, |
98 | const typename QtPrivate::ContextTypeForFunctor<ViewHandler>::ContextType *context, |
99 | ViewHandler &&viewHandler) |
100 | { |
101 | using ViewTraits = QHttpServerRouterViewTraits<ViewHandler>; |
102 | static_assert(ViewTraits::Arguments::StaticAssert, |
103 | "ViewHandler arguments are in the wrong order or not supported" ); |
104 | return routeImpl<Rule, ViewHandler, ViewTraits>(pathPattern, context, |
105 | std::forward<ViewHandler>(viewHandler)); |
106 | } |
107 | |
108 | template<typename Rule = QHttpServerRouterRule, typename ViewHandler> |
109 | Rule *route(const QString &pathPattern, |
110 | ViewHandler &&viewHandler) |
111 | { |
112 | return route<Rule>(pathPattern, QHttpServerRequest::Method::AnyKnown, |
113 | this, std::forward<ViewHandler>(viewHandler)); |
114 | } |
115 | |
116 | template<typename Rule = QHttpServerRouterRule, typename ViewHandler> |
117 | Rule *route(const QString &pathPattern, QHttpServerRequest::Methods method, |
118 | ViewHandler &&viewHandler) |
119 | { |
120 | return route<Rule>(pathPattern, method, |
121 | this, std::forward<ViewHandler>(viewHandler)); |
122 | } |
123 | #endif |
124 | |
125 | #ifdef Q_QDOC |
126 | template <typename Functor> |
127 | void setMissingHandler(const QObject *receiver, Functor &&slot); |
128 | #else |
129 | template <typename Handler, if_missinghandler_prototype_compatible<Handler> = true> |
130 | void setMissingHandler(const typename QtPrivate::ContextTypeForFunctor<Handler>::ContextType *context, |
131 | Handler &&handler) |
132 | { |
133 | setMissingHandlerImpl(context, |
134 | handler: QtPrivate::makeCallableObject<MissingHandlerPrototype>( |
135 | std::forward<Handler>(handler))); |
136 | } |
137 | #endif |
138 | |
139 | #ifdef Q_QDOC |
140 | template <typename Functor> |
141 | void addAfterRequestHandler(const QObject *receiver, Functor &&slot); |
142 | #else |
143 | template <typename Handler, if_after_request_prototype_compatible<Handler> = true> |
144 | void addAfterRequestHandler(const typename QtPrivate::ContextTypeForFunctor<Handler>::ContextType *context, |
145 | Handler &&handler) |
146 | { |
147 | addAfterRequestHandlerImpl(context, |
148 | handler: QtPrivate::makeCallableObject<AfterRequestPrototype>( |
149 | std::forward<Handler>(handler))); |
150 | } |
151 | #endif |
152 | |
153 | void clearMissingHandler(); |
154 | |
155 | private: |
156 | void setMissingHandlerImpl(const QObject *context, QtPrivate::QSlotObjectBase *handler); |
157 | |
158 | void addAfterRequestHandlerImpl(const QObject *context, QtPrivate::QSlotObjectBase *handler); |
159 | |
160 | template<typename ViewHandler, typename ViewTraits> |
161 | auto createRouteHandler(const typename QtPrivate::ContextTypeForFunctor<ViewHandler>::ContextType *context, |
162 | ViewHandler &&viewHandler) |
163 | { |
164 | return [this, context, viewHandler]( |
165 | const QRegularExpressionMatch &match, |
166 | const QHttpServerRequest &request, |
167 | QHttpServerResponder &responder) mutable { |
168 | auto boundViewHandler = QHttpServerRouterRule::bindCaptured<ViewHandler, ViewTraits>(context, |
169 | std::forward<ViewHandler>(viewHandler), match); |
170 | responseImpl<ViewTraits>(boundViewHandler, request, std::move(responder)); |
171 | }; |
172 | } |
173 | |
174 | template<typename Rule, typename ViewHandler, typename ViewTraits> |
175 | Rule *routeImpl(const QString &pathPattern, |
176 | const typename QtPrivate::ContextTypeForFunctor<ViewHandler>::ContextType *context, |
177 | ViewHandler &&viewHandler) |
178 | { |
179 | auto routerHandler = createRouteHandler<ViewHandler, ViewTraits>(context, |
180 | std::forward<ViewHandler>(viewHandler)); |
181 | auto rule = std::make_unique<Rule>(pathPattern, context, std::move(routerHandler)); |
182 | return reinterpret_cast<Rule*>(router()->addRule<ViewHandler, ViewTraits>(std::move(rule))); |
183 | } |
184 | |
185 | template<typename Rule, typename ViewHandler, typename ViewTraits> |
186 | Rule *routeImpl(const QString &pathPattern, QHttpServerRequest::Methods method, |
187 | const typename QtPrivate::ContextTypeForFunctor<ViewHandler>::ContextType *context, |
188 | ViewHandler &&viewHandler) |
189 | { |
190 | auto routerHandler = createRouteHandler<ViewHandler, ViewTraits>(context, |
191 | std::forward<ViewHandler>(viewHandler)); |
192 | auto rule = std::make_unique<Rule>(pathPattern, method, context, std::move(routerHandler)); |
193 | return reinterpret_cast<Rule*>(router()->addRule<ViewHandler, ViewTraits>(std::move(rule))); |
194 | } |
195 | |
196 | template<typename ViewTraits, typename T> |
197 | void responseImpl(T &boundViewHandler, const QHttpServerRequest &request, |
198 | QHttpServerResponder &&responder) |
199 | { |
200 | if constexpr (ViewTraits::Arguments::PlaceholdersCount == 0) { |
201 | ResponseType<typename ViewTraits::ReturnType> response(boundViewHandler()); |
202 | sendResponse(std::move(response), request, std::move(responder)); |
203 | } else if constexpr (ViewTraits::Arguments::PlaceholdersCount == 1) { |
204 | if constexpr (ViewTraits::Arguments::Last::IsRequest::Value) { |
205 | ResponseType<typename ViewTraits::ReturnType> response(boundViewHandler(request)); |
206 | sendResponse(std::move(response), request, std::move(responder)); |
207 | } else { |
208 | static_assert(std::is_same_v<typename ViewTraits::ReturnType, void>, |
209 | "Handlers with responder argument must have void return type." ); |
210 | boundViewHandler(responder); |
211 | } |
212 | } else if constexpr (ViewTraits::Arguments::PlaceholdersCount == 2) { |
213 | static_assert(std::is_same_v<typename ViewTraits::ReturnType, void>, |
214 | "Handlers with responder argument must have void return type." ); |
215 | if constexpr (ViewTraits::Arguments::Last::IsRequest::Value) { |
216 | boundViewHandler(responder, request); |
217 | } else { |
218 | boundViewHandler(request, responder); |
219 | } |
220 | } else { |
221 | static_assert(dependent_false_v<ViewTraits>); |
222 | } |
223 | } |
224 | |
225 | bool handleRequest(const QHttpServerRequest &request, |
226 | QHttpServerResponder &responder) override; |
227 | void missingHandler(const QHttpServerRequest &request, |
228 | QHttpServerResponder &responder) override; |
229 | |
230 | void sendResponse(QHttpServerResponse &&response, const QHttpServerRequest &request, |
231 | QHttpServerResponder &&responder); |
232 | |
233 | #if QT_CONFIG(future) |
234 | void sendResponse(QFuture<QHttpServerResponse> &&response, const QHttpServerRequest &request, |
235 | QHttpServerResponder &&responder); |
236 | #endif |
237 | }; |
238 | |
239 | QT_END_NAMESPACE |
240 | |
241 | #endif // QHTTPSERVER_H |
242 | |