8#include "multipartformdataparser.h"
14#include <QJsonDocument>
21 : d_ptr(new RequestPrivate)
23 d_ptr->engineRequest = engineRequest;
29 qDeleteAll(d_ptr->uploads);
37 return d->engineRequest->remoteAddress;
45 quint32 data = d->engineRequest->remoteAddress.toIPv4Address(&ok);
49 return d->engineRequest->remoteAddress.toString();
59 if (!d->remoteHostname.isEmpty()) {
60 ret = d->remoteHostname;
66 qCDebug(CUTELYST_REQUEST) <<
"DNS lookup for the client hostname failed"
67 << d->engineRequest->remoteAddress;
72 ret = d->remoteHostname;
79 return d->engineRequest->remotePort;
87 if (!(d->parserStatus & RequestPrivate::UrlParsed)) {
89 if (d->engineRequest->serverAddress.isEmpty()) {
95 uri.setScheme(d->engineRequest->isSecure ? QStringLiteral(
"https")
96 : QStringLiteral(
"http"));
100 uri.setPath(d->engineRequest->path);
102 if (!d->engineRequest->query.isEmpty()) {
107 d->parserStatus |= RequestPrivate::UrlParsed;
116 if (!(d->parserStatus & RequestPrivate::BaseParsed)) {
117 base = d->engineRequest->isSecure ? QStringLiteral(
"https://") : QStringLiteral(
"http://");
120 if (d->engineRequest->serverAddress.isEmpty()) {
127 d->parserStatus |= RequestPrivate::BaseParsed;
135 return d->engineRequest->path;
177 return d->engineRequest->isSecure;
189 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
217 return RequestPrivate::paramsMultiMapToVariantMap(
bodyParameters());
223 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
235 while (it != query.
constEnd() && it.key() == key) {
245 if (!(d->parserStatus & RequestPrivate::QueryParsed)) {
248 return d->queryKeywords;
259 if (!(d->parserStatus & RequestPrivate::QueryParsed)) {
262 return d->queryParam;
271 while (it != query.
constEnd() && it.key() == key) {
281 if (!(d->parserStatus & RequestPrivate::CookiesParsed)) {
285 return d->cookies.value(name).value;
293 if (!(d->parserStatus & RequestPrivate::CookiesParsed)) {
297 for (
auto it = d->cookies.constFind(name); it != d->cookies.constEnd() && it->name == name;
307 if (!(d->parserStatus & RequestPrivate::CookiesParsed)) {
316 return d->engineRequest->headers;
322 return d->engineRequest->method;
328 return d->engineRequest->method.compare(
"POST") == 0;
334 return d->engineRequest->method.compare(
"GET") == 0;
340 return d->engineRequest->method.compare(
"HEAD") == 0;
346 return d->engineRequest->method.compare(
"PUT") == 0;
352 return d->engineRequest->method.compare(
"PATCH") == 0;
358 return d->engineRequest->method.compare(
"DELETE") == 0;
364 return d->engineRequest->protocol;
370 return d->engineRequest->headers.header(
"X-Requested-With").compare(
"XMLHttpRequest") == 0;
376 return d->engineRequest->remoteUser;
382 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
391 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
394 return d->uploadsMap;
401 const auto range = map.equal_range(name);
402 for (
auto i = range.first; i != range.second; ++i) {
414 auto it = args.constEnd();
415 while (it != args.constBegin()) {
417 ret.
replace(it.key(), it.value());
445void RequestPrivate::parseUrlQuery()
const
448 if (engineRequest->query.size()) {
450 if (engineRequest->query.indexOf(
'=') < 0) {
452 queryKeywords = Utils::decodePercentEncoding(&aux);
454 if (parserStatus & RequestPrivate::UrlParsed) {
455 queryParam = Utils::decodePercentEncoding(engineRequest->query.data(),
456 engineRequest->query.size());
458 QByteArray aux = engineRequest->query;
460 queryParam = Utils::decodePercentEncoding(aux.
data(), aux.
size());
464 parserStatus |= RequestPrivate::QueryParsed;
467void RequestPrivate::parseBody()
const
470 parserStatus |= RequestPrivate::BodyParsed;
474 bool sequencial = body->isSequential();
475 qint64 posOrig = body->pos();
476 if (sequencial && posOrig) {
477 qCWarning(CUTELYST_REQUEST) <<
"Can not parse sequential post body out of beginning";
478 parserStatus |= RequestPrivate::BodyParsed;
482 const QByteArray contentType = engineRequest->headers.header(
"Content-Type");
483 if (contentType.
startsWith(
"application/x-www-form-urlencoded")) {
490 QByteArray line = body->readAll();
491 bodyParam = Utils::decodePercentEncoding(line.
data(), line.
size());
493 }
else if (contentType.
startsWith(
"multipart/form-data")) {
499 for (
Upload *upload : ups) {
500 if (upload->filename().isEmpty() &&
501 upload->headers().header(
"Content-Type"_ba).isEmpty()) {
505 uploadsMap.insert(upload->name(), upload);
509 }
else if (contentType.
startsWith(
"application/cbor")) {
515 }
else if (contentType.
startsWith(
"application/json")) {
527 parserStatus |= RequestPrivate::BodyParsed;
530static inline bool isSlit(
char c)
532 return c ==
';' || c ==
',';
535int findNextSplit(QByteArrayView text,
int from,
int length)
537 while (from < length) {
538 if (isSlit(text.
at(from))) {
546static inline bool isLWS(
char c)
548 return c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n';
551static int nextNonWhitespace(QByteArrayView text,
int from,
int length)
557 while (from < length) {
558 if (isLWS(text.
at(from)))
575 const int length = text.
length();
576 position = nextNonWhitespace(text, position, length);
578 int semiColonPosition = findNextSplit(text, position, length);
579 if (semiColonPosition < 0)
580 semiColonPosition = length;
582 int equalsPosition = text.
indexOf(
'=', position);
583 if (equalsPosition < 0 || equalsPosition > semiColonPosition) {
588 int secondLength = semiColonPosition - equalsPosition - 1;
589 if (secondLength > 0) {
593 position = semiColonPosition;
597void RequestPrivate::parseCookies()
const
599 const QByteArray cookieString = engineRequest->headers.header(
"Cookie"_ba);
601 const int length = cookieString.
length();
602 while (position < length) {
603 const auto cookie = nextField(cookieString, position);
614 cookies.insert(cookie.name, cookie);
618 parserStatus |= RequestPrivate::CookiesParsed;
621QVariantMap RequestPrivate::paramsMultiMapToVariantMap(
const ParamsMultiMap ¶ms)
627 ret.insert(ret.constBegin(), end.key(), end.value());
632#include "moc_request.cpp"
QVariantMap bodyParametersVariant() const
QCborValue bodyCbor() const
QVariantMap queryParametersVariant() const
QString addressString() const
bool isGet() const noexcept
QString queryKeywords() const
QVector< Upload * > uploads() const
ParamsMultiMap bodyParameters() const
QVariant bodyData() const
quint16 port() const noexcept
QJsonArray bodyJsonArray() const
bool xhr() const noexcept
bool secure() const noexcept
QJsonObject bodyJsonObject() const
QString path() const noexcept
ParamsMultiMap queryParams() const
QStringList captures() const noexcept
bool isPut() const noexcept
bool isDelete() const noexcept
QByteArray protocol() const noexcept
QByteArray cookie(QByteArrayView name) const
QUrl uriWith(const ParamsMultiMap &args, bool append=false) const
bool isPost() const noexcept
QString remoteUser() const noexcept
QJsonDocument bodyJsonDocument() const
ParamsMultiMap mangleParams(const ParamsMultiMap &args, bool append=false) const
void setCaptures(const QStringList &captures)
QMultiMap< QByteArrayView, Cookie > cookies() const
Headers headers() const noexcept
QIODevice * body() const noexcept
ParamsMultiMap queryParameters() const
bool isPatch() const noexcept
Engine * engine() const noexcept
Request(EngineRequest *engineRequest)
QByteArray method() const noexcept
bool isHead() const noexcept
void setArguments(const QStringList &arguments)
QString match() const noexcept
QStringList arguments() const noexcept
QHostAddress address() const noexcept
void setMatch(const QString &match)
QMultiMap< QStringView, Upload * > uploadsMap() const
Cutelyst Upload handles file upload requests.
QMultiMap< QString, QString > ParamsMultiMap
The Cutelyst namespace holds all public Cutelyst API.
bool isEmpty() const const
qsizetype length() const const
qsizetype size() const const
bool startsWith(QByteArrayView bv) const const
char at(qsizetype n) const const
qsizetype indexOf(QByteArrayView bv, qsizetype from) const const
qsizetype length() const const
QByteArrayView sliced(qsizetype pos) const const
QByteArray toByteArray() const const
QByteArrayView trimmed() const const
QCborValue fromCbor(QCborStreamReader &reader)
QString toString() const const
QHostInfo::HostInfoError error() const const
QHostInfo fromName(const QString &name)
QString hostName() const const
QJsonArray array() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QJsonObject object() const const
void prepend(QList< T >::parameter_type value)
QMultiMap< Key, T >::const_iterator constBegin() const const
QMultiMap< Key, T >::const_iterator constEnd() const const
QMultiMap< Key, T >::const_iterator constFind(const Key &key) const const
QMultiMap< Key, T >::iterator replace(const Key &key, const T &value)
QMultiMap< Key, T > & unite(QMultiMap< Key, T > &&other)
QString fromLatin1(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
void setQuery(const QString &query, QUrl::ParsingMode mode)
QString url(QUrl::FormattingOptions options) const const
void addQueryItem(const QString &key, const QString &value)
QVariant fromValue(T &&value)
QJsonDocument toJsonDocument() const const