5 #include "response_p.h"
12 #include <QtCore/QJsonDocument>
14 #include <QCryptographicHash>
20 : d_ptr(new ResponsePrivate(defaultHeaders, engineRequest))
22 open(QIODevice::WriteOnly);
41 if (!(d->engineRequest->status & EngineRequest::FinalizedHeaders)) {
42 if (d->headers.header(QStringLiteral(
"TRANSFER_ENCODING")).compare(u
"chunked") == 0) {
43 d->engineRequest->status |= EngineRequest::IOWrite | EngineRequest::Chunked;
47 d->headers.setHeader(QStringLiteral(
"CONNECTION"), QStringLiteral(
"close"));
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 || d->engineRequest->status & EngineRequest::IOWrite;
87 if (d->bodyIODevice) {
88 delete d->bodyIODevice;
89 d->bodyIODevice =
nullptr;
98 return d->bodyIODevice;
106 if (!(d->engineRequest->status & EngineRequest::IOWrite)) {
107 d->bodyData = QByteArray();
108 if (d->bodyIODevice) {
109 delete d->bodyIODevice;
111 d->bodyIODevice =
body;
118 d->setBodyData(
body);
124 const QByteArray
body = documment.toJson(QJsonDocument::Compact);
125 d->setBodyData(
body);
126 d->headers.setContentType(QStringLiteral(
"application/json"));
132 d->setBodyData(json.toUtf8());
133 d->headers.setContentType(QStringLiteral(
"application/json"));
139 d->setBodyData(json);
140 d->headers.setContentType(QStringLiteral(
"application/json"));
146 const QByteArray
body = QJsonDocument(
object).toJson(QJsonDocument::Compact);
147 d->setBodyData(
body);
148 d->headers.setContentType(QStringLiteral(
"application/json"));
154 const QByteArray
body = QJsonDocument(array).toJson(QJsonDocument::Compact);
155 d->setBodyData(
body);
156 d->headers.setContentType(QStringLiteral(
"application/json"));
162 return d->headers.contentEncoding();
168 Q_ASSERT_X(!(d->engineRequest->status & EngineRequest::FinalizedHeaders),
169 "setContentEncoding",
170 "setting a header value after finalize_headers and the response callback has been called. Not what you want.");
172 d->headers.setContentEncoding(encoding);
178 return d->headers.contentLength();
184 Q_ASSERT_X(!(d->engineRequest->status & EngineRequest::FinalizedHeaders),
186 "setting a header value after finalize_headers and the response callback has been called. Not what you want.");
188 d->headers.setContentLength(length);
194 return d->headers.contentType();
200 return d->headers.contentTypeCharset();
206 return QVariant::fromValue(d->cookies.value(name));
209 #if (QT_VERSION < QT_VERSION_CHECK(6, 1, 0))
210 QVariant Response::cuteCookie(
const QByteArray &name)
const
213 return QVariant::fromValue(d->cuteCookies.value(name));
220 return d->cookies.values();
223 #if (QT_VERSION < QT_VERSION_CHECK(6, 1, 0))
224 QList<Cookie> Response::cuteCookies()
const
227 return d->cuteCookies.values();
237 #if (QT_VERSION < QT_VERSION_CHECK(6, 1, 0))
238 void Response::setCuteCookie(
const Cookie &cookie)
253 #if (QT_VERSION < QT_VERSION_CHECK(6, 1, 0))
254 void Response::setCuteCookies(
const QList<Cookie> &cookies)
266 return d->cookies.remove(name);
269 #if (QT_VERSION < QT_VERSION_CHECK(6, 1, 0))
270 int Response::removeCuteCookies(
const QByteArray &name)
273 return d->cuteCookies.remove(name);
284 const auto location = QString::fromLatin1(url.toEncoded(QUrl::FullyEncoded));
285 qCDebug(CUTELYST_RESPONSE) <<
"Redirecting to" <<
location <<
status;
287 d->headers.setHeader(QStringLiteral(
"LOCATION"),
location);
288 d->headers.setContentType(QStringLiteral(
"text/html; charset=utf-8"));
290 const QString buf = QLatin1String(R
"V0G0N(<!DOCTYPE html>
291 <html xmlns="http://www.w3.org/1999/xhtml">
296 <p>This item has moved <a href=")V0G0N") + location + QLatin1String(R"V0G0N(">here</a>.</p>
302 d->headers.removeHeader(QStringLiteral(
"LOCATION"));
303 qCDebug(CUTELYST_ENGINE) <<
"Invalid redirect removing header" << url <<
status;
315 if (url.matches(d->engineRequest->context->req()->uri(), QUrl::RemovePath | QUrl::RemoveQuery)) {
331 return d->headers.header(field);
337 Q_ASSERT_X(!(d->engineRequest->status & EngineRequest::FinalizedHeaders),
339 "setting a header value after finalize_headers and the response callback has been called. Not what you want.");
341 d->headers.setHeader(field, value);
353 return d->engineRequest->status & EngineRequest::FinalizedHeaders;
364 if (d->engineRequest->status & EngineRequest::IOWrite) {
366 }
else if (d->bodyIODevice) {
367 return d->bodyIODevice->size();
369 return d->bodyData.size();
376 return d->engineRequest->webSocketHandshake(key, origin, protocol);
382 return d->engineRequest->webSocketSendTextMessage(message);
388 return d->engineRequest->webSocketSendBinaryMessage(message);
394 return d->engineRequest->webSocketSendPing(payload);
400 return d->engineRequest->webSocketClose(code, reason);
403 void ResponsePrivate::setBodyData(
const QByteArray &body)
405 if (!(engineRequest->status & EngineRequest::IOWrite)) {
408 bodyIODevice =
nullptr;
411 headers.setContentLength(body.size());
415 #include "moc_response.cpp"
void redirect(const QUrl &url, quint16 status=Found)
QVariant cookie(const QByteArray &name) const
qint64 contentLength() const
bool hasBody() const noexcept
QString header(const QString &field) const
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...
Response(const Headers &defaultHeaders, EngineRequest *conn=nullptr)
Headers & headers() noexcept
void setBody(QIODevice *body)
QIODevice * bodyDevice() const
QString contentEncoding() const
void setJsonArrayBody(const QJsonArray &array)
void redirectSafe(const QUrl &url, const QUrl &fallback)
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
bool webSocketHandshake(const QString &key={}, const QString &origin={}, const QString &protocol={})
Sends the websocket handshake, if no parameters are defined it will use header data.
QString contentType() const
QString contentTypeCharset() const
void setContentLength(qint64 length)
int removeCookies(const QByteArray &name)
void setContentEncoding(const QString &encoding)
void setJsonObjectBody(const QJsonObject &object)
void setHeader(const QString &field, const QString &value)
virtual qint64 readData(char *data, qint64 maxlen) override
virtual qint64 size() const noexcept override
void setJsonBody(const QJsonDocument &documment)
Q_REQUIRED_RESULT QByteArray & body()
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
virtual bool isSequential() const noexcept override
The Cutelyst namespace holds all public Cutelyst API.