9#include <Cutelyst/Context>
10#include <Cutelyst/response_p.h>
12#include <QLoggingCategory>
13Q_LOGGING_CATEGORY(CUTELYST_ENGINEREQUEST,
"cutelyst.engine_request", QtWarningMsg)
16using namespace Qt::Literals::StringLiterals;
18EngineRequest::EngineRequest()
22EngineRequest::~EngineRequest()
29 if (!(
status & EngineRequest::Chunked)) {
31 QIODevice *bodyDevice = response->
bodyDevice();
34 if (!bodyDevice->isSequential()) {
38 char block[64 * 1024];
39 while (!bodyDevice->atEnd()) {
40 qint64 in = bodyDevice->read(block,
sizeof(block));
45 if (
write(block, in) != in) {
46 qCWarning(CUTELYST_ENGINEREQUEST) <<
"Failed to write body";
51 const QByteArray bodyByteArray = response->
body();
52 write(bodyByteArray.constData(), bodyByteArray.size());
54 }
else if (!(
status & EngineRequest::ChunkedDone)) {
70 erroBody.reserve(512);
72 erroBody.append(
context->errors().join(u
'\n').toUtf8());
77 res->
setStatus(Response::InternalServerError);
90 status |= EngineRequest::Finalized;
98 const auto cookies = res->
cookies();
99 for (
const QNetworkCookie &cookie : cookies) {
100 headersRef.
pushHeader(
"Set-Cookie"_ba, cookie.toRawForm());
110 const qint64 size = response->
size();
118 status |= EngineRequest::FinalizedHeaders;
124 if (!(
status & EngineRequest::Chunked)) {
126 }
else if (!(
status & EngineRequest::ChunkedDone)) {
127 const QByteArray chunkSize = QByteArray::number(len, 16).toUpper();
129 chunk.reserve(
int(len + chunkSize.size() + 4));
130 chunk.append(chunkSize).append(
"\r\n", 2).append(data,
int(len)).append(
"\r\n", 2);
132 qint64 retWrite =
doWrite(chunk.data(), chunk.size());
136 status |= EngineRequest::ChunkedDone;
139 return retWrite == chunk.size() ? len : -1;
144bool EngineRequest::webSocketHandshake(
const QByteArray &key,
145 const QByteArray &origin,
146 const QByteArray &protocol)
148 if (
status & EngineRequest::FinalizedHeaders) {
152 if (webSocketHandshakeDo(key, origin,
protocol)) {
153 status |= EngineRequest::FinalizedHeaders | EngineRequest::Async | EngineRequest::IOWrite;
163bool EngineRequest::webSocketSendTextMessage(
const QString &message)
169bool EngineRequest::webSocketSendBinaryMessage(
const QByteArray &message)
175bool EngineRequest::webSocketSendPing(
const QByteArray &payload)
181bool EngineRequest::webSocketClose(quint16 code,
const QString &reason)
192bool EngineRequest::webSocketHandshakeDo(
const QByteArray &key,
193 const QByteArray &origin,
194 const QByteArray &protocol)
209 char *data = rawPath;
210 const char *inputPtr = data;
212 bool lastSlash =
false;
213 bool skipUtf8 =
true;
215 for (
int i = 0; i < len; ++i, ++outlen) {
216 const char c = inputPtr[i];
217 if (c ==
'%' && i + 2 < len) {
218 int a =
static_cast<unsigned char>(inputPtr[++i]);
219 int b =
static_cast<unsigned char>(inputPtr[++i]);
221 if (a >=
'0' && a <=
'9') {
223 }
else if (a >=
'a' && a <=
'f') {
225 }
else if (a >=
'A' && a <=
'F') {
229 if (b >=
'0' && b <=
'9') {
231 }
else if (b >=
'a' && b <=
'f') {
233 }
else if (b >=
'A' && b <=
'F') {
237 *data++ = char((a << 4) | b);
239 }
else if (c ==
'+') {
241 }
else if (c ==
'/') {
257 path = QString::fromLatin1(rawPath, outlen);
259 path = QString::fromUtf8(rawPath, outlen);
262 if (!
path.startsWith(u
'/')) {
267#include "moc_enginerequest.cpp"
virtual qint64 doWrite(const char *data, qint64 len)=0
virtual void finalizeBody()
virtual void finalizeError()
void setPath(char *rawPath, int len)
qint64 write(const char *data, qint64 len)
virtual bool writeHeaders(quint16 status, const Headers &headers)=0
virtual bool finalizeHeaders()
virtual void finalizeCookies()
virtual void processingFinished()
void setContentType(const QByteArray &type)
Headers & headers() noexcept
void setStatus(quint16 status) noexcept
void setBody(QIODevice *body)
QList< QNetworkCookie > cookies() const
QIODevice * bodyDevice() const noexcept
qint64 size() const noexcept override
quint16 status() const noexcept
The Cutelyst namespace holds all public Cutelyst API.