1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtHttpServer/qhttpserver.h>
5
6#include <QtHttpServer/qhttpserverrequest.h>
7#include <QtHttpServer/qhttpserverresponder.h>
8#include <QtHttpServer/qhttpserverresponse.h>
9
10#include <private/qhttpserver_p.h>
11#include <private/qhttpserverstream_p.h>
12
13#include <QtCore/qloggingcategory.h>
14
15#include <QtNetwork/qtcpsocket.h>
16
17QT_BEGIN_NAMESPACE
18
19Q_LOGGING_CATEGORY(lcHS, "qt.httpserver");
20
21void QHttpServerPrivate::callMissingHandler(const QHttpServerRequest &request,
22 QHttpServerResponder &&responder)
23{
24 Q_Q(QHttpServer);
25
26 if (missingHandler) {
27 missingHandler(request, std::move(responder));
28 } else {
29 qCDebug(lcHS) << "missing handler:" << request.url().path();
30 q->sendResponse(response: QHttpServerResponder::StatusCode::NotFound, request, responder: std::move(responder));
31 }
32}
33
34/*!
35 \class QHttpServer
36 \since 6.4
37 \inmodule QtHttpServer
38 \brief QHttpServer is a simplified API for QAbstractHttpServer and QHttpServerRouter.
39
40 \code
41
42 QHttpServer server;
43
44 server.route("/", [] () {
45 return "hello world";
46 });
47 server.listen();
48
49 \endcode
50*/
51
52/*!
53 Creates an instance of QHttpServer with parent \a parent.
54*/
55QHttpServer::QHttpServer(QObject *parent)
56 : QAbstractHttpServer(*new QHttpServerPrivate, parent)
57{
58}
59
60/*! \fn template<typename Rule = QHttpServerRouterRule, typename ... Args> bool QHttpServer::route(Args && ... args)
61
62 This function is just a wrapper to simplify the router API.
63
64 This function takes variadic arguments \a args. The last argument is a
65 callback (\c{ViewHandler}). The remaining arguments are used to create a
66 new \c Rule (the default is QHttpServerRouterRule). This is in turn added
67 to the QHttpServerRouter. It returns \c true if a new rule is created,
68 otherwise it returns \c false.
69
70 \c ViewHandler can be a function pointer, non-mutable lambda, or any
71 other copiable callable with const call operator. The callable can take two
72 optional special arguments: \c {const QHttpServerRequest&} and
73 \c {QHttpServerResponder&&}. These special arguments must be the last in
74 the parameter list, but in any order, and there can be none, one, or both
75 of them present.
76
77 Examples:
78
79 \code
80
81 QHttpServer server;
82
83 // Valid:
84 server.route("test", [] (const int page) { return ""; });
85 server.route("test", [] (const int page, const QHttpServerRequest &request) { return ""; });
86 server.route("test", [] (QHttpServerResponder &&responder) { return ""; });
87
88 // Invalid (compile time error):
89 server.route("test", [] (const QHttpServerRequest &request, const int page) { return ""; }); // request must be last
90 server.route("test", [] (QHttpServerRequest &request) { return ""; }); // request must be passed by const reference
91 server.route("test", [] (QHttpServerResponder &responder) { return ""; }); // responder must be passed by universal reference
92
93 \endcode
94
95 The request handler may return \c {QFuture<QHttpServerResponse>} if
96 asynchronous processing is desired:
97
98 \code
99 server.route("/feature/", [] (int id) {
100 return QtConcurrent::run([] () {
101 return QHttpServerResponse("the future is coming");
102 });
103 });
104 \endcode
105
106
107 \sa QHttpServerRouter::addRule
108*/
109
110/*! \fn template<typename ViewHandler> void QHttpServer::afterRequest(ViewHandler &&viewHandler)
111 Register a function to be run after each request.
112
113 The \a viewHandler argument can be a function pointer, non-mutable lambda,
114 or any other copiable callable with const call operator. The callable
115 can take one or two optional arguments: \c {QHttpServerResponse &&} and
116 \c {const QHttpServerRequest &}. If both are given, they can be in either
117 order.
118
119 Examples:
120
121 \code
122
123 QHttpServer server;
124
125 // Valid:
126 server.afterRequest([] (QHttpServerResponse &&resp, const QHttpServerRequest &request) {
127 return std::move(resp);
128 }
129 server.afterRequest([] (const QHttpServerRequest &request, QHttpServerResponse &&resp) {
130 return std::move(resp);
131 }
132 server.afterRequest([] (QHttpServerResponse &&resp) { return std::move(resp); }
133
134 // Invalid (compile time error):
135 // resp must be passed by universal reference
136 server.afterRequest([] (QHttpServerResponse &resp, const QHttpServerRequest &request) {
137 return std::move(resp);
138 }
139 // request must be passed by const reference
140 server.afterRequest([] (QHttpServerResponse &&resp, QHttpServerRequest &request) {
141 return std::move(resp);
142 }
143
144 \endcode
145*/
146
147/*!
148 Destroys a QHttpServer.
149*/
150QHttpServer::~QHttpServer()
151{
152}
153
154/*!
155 Returns the router object.
156*/
157QHttpServerRouter *QHttpServer::router()
158{
159 Q_D(QHttpServer);
160 return &d->router;
161}
162
163/*!
164 \typealias QHttpServer::MissingHandler
165
166 Type alias for std::function<void(const QHttpServerRequest &request,
167 QHttpServerResponder &&responder)>.
168*/
169
170/*!
171 Set a handler to call for unhandled paths.
172
173 The invocable passed as \a handler will be invoked for each request
174 that cannot be handled by any of registered route handlers. Passing a
175 default-constructed std::function resets the handler to the default one
176 that produces replies with status 404 Not Found.
177*/
178void QHttpServer::setMissingHandler(QHttpServer::MissingHandler handler)
179{
180 Q_D(QHttpServer);
181 d->missingHandler = handler;
182}
183
184/*!
185 \internal
186*/
187void QHttpServer::afterRequestImpl(AfterRequestHandler afterRequestHandler)
188{
189 Q_D(QHttpServer);
190 d->afterRequestHandlers.push_back(x: std::move(afterRequestHandler));
191}
192
193/*!
194 \internal
195*/
196void QHttpServer::sendResponse(QHttpServerResponse &&response, const QHttpServerRequest &request,
197 QHttpServerResponder &&responder)
198{
199 Q_D(QHttpServer);
200 for (auto afterRequestHandler : d->afterRequestHandlers)
201 response = afterRequestHandler(std::move(response), request);
202 responder.sendResponse(response);
203}
204
205#if QT_CONFIG(future)
206void QHttpServer::sendResponse(QFuture<QHttpServerResponse> &&response,
207 const QHttpServerRequest &request, QHttpServerResponder &&responder)
208{
209 response.then(context: this,
210 function: [this, &request,
211 responder = std::move(responder)](QHttpServerResponse &&response) mutable {
212 sendResponse(response: std::move(response), request, responder: std::move(responder));
213 });
214}
215#endif // QT_CONFIG(future)
216
217/*!
218 \internal
219*/
220bool QHttpServer::handleRequest(const QHttpServerRequest &request, QHttpServerResponder &responder)
221{
222 Q_D(QHttpServer);
223 return d->router.handleRequest(request, responder);
224}
225
226/*!
227 \internal
228*/
229void QHttpServer::missingHandler(const QHttpServerRequest &request,
230 QHttpServerResponder &&responder)
231{
232 Q_D(QHttpServer);
233 return d->callMissingHandler(request, responder: std::move(responder));
234}
235
236QT_END_NAMESPACE
237
238#include "moc_qhttpserver.cpp"
239

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