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 | |
17 | QT_BEGIN_NAMESPACE |
18 | |
19 | Q_LOGGING_CATEGORY(lcHS, "qt.httpserver" ); |
20 | |
21 | void 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 | */ |
55 | QHttpServer::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 | */ |
150 | QHttpServer::~QHttpServer() |
151 | { |
152 | } |
153 | |
154 | /*! |
155 | Returns the router object. |
156 | */ |
157 | QHttpServerRouter *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 | */ |
178 | void QHttpServer::setMissingHandler(QHttpServer::MissingHandler handler) |
179 | { |
180 | Q_D(QHttpServer); |
181 | d->missingHandler = handler; |
182 | } |
183 | |
184 | /*! |
185 | \internal |
186 | */ |
187 | void QHttpServer::afterRequestImpl(AfterRequestHandler afterRequestHandler) |
188 | { |
189 | Q_D(QHttpServer); |
190 | d->afterRequestHandlers.push_back(x: std::move(afterRequestHandler)); |
191 | } |
192 | |
193 | /*! |
194 | \internal |
195 | */ |
196 | void 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) |
206 | void 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 | */ |
220 | bool 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 | */ |
229 | void QHttpServer::missingHandler(const QHttpServerRequest &request, |
230 | QHttpServerResponder &&responder) |
231 | { |
232 | Q_D(QHttpServer); |
233 | return d->callMissingHandler(request, responder: std::move(responder)); |
234 | } |
235 | |
236 | QT_END_NAMESPACE |
237 | |
238 | #include "moc_qhttpserver.cpp" |
239 | |