8 #include "multipartformdataparser.h"
14 #include <QJsonDocument>
15 #include <QJsonObject>
20 : d_ptr(new RequestPrivate)
22 d_ptr->engineRequest = engineRequest;
28 qDeleteAll(d_ptr->uploads);
36 return d->engineRequest->remoteAddress;
44 quint32 data = d->engineRequest->remoteAddress.toIPv4Address(&ok);
48 return d->engineRequest->remoteAddress.toString();
58 if (!d->remoteHostname.isEmpty()) {
59 ret = d->remoteHostname;
65 qCDebug(CUTELYST_REQUEST) <<
"DNS lookup for the client hostname failed"
66 << d->engineRequest->remoteAddress;
71 ret = d->remoteHostname;
75 quint16 Request::port() const noexcept
78 return d->engineRequest->remotePort;
86 if (!(d->parserStatus & RequestPrivate::UrlParsed)) {
88 if (d->engineRequest->serverAddress.isEmpty()) {
94 uri.
setScheme(d->engineRequest->isSecure ? QStringLiteral(
"https")
95 : QStringLiteral(
"http"));
99 uri.
setPath(d->engineRequest->path);
101 if (!d->engineRequest->query.isEmpty()) {
106 d->parserStatus |= RequestPrivate::UrlParsed;
115 if (!(d->parserStatus & RequestPrivate::BaseParsed)) {
116 base = d->engineRequest->isSecure ? QStringLiteral(
"https://") : QStringLiteral(
"http://");
119 if (d->engineRequest->serverAddress.isEmpty()) {
126 d->parserStatus |= RequestPrivate::BaseParsed;
134 return d->engineRequest->path;
173 bool Request::secure() const noexcept
176 return d->engineRequest->isSecure;
188 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
216 return RequestPrivate::paramsMultiMapToVariantMap(
bodyParameters());
222 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
234 while (it != query.
constEnd() && it.
key() == key) {
244 if (!(d->parserStatus & RequestPrivate::QueryParsed)) {
247 return d->queryKeywords;
258 if (!(d->parserStatus & RequestPrivate::QueryParsed)) {
261 return d->queryParam;
270 while (it != query.
constEnd() && it.
key() == key) {
280 if (!(d->parserStatus & RequestPrivate::CookiesParsed)) {
284 return d->cookies.value(name).value;
292 if (!(d->parserStatus & RequestPrivate::CookiesParsed)) {
296 for (
auto it = d->cookies.constFind(name); it != d->cookies.constEnd() && it->name == name;
306 if (!(d->parserStatus & RequestPrivate::CookiesParsed)) {
315 return d->engineRequest->headers;
321 return d->engineRequest->method;
327 return d->engineRequest->method.compare(
"POST") == 0;
333 return d->engineRequest->method.compare(
"GET") == 0;
339 return d->engineRequest->method.compare(
"HEAD") == 0;
345 return d->engineRequest->method.compare(
"PUT") == 0;
351 return d->engineRequest->method.compare(
"PATCH") == 0;
357 return d->engineRequest->method.compare(
"DELETE") == 0;
363 return d->engineRequest->protocol;
369 return d->engineRequest->headers.header(
"X-Requested-With").compare(
"XMLHttpRequest") == 0;
375 return d->engineRequest->remoteUser;
381 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
390 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
393 return d->uploadsMap;
400 const auto range = map.equal_range(name);
401 for (
auto i = range.first; i != range.second; ++i) {
416 ret.
replace(it.key(), it.value());
444 void RequestPrivate::parseUrlQuery()
const
447 if (engineRequest->query.size()) {
449 if (engineRequest->query.indexOf(
'=') < 0) {
451 queryKeywords = Utils::decodePercentEncoding(&aux);
453 if (parserStatus & RequestPrivate::UrlParsed) {
454 queryParam = Utils::decodePercentEncoding(engineRequest->query.data(),
455 engineRequest->query.size());
459 queryParam = Utils::decodePercentEncoding(aux.
data(), aux.
size());
463 parserStatus |= RequestPrivate::QueryParsed;
466 void RequestPrivate::parseBody()
const
469 parserStatus |= RequestPrivate::BodyParsed;
473 bool sequencial = body->isSequential();
474 qint64 posOrig = body->pos();
475 if (sequencial && posOrig) {
476 qCWarning(CUTELYST_REQUEST) <<
"Can not parse sequential post body out of beginning";
477 parserStatus |= RequestPrivate::BodyParsed;
481 const QByteArray contentType = engineRequest->headers.header(
"Content-Type");
482 if (contentType.
startsWith(
"application/x-www-form-urlencoded")) {
490 bodyParam = Utils::decodePercentEncoding(line.
data(), line.
size());
492 }
else if (contentType.
startsWith(
"multipart/form-data")) {
498 for (
Upload *upload : ups) {
499 if (upload->filename().isEmpty() &&
500 upload->headers().header(
"Content-Type"_qba).isEmpty()) {
504 uploadsMap.insert(upload->name(), upload);
508 }
else if (contentType.
startsWith(
"application/cbor")) {
514 }
else if (contentType.
startsWith(
"application/json")) {
526 parserStatus |= RequestPrivate::BodyParsed;
529 static inline bool isSlit(
char c)
531 return c ==
';' || c ==
',';
536 while (from < length) {
537 if (isSlit(text.
at(from))) {
545 static inline bool isLWS(
char c)
547 return c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n';
550 static int nextNonWhitespace(
QByteArrayView text,
int from,
int length)
556 while (from < length) {
557 if (isLWS(text.
at(from)))
574 const int length = text.
length();
575 position = nextNonWhitespace(text, position, length);
577 int semiColonPosition = findNextSplit(text, position, length);
578 if (semiColonPosition < 0)
579 semiColonPosition = length;
581 int equalsPosition = text.
indexOf(
'=', position);
582 if (equalsPosition < 0 || equalsPosition > semiColonPosition) {
587 int secondLength = semiColonPosition - equalsPosition - 1;
588 if (secondLength > 0) {
592 position = semiColonPosition;
596 void RequestPrivate::parseCookies()
const
598 const QByteArray cookieString = engineRequest->headers.header(
"Cookie"_qba);
600 const int length = cookieString.
length();
601 while (position < length) {
602 const auto cookie = nextField(cookieString, position);
613 cookies.insert(cookie.name, cookie);
617 parserStatus |= RequestPrivate::CookiesParsed;
620 QVariantMap RequestPrivate::paramsMultiMapToVariantMap(
const ParamsMultiMap ¶ms)
626 ret.insert(ret.constBegin(), end.key(), end.value());
631 #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
QJsonArray bodyJsonArray() const
bool xhr() const noexcept
QJsonObject bodyJsonObject() const
QStringList captures() const noexcept
bool isPut() const noexcept
bool isDelete() const noexcept
QByteArray cookie(QByteArrayView name) const
QUrl uriWith(const ParamsMultiMap &args, bool append=false) const
bool isPost() 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)
bool isHead() const noexcept
void setArguments(const QStringList &arguments)
QHostAddress address() const noexcept
void setMatch(const QString &match)
QMultiMap< QStringView, Upload * > uploadsMap() const
Cutelyst Upload handles file upload requests.
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::parameter_type value)
void push_back(QList::parameter_type value)
const Key & key() const const
QMultiMap::const_iterator constBegin() const const
QMultiMap::const_iterator constEnd() const const
QMultiMap::const_iterator constFind(const Key &key) const const
QMultiMap::iterator replace(const Key &key, const T &value)
QMultiMap< Key, T > & unite(QMultiMap< Key, T > &&other)
QString & append(QChar ch)
QString fromLatin1(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
void setAuthority(const QString &authority, QUrl::ParsingMode mode)
void setHost(const QString &host, QUrl::ParsingMode mode)
void setPath(const QString &path, QUrl::ParsingMode mode)
void setQuery(const QString &query, QUrl::ParsingMode mode)
void setScheme(const QString &scheme)
QString url(QUrl::FormattingOptions options) const const
void addQueryItem(const QString &key, const QString &value)
QVariant fromValue(T &&value)
QJsonDocument toJsonDocument() const const