11#include <QCryptographicHash>
15#include <QtCore/QJsonDocument>
20 : d_ptr(new ResponsePrivate(defaultHeaders, engineRequest))
22 open(QIODevice::WriteOnly);
41 if (!(d->engineRequest->status & EngineRequest::FinalizedHeaders)) {
42 if (d->headers.header(
"Transfer-Encoding"_qba).compare(
"chunked") == 0) {
43 d->engineRequest->status |= EngineRequest::IOWrite | EngineRequest::Chunked;
47 d->headers.setHeader(
"Connection"_qba,
"Close"_qba);
48 d->engineRequest->status |= EngineRequest::IOWrite;
50 delete d->bodyIODevice;
51 d->bodyIODevice =
nullptr;
52 d->bodyData = QByteArray();
54 d->engineRequest->finalizeHeaders();
57 return d->engineRequest->write(data, len);
62 delete d_ptr->bodyIODevice;
81 return !d->bodyData.isEmpty() || d->bodyIODevice ||
82 d->engineRequest->status & EngineRequest::IOWrite;
88 if (d->bodyIODevice) {
89 delete d->bodyIODevice;
90 d->bodyIODevice =
nullptr;
99 return d->bodyIODevice;
107 if (!(d->engineRequest->status & EngineRequest::IOWrite)) {
108 d->bodyData = QByteArray();
109 if (d->bodyIODevice) {
110 delete d->bodyIODevice;
112 d->bodyIODevice =
body;
119 d->setBodyData(
body);
125 d->setBodyData(json);
126 d->headers.setContentType(
"application/json"_qba);
131 setJsonBody(QJsonDocument(obj).toJson(QJsonDocument::Compact));
136 setJsonBody(QJsonDocument(array).toJson(QJsonDocument::Compact));
142 return d->headers.contentEncoding();
148 Q_ASSERT_X(!(d->engineRequest->status & EngineRequest::FinalizedHeaders),
149 "setContentEncoding",
150 "setting a header value after finalize_headers and the response callback has been "
151 "called. Not what you want.");
153 d->headers.setContentEncoding(encoding);
159 return d->headers.contentLength();
165 Q_ASSERT_X(!(d->engineRequest->status & EngineRequest::FinalizedHeaders),
167 "setting a header value after finalize_headers and the response callback has been "
168 "called. Not what you want.");
170 d->headers.setContentLength(length);
176 return d->headers.contentType();
182 return d->headers.contentTypeCharset();
188 return QVariant::fromValue(d->cookies.value(name));
194 return d->cookies.values();
214 return d->cookies.remove(name);
224 const auto location = url.toEncoded(QUrl::FullyEncoded);
225 qCDebug(CUTELYST_RESPONSE) <<
"Redirecting to" <<
location <<
status;
227 d->headers.setHeader(
"Location"_qba,
location);
228 d->headers.setContentType(
"text/html; charset=utf-8"_qba);
230 const QByteArray buf = R
"V0G0N(<!DOCTYPE html>
231<html xmlns="http://www.w3.org/1999/xhtml">
236 <p>This item has moved <a href=")V0G0N" +
243 d->headers.removeHeader(
"Location"_qba);
244 qCDebug(CUTELYST_ENGINE) <<
"Invalid redirect removing header" << url <<
status;
256 if (url.matches(d->engineRequest->context->req()->uri(),
257 QUrl::RemovePath | QUrl::RemoveQuery)) {
273 return d->headers.header(field);
279 Q_ASSERT_X(!(d->engineRequest->status & EngineRequest::FinalizedHeaders),
281 "setting a header value after finalize_headers and the response callback has been "
282 "called. Not what you want.");
284 d->headers.setHeader(key, value);
296 return d->engineRequest->status & EngineRequest::FinalizedHeaders;
307 if (d->engineRequest->status & EngineRequest::IOWrite) {
309 }
else if (d->bodyIODevice) {
310 return d->bodyIODevice->size();
312 return d->bodyData.size();
317 const QByteArray &origin,
318 const QByteArray &protocol)
321 return d->engineRequest->webSocketHandshake(key, origin, protocol);
327 return d->engineRequest->webSocketSendTextMessage(message);
333 return d->engineRequest->webSocketSendBinaryMessage(message);
339 return d->engineRequest->webSocketSendPing(payload);
345 return d->engineRequest->webSocketClose(code, reason);
348void ResponsePrivate::setBodyData(
const QByteArray &body)
350 if (!(engineRequest->status & EngineRequest::IOWrite)) {
353 bodyIODevice =
nullptr;
356 headers.setContentLength(body.size());
360#include "moc_response.cpp"
qint64 size() const noexcept override
QByteArray header(const QByteArray &field) const noexcept
void redirect(const QUrl &url, quint16 status=Found)
QVariant cookie(const QByteArray &name) const
qint64 contentLength() const
bool webSocketHandshake(const QByteArray &key={}, const QByteArray &origin={}, const QByteArray &protocol={})
Sends the websocket handshake, if no parameters are defined it will use header data.
bool hasBody() const noexcept
bool webSocketTextMessage(const QString &message)
Sends a WebSocket text message.
void setStatus(quint16 status) noexcept
bool webSocketPing(const QByteArray &payload={})
Sends a WebSocket ping with an optional payload limited to 125 bytes, which will be truncated if larg...
void setHeader(const QByteArray &key, const QByteArray &value)
Response(const Headers &defaultHeaders, EngineRequest *conn=nullptr)
QByteArray contentEncoding() const noexcept
QByteArray contentTypeCharset() const
void setBody(QIODevice *body)
void setJsonArrayBody(const QJsonArray &array)
void redirectSafe(const QUrl &url, const QUrl &fallback)
Headers & headers() noexcept
bool isSequential() const noexcept override
void setCookies(const QList< QNetworkCookie > &cookies)
virtual qint64 writeData(const char *data, qint64 len) override
QList< QNetworkCookie > cookies() const
bool webSocketBinaryMessage(const QByteArray &message)
Sends a WebSocket binary message.
bool isFinalizedHeaders() const noexcept
void setContentLength(qint64 length)
int removeCookies(const QByteArray &name)
void setJsonObjectBody(const QJsonObject &obj)
virtual qint64 readData(char *data, qint64 maxlen) override
QIODevice * bodyDevice() const noexcept
void setJsonBody(QStringView json)
bool webSocketClose(quint16 code=Response::CloseCodeNormal, const QString &reason={})
Sends a WebSocket close frame, with both optional close code and a string reason.
quint16 status() const noexcept
void setCookie(const QNetworkCookie &cookie)
QUrl location() const noexcept
void setContentEncoding(const QByteArray &encoding)
QByteArray contentType() const
The Cutelyst namespace holds all public Cutelyst API.