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

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