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
21QT_BEGIN_NAMESPACE
22
23class QHttpServerRequest;
24
25class QHttpServerPrivate;
26class 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
58public:
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
155private:
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
239QT_END_NAMESPACE
240
241#endif // QHTTPSERVER_H
242

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qthttpserver/src/httpserver/qhttpserver.h