1 | // Copyright (C) 2019 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include <QtHttpServer/qhttpserverresponse.h> |
5 | |
6 | #include <private/qhttpserverliterals_p.h> |
7 | #include <private/qhttpserverresponse_p.h> |
8 | #include <private/qhttpserverresponder_p.h> |
9 | |
10 | #include <QtCore/qfile.h> |
11 | #include <QtCore/qjsondocument.h> |
12 | #include <QtCore/qjsonobject.h> |
13 | #include <QtCore/qmimedatabase.h> |
14 | #include <QtNetwork/qtcpsocket.h> |
15 | |
16 | QT_BEGIN_NAMESPACE |
17 | |
18 | /*! |
19 | \class QHttpServerResponse |
20 | \since 6.4 |
21 | \inmodule QtHttpServer |
22 | \brief Encapsulates an HTTP response. |
23 | |
24 | API for creating, reading and modifying a response from an HTTP server, |
25 | and for writing its contents to a QHttpServerResponder. |
26 | It has numerous constructors, and \c static function \c fromFile for |
27 | constructing it from the contents of a file. There are functions for |
28 | setting, getting, and removing headers, and for getting the data, status |
29 | code and mime type. |
30 | */ |
31 | |
32 | /*! |
33 | \internal |
34 | */ |
35 | QHttpServerResponsePrivate::QHttpServerResponsePrivate( |
36 | QByteArray &&d, const QHttpServerResponse::StatusCode sc) |
37 | : data(std::move(d)), |
38 | statusCode(sc) |
39 | { } |
40 | |
41 | /*! |
42 | \internal |
43 | */ |
44 | QHttpServerResponsePrivate::QHttpServerResponsePrivate(const QHttpServerResponse::StatusCode sc) |
45 | : statusCode(sc) |
46 | { } |
47 | |
48 | /*! |
49 | \typealias QHttpServerResponse::StatusCode |
50 | |
51 | Type alias for QHttpServerResponder::StatusCode |
52 | */ |
53 | |
54 | /*! |
55 | Move-constructs an instance of a QHttpServerResponse object from \a other. |
56 | */ |
57 | QHttpServerResponse::QHttpServerResponse(QHttpServerResponse &&other) noexcept |
58 | : d_ptr(std::move(other.d_ptr)) |
59 | { |
60 | } |
61 | |
62 | /*! |
63 | Move-assigns the values of \a other to this object. |
64 | */ |
65 | QHttpServerResponse& QHttpServerResponse::operator=(QHttpServerResponse &&other) noexcept |
66 | { |
67 | if (this == &other) |
68 | return *this; |
69 | |
70 | qSwap(value1&: d_ptr, value2&: other.d_ptr); |
71 | return *this; |
72 | } |
73 | |
74 | /*! |
75 | Creates a QHttpServerResponse object with the status code \a statusCode. |
76 | */ |
77 | QHttpServerResponse::QHttpServerResponse( |
78 | const QHttpServerResponse::StatusCode statusCode) |
79 | : QHttpServerResponse(QHttpServerLiterals::contentTypeXEmpty(), |
80 | QByteArray(), |
81 | statusCode) |
82 | { |
83 | } |
84 | |
85 | /*! |
86 | Creates a QHttpServerResponse object from \a data with the status code \a status. |
87 | */ |
88 | QHttpServerResponse::QHttpServerResponse(const char *data, const StatusCode status) |
89 | : QHttpServerResponse(QByteArray::fromRawData(data, size: qstrlen(str: data)), status) |
90 | { |
91 | } |
92 | |
93 | /*! |
94 | Creates a QHttpServerResponse object from \a data with the status code \a status. |
95 | */ |
96 | QHttpServerResponse::QHttpServerResponse(const QString &data, const StatusCode status) |
97 | : QHttpServerResponse(data.toUtf8(), status) |
98 | { |
99 | } |
100 | |
101 | /*! |
102 | Creates a QHttpServerResponse object from \a data with the status code \a status. |
103 | */ |
104 | QHttpServerResponse::QHttpServerResponse(const QByteArray &data, const StatusCode status) |
105 | : QHttpServerResponse(QMimeDatabase().mimeTypeForData(data).name().toLocal8Bit(), data, status) |
106 | { |
107 | } |
108 | |
109 | /*! |
110 | Move-constructs a QHttpServerResponse whose body will contain the given |
111 | \a data with the status code \a status. |
112 | */ |
113 | QHttpServerResponse::QHttpServerResponse(QByteArray &&data, const StatusCode status) |
114 | : QHttpServerResponse(QMimeDatabase().mimeTypeForData(data).name().toLocal8Bit(), |
115 | std::move(data), status) |
116 | { |
117 | } |
118 | |
119 | /*! |
120 | Creates a QHttpServerResponse object from \a data with the status code \a status. |
121 | */ |
122 | QHttpServerResponse::QHttpServerResponse(const QJsonObject &data, const StatusCode status) |
123 | : QHttpServerResponse(QHttpServerLiterals::contentTypeJson(), |
124 | QJsonDocument(data).toJson(format: QJsonDocument::Compact), status) |
125 | { |
126 | } |
127 | |
128 | /*! |
129 | Creates a QHttpServerResponse object from \a data with the status code \a status. |
130 | */ |
131 | QHttpServerResponse::QHttpServerResponse(const QJsonArray &data, const StatusCode status) |
132 | : QHttpServerResponse(QHttpServerLiterals::contentTypeJson(), |
133 | QJsonDocument(data).toJson(format: QJsonDocument::Compact), status) |
134 | { |
135 | } |
136 | |
137 | /*! |
138 | \fn QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType, |
139 | const QByteArray &data, |
140 | const StatusCode status) |
141 | \fn QHttpServerResponse::QHttpServerResponse(QByteArray &&mimeType, |
142 | const QByteArray &data, |
143 | const StatusCode status) |
144 | \fn QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType, |
145 | QByteArray &&data, |
146 | const StatusCode status) |
147 | \fn QHttpServerResponse::QHttpServerResponse(QByteArray &&mimeType, |
148 | QByteArray &&data, |
149 | const StatusCode status) |
150 | |
151 | Creates a QHttpServer response. |
152 | |
153 | The response will use the given \a status code and deliver the \a data as |
154 | its body, with a \c ContentType header describing it as being of MIME type |
155 | \a mimeType. |
156 | */ |
157 | QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType, |
158 | const QByteArray &data, |
159 | const StatusCode status) |
160 | : d_ptr(new QHttpServerResponsePrivate(QByteArray(data), status)) |
161 | { |
162 | if (!mimeType.isEmpty()) { |
163 | setHeader(name: QHttpServerLiterals::contentTypeHeader(), value: mimeType); |
164 | } |
165 | } |
166 | |
167 | QHttpServerResponse::QHttpServerResponse(QByteArray &&mimeType, |
168 | const QByteArray &data, |
169 | const StatusCode status) |
170 | : d_ptr(new QHttpServerResponsePrivate(QByteArray(data), status)) |
171 | { |
172 | if (!mimeType.isEmpty()) { |
173 | setHeader(name: QHttpServerLiterals::contentTypeHeader(), value: std::move(mimeType)); |
174 | } |
175 | } |
176 | |
177 | QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType, |
178 | QByteArray &&data, |
179 | const StatusCode status) |
180 | : d_ptr(new QHttpServerResponsePrivate(std::move(data), status)) |
181 | { |
182 | if (!mimeType.isEmpty()) { |
183 | setHeader(name: QHttpServerLiterals::contentTypeHeader(), value: mimeType); |
184 | } |
185 | } |
186 | |
187 | QHttpServerResponse::QHttpServerResponse(QByteArray &&mimeType, |
188 | QByteArray &&data, |
189 | const StatusCode status) |
190 | : d_ptr(new QHttpServerResponsePrivate(std::move(data), status)) |
191 | { |
192 | if (!mimeType.isEmpty()) { |
193 | setHeader(name: QHttpServerLiterals::contentTypeHeader(), value: std::move(mimeType)); |
194 | } |
195 | } |
196 | |
197 | /*! |
198 | Destroys a QHttpServerResponse object. |
199 | */ |
200 | QHttpServerResponse::~QHttpServerResponse() |
201 | { |
202 | } |
203 | |
204 | /*! |
205 | Returns a QHttpServerResponse from the content of the file \a fileName. |
206 | |
207 | It is the caller's responsibility to sanity-check the filename, and to have |
208 | a well-defined policy for which files the server will request. |
209 | */ |
210 | QHttpServerResponse QHttpServerResponse::fromFile(const QString &fileName) |
211 | { |
212 | QFile file(fileName); |
213 | if (!file.open(flags: QFile::ReadOnly)) |
214 | return QHttpServerResponse(StatusCode::NotFound); |
215 | const QByteArray data = file.readAll(); |
216 | file.close(); |
217 | const QByteArray mimeType = QMimeDatabase().mimeTypeForFileNameAndData(fileName, data).name().toLocal8Bit(); |
218 | return QHttpServerResponse(mimeType, data); |
219 | } |
220 | |
221 | /*! |
222 | Returns the response body. |
223 | */ |
224 | QByteArray QHttpServerResponse::data() const |
225 | { |
226 | Q_D(const QHttpServerResponse); |
227 | return d->data; |
228 | } |
229 | |
230 | /*! |
231 | Returns the status code. |
232 | */ |
233 | QHttpServerResponse::StatusCode QHttpServerResponse::statusCode() const |
234 | { |
235 | Q_D(const QHttpServerResponse); |
236 | return d->statusCode; |
237 | } |
238 | |
239 | /*! |
240 | Returns the value of the HTTP "Content-Type" header. |
241 | |
242 | \note Default value is "text/html" |
243 | */ |
244 | QByteArray QHttpServerResponse::mimeType() const |
245 | { |
246 | Q_D(const QHttpServerResponse); |
247 | const auto res = d->headers.find( |
248 | x: QHttpServerLiterals::contentTypeHeader()); |
249 | if (res == d->headers.end()) |
250 | return QHttpServerLiterals::contentTypeTextHtml(); |
251 | |
252 | return res->second; |
253 | } |
254 | |
255 | /*! |
256 | Adds the HTTP header with name \a name and value \a value, |
257 | does not override any previously set headers. |
258 | */ |
259 | void QHttpServerResponse::(QByteArray &&name, QByteArray &&value) |
260 | { |
261 | Q_D(QHttpServerResponse); |
262 | d->headers.emplace(args: std::move(name), args: std::move(value)); |
263 | } |
264 | |
265 | /*! |
266 | Adds the HTTP header with name \a name and value \a value, |
267 | does not override any previously set headers. |
268 | */ |
269 | void QHttpServerResponse::(QByteArray &&name, const QByteArray &value) |
270 | { |
271 | Q_D(QHttpServerResponse); |
272 | d->headers.emplace(args: std::move(name), args: value); |
273 | } |
274 | |
275 | /*! |
276 | Adds the HTTP header with name \a name and value \a value, |
277 | does not override any previously set headers. |
278 | */ |
279 | void QHttpServerResponse::(const QByteArray &name, QByteArray &&value) |
280 | { |
281 | Q_D(QHttpServerResponse); |
282 | d->headers.emplace(args: name, args: std::move(value)); |
283 | } |
284 | |
285 | /*! |
286 | Adds the HTTP header with name \a name and value \a value, |
287 | does not override any previously set headers. |
288 | */ |
289 | void QHttpServerResponse::(const QByteArray &name, const QByteArray &value) |
290 | { |
291 | Q_D(QHttpServerResponse); |
292 | d->headers.emplace(args: name, args: value); |
293 | } |
294 | |
295 | /*! |
296 | Adds the HTTP headers in \a headers, |
297 | does not override any previously set headers. |
298 | */ |
299 | void QHttpServerResponse::(QHttpServerResponder::HeaderList ) |
300 | { |
301 | for (auto && : headers) |
302 | addHeader(name: header.first, value: header.second); |
303 | } |
304 | |
305 | /*! |
306 | \fn template<typename Container> void QHttpServerResponse::addHeaders(const Container |
307 | &headerList) |
308 | |
309 | Adds the HTTP headers in \a headerList, does not override any previously set headers. |
310 | |
311 | \c Container must be a container that represents the header name and content as |
312 | key-value pairs. |
313 | */ |
314 | |
315 | /*! |
316 | Removes the HTTP header with name \a name. |
317 | */ |
318 | void QHttpServerResponse::(const QByteArray &name) |
319 | { |
320 | Q_D(QHttpServerResponse); |
321 | d->headers.erase(x: name); |
322 | } |
323 | |
324 | /*! |
325 | Removes all HTTP headers. |
326 | */ |
327 | void QHttpServerResponse::() |
328 | { |
329 | Q_D(QHttpServerResponse); |
330 | d->headers.clear(); |
331 | } |
332 | |
333 | /*! |
334 | Sets the HTTP header with name \a name and value \a value, |
335 | overriding any previously set headers. |
336 | */ |
337 | void QHttpServerResponse::(QByteArray &&name, QByteArray &&value) |
338 | { |
339 | clearHeader(name); |
340 | addHeader(name: std::move(name), value: std::move(value)); |
341 | } |
342 | |
343 | /*! |
344 | Sets the HTTP header with name \a name and value \a value, |
345 | overriding any previously set headers. |
346 | */ |
347 | void QHttpServerResponse::(QByteArray &&name, const QByteArray &value) |
348 | { |
349 | clearHeader(name); |
350 | addHeader(name: std::move(name), value); |
351 | } |
352 | |
353 | /*! |
354 | Sets the HTTP header with name \a name and value \a value, |
355 | overriding any previously set headers. |
356 | */ |
357 | void QHttpServerResponse::(const QByteArray &name, QByteArray &&value) |
358 | { |
359 | clearHeader(name); |
360 | addHeader(name, value: std::move(value)); |
361 | } |
362 | |
363 | /*! |
364 | Sets the HTTP header with name \a name and value \a value, |
365 | overriding any previously set headers. |
366 | */ |
367 | void QHttpServerResponse::(const QByteArray &name, const QByteArray &value) |
368 | { |
369 | clearHeader(name); |
370 | addHeader(name, value); |
371 | } |
372 | |
373 | /*! |
374 | Sets the headers \a headers, overriding any previously set headers. |
375 | */ |
376 | void QHttpServerResponse::(QHttpServerResponder::HeaderList ) |
377 | { |
378 | for (auto && : headers) |
379 | setHeader(name: header.first, value: header.second); |
380 | } |
381 | |
382 | /*! |
383 | Returns true if the response contains an HTTP header with name \a header, |
384 | otherwise returns false. |
385 | */ |
386 | bool QHttpServerResponse::(const QByteArray &) const |
387 | { |
388 | Q_D(const QHttpServerResponse); |
389 | return d->headers.find(x: header) != d->headers.end(); |
390 | } |
391 | |
392 | /*! |
393 | Returns true if the response contains an HTTP header with name \a name and |
394 | with value \a value, otherwise returns false. |
395 | */ |
396 | bool QHttpServerResponse::(const QByteArray &name, |
397 | const QByteArray &value) const |
398 | { |
399 | Q_D(const QHttpServerResponse); |
400 | auto range = d->headers.equal_range(x: name); |
401 | |
402 | auto condition = [&value] (const std::pair<QByteArray, QByteArray> &pair) { |
403 | return pair.second == value; |
404 | }; |
405 | |
406 | return std::find_if(first: range.first, last: range.second, pred: condition) != range.second; |
407 | } |
408 | |
409 | /*! |
410 | Returns values of the HTTP header with name \a name. |
411 | */ |
412 | QList<QByteArray> QHttpServerResponse::(const QByteArray &name) const |
413 | { |
414 | Q_D(const QHttpServerResponse); |
415 | |
416 | QList<QByteArray> results; |
417 | auto range = d->headers.equal_range(x: name); |
418 | |
419 | for (auto it = range.first; it != range.second; ++it) |
420 | results.append(t: it->second); |
421 | |
422 | return results; |
423 | } |
424 | |
425 | QT_END_NAMESPACE |
426 | |