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
16QT_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*/
35QHttpServerResponsePrivate::QHttpServerResponsePrivate(
36 QByteArray &&d, const QHttpServerResponse::StatusCode sc)
37 : data(std::move(d)),
38 statusCode(sc)
39{ }
40
41/*!
42 \internal
43*/
44QHttpServerResponsePrivate::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*/
57QHttpServerResponse::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*/
65QHttpServerResponse& 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*/
77QHttpServerResponse::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*/
88QHttpServerResponse::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*/
96QHttpServerResponse::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*/
104QHttpServerResponse::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*/
113QHttpServerResponse::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*/
122QHttpServerResponse::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*/
131QHttpServerResponse::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*/
157QHttpServerResponse::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
167QHttpServerResponse::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
177QHttpServerResponse::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
187QHttpServerResponse::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*/
200QHttpServerResponse::~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*/
210QHttpServerResponse 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*/
224QByteArray QHttpServerResponse::data() const
225{
226 Q_D(const QHttpServerResponse);
227 return d->data;
228}
229
230/*!
231 Returns the status code.
232*/
233QHttpServerResponse::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*/
244QByteArray 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*/
259void QHttpServerResponse::addHeader(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*/
269void QHttpServerResponse::addHeader(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*/
279void QHttpServerResponse::addHeader(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*/
289void QHttpServerResponse::addHeader(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*/
299void QHttpServerResponse::addHeaders(QHttpServerResponder::HeaderList headers)
300{
301 for (auto &&header : 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*/
318void QHttpServerResponse::clearHeader(const QByteArray &name)
319{
320 Q_D(QHttpServerResponse);
321 d->headers.erase(x: name);
322}
323
324/*!
325 Removes all HTTP headers.
326*/
327void QHttpServerResponse::clearHeaders()
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*/
337void QHttpServerResponse::setHeader(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*/
347void QHttpServerResponse::setHeader(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*/
357void QHttpServerResponse::setHeader(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*/
367void QHttpServerResponse::setHeader(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*/
376void QHttpServerResponse::setHeaders(QHttpServerResponder::HeaderList headers)
377{
378 for (auto &&header : 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*/
386bool QHttpServerResponse::hasHeader(const QByteArray &header) 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*/
396bool QHttpServerResponse::hasHeader(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*/
412QList<QByteArray> QHttpServerResponse::headers(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
425QT_END_NAMESPACE
426

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