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#include <QtHttpServer/qhttpserverviewtraits.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<int I, typename ... Ts>
33 struct VariadicTypeAt { using Type = typename std::tuple_element<I, std::tuple<Ts...>>::type; };
34
35 template<typename ... Ts>
36 struct VariadicTypeLast {
37 using Type = typename VariadicTypeAt<sizeof ... (Ts) - 1, Ts...>::Type;
38 };
39
40 template <typename...>
41 static constexpr bool dependent_false_v = false;
42
43 template<typename T>
44 using ResponseType =
45#if QT_CONFIG(future)
46 std::conditional_t<
47 std::is_same_v<QFuture<QHttpServerResponse>, T>,
48 QFuture<QHttpServerResponse>,
49 QHttpServerResponse
50 >;
51#else
52 QHttpServerResponse;
53#endif
54
55public:
56 explicit QHttpServer(QObject *parent = nullptr);
57 ~QHttpServer();
58
59 QHttpServerRouter *router();
60
61 template<typename Rule = QHttpServerRouterRule, typename ... Args>
62 bool route(Args && ... args)
63 {
64 using ViewHandler = typename VariadicTypeLast<Args...>::Type;
65 using ViewTraits = QHttpServerRouterViewTraits<ViewHandler>;
66 static_assert(ViewTraits::Arguments::StaticAssert,
67 "ViewHandler arguments are in the wrong order or not supported");
68 return routeHelper<Rule, ViewHandler, ViewTraits>(
69 QtPrivate::makeIndexSequence<sizeof ... (Args) - 1>{},
70 std::forward<Args>(args)...);
71 }
72
73 template<typename ViewHandler>
74 void afterRequest(ViewHandler &&viewHandler)
75 {
76 using ViewTraits = QHttpServerAfterRequestViewTraits<ViewHandler>;
77 static_assert(ViewTraits::Arguments::StaticAssert,
78 "ViewHandler arguments are in the wrong order or not supported");
79 afterRequestHelper<ViewTraits, ViewHandler>(std::move(viewHandler));
80 }
81
82 using MissingHandler = std::function<void(const QHttpServerRequest &request,
83 QHttpServerResponder &&responder)>;
84
85 void setMissingHandler(MissingHandler handler);
86
87private:
88 using AfterRequestHandler =
89 std::function<QHttpServerResponse(QHttpServerResponse &&response,
90 const QHttpServerRequest &request)>;
91
92 template<typename ViewTraits, typename ViewHandler>
93 void afterRequestHelper(ViewHandler &&viewHandler) {
94 auto handler = [viewHandler](QHttpServerResponse &&resp,
95 const QHttpServerRequest &request) {
96 if constexpr (ViewTraits::Arguments::Last::IsRequest::Value) {
97 if constexpr (ViewTraits::Arguments::Count == 2)
98 return std::move(viewHandler(std::move(resp), request));
99 else
100 static_assert(dependent_false_v<ViewTraits>);
101 } else if constexpr (ViewTraits::Arguments::Last::IsResponse::Value) {
102 if constexpr (ViewTraits::Arguments::Count == 1)
103 return std::move(viewHandler(std::move(resp)));
104 else if constexpr (ViewTraits::Arguments::Count == 2)
105 return std::move(viewHandler(request, std::move(resp)));
106 else
107 static_assert(dependent_false_v<ViewTraits>);
108 } else {
109 static_assert(dependent_false_v<ViewTraits>);
110 }
111 };
112
113 afterRequestImpl(afterRequestHandler: std::move(handler));
114 }
115
116 void afterRequestImpl(AfterRequestHandler afterRequestHandler);
117
118 template<typename Rule, typename ViewHandler, typename ViewTraits, int ... I, typename ... Args>
119 bool routeHelper(QtPrivate::IndexesList<I...>, Args &&... args)
120 {
121 return routeImpl<Rule,
122 ViewHandler,
123 ViewTraits,
124 typename VariadicTypeAt<I, Args...>::Type...>(std::forward<Args>(args)...);
125 }
126
127 template<typename Rule, typename ViewHandler, typename ViewTraits, typename ... Args>
128 bool routeImpl(Args &&...args, ViewHandler &&viewHandler)
129 {
130 auto routerHandler = [this, viewHandler = std::forward<ViewHandler>(viewHandler)](
131 const QRegularExpressionMatch &match,
132 const QHttpServerRequest &request,
133 QHttpServerResponder &&responder) {
134 auto boundViewHandler = router()->bindCaptured(viewHandler, match);
135 responseImpl<ViewTraits>(boundViewHandler, request, std::move(responder));
136 };
137
138 auto rule = std::make_unique<Rule>(std::forward<Args>(args)..., std::move(routerHandler));
139
140 return router()->addRule<ViewHandler, ViewTraits>(std::move(rule));
141 }
142
143 template<typename ViewTraits, typename T>
144 void responseImpl(T &boundViewHandler, const QHttpServerRequest &request,
145 QHttpServerResponder &&responder)
146 {
147 if constexpr (ViewTraits::Arguments::PlaceholdersCount == 0) {
148 ResponseType<typename ViewTraits::ReturnType> response(boundViewHandler());
149 sendResponse(std::move(response), request, std::move(responder));
150 } else if constexpr (ViewTraits::Arguments::PlaceholdersCount == 1) {
151 if constexpr (ViewTraits::Arguments::Last::IsRequest::Value) {
152 ResponseType<typename ViewTraits::ReturnType> response(boundViewHandler(request));
153 sendResponse(std::move(response), request, std::move(responder));
154 } else {
155 static_assert(std::is_same_v<typename ViewTraits::ReturnType, void>,
156 "Handlers with responder argument must have void return type.");
157 boundViewHandler(std::move(responder));
158 }
159 } else if constexpr (ViewTraits::Arguments::PlaceholdersCount == 2) {
160 static_assert(std::is_same_v<typename ViewTraits::ReturnType, void>,
161 "Handlers with responder argument must have void return type.");
162 if constexpr (ViewTraits::Arguments::Last::IsRequest::Value) {
163 boundViewHandler(std::move(responder), request);
164 } else {
165 boundViewHandler(request, std::move(responder));
166 }
167 } else {
168 static_assert(dependent_false_v<ViewTraits>);
169 }
170 }
171
172 bool handleRequest(const QHttpServerRequest &request,
173 QHttpServerResponder &responder) override final;
174 void missingHandler(const QHttpServerRequest &request,
175 QHttpServerResponder &&responder) override final;
176
177 void sendResponse(QHttpServerResponse &&response, const QHttpServerRequest &request,
178 QHttpServerResponder &&responder);
179
180#if QT_CONFIG(future)
181 void sendResponse(QFuture<QHttpServerResponse> &&response, const QHttpServerRequest &request,
182 QHttpServerResponder &&responder);
183#endif
184};
185
186QT_END_NAMESPACE
187
188#endif // QHTTPSERVER_H
189

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