8 #include "multipartformdataparser.h" 14 #include <QJsonDocument> 15 #include <QJsonObject> 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"));
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) {
417 ret.
replace(it.key(), it.value());
445 void 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());
460 queryParam = Utils::decodePercentEncoding(aux.
data(), aux.
size());
464 parserStatus |= RequestPrivate::QueryParsed;
467 void 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")) {
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;
530 static inline bool isSlit(
char c)
532 return c ==
';' || c ==
',';
537 while (from < length) {
538 if (isSlit(text.
at(from))) {
546 static inline bool isLWS(
char c)
548 return c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n';
551 static 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;
597 void 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;
621 QVariantMap RequestPrivate::paramsMultiMapToVariantMap(
const ParamsMultiMap ¶ms)
627 ret.insert(ret.constBegin(), end.key(), end.value());
632 #include "moc_request.cpp" QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QString url(FormattingOptions options) const const
Request(EngineRequest *engineRequest)
QString & append(QChar ch)
QByteArray toByteArray() const const
const_iterator constFind(const Key &key) const const
QJsonDocument toJsonDocument() const const
QJsonArray array() const const
iterator replace(const Key &key, const T &value)
QVariant bodyData() const
void push_back(parameter_type value)
QByteArray protocol() const noexcept
const_iterator constEnd() const const
QCborValue bodyCbor() const
bool isDelete() const noexcept
QVariant fromValue(T &&value)
QJsonObject object() const const
QStringList arguments() const noexcept
bool isEmpty() const const
bool startsWith(QByteArrayView bv) const const
QJsonArray bodyJsonArray() const
QByteArrayView sliced(qsizetype pos) const const
QString toString() const const
QString fromUtf8(QByteArrayView str)
qsizetype length() const const
void setMatch(const QString &match)
QIODevice * body() const noexcept
QString match() const noexcept
Cutelyst Upload handles file upload requests.
void setPath(const QString &path, ParsingMode mode)
const_iterator constBegin() const const
ParamsMultiMap queryParams() const
ParamsMultiMap bodyParameters() const
QCborValue fromCbor(QCborStreamReader &reader)
void addQueryItem(const QString &key, const QString &value)
QVector< Upload * > uploads() const
QHostAddress address() const noexcept
void setAuthority(const QString &authority, ParsingMode mode)
QString addressString() const
Headers headers() const noexcept
bool isGet() const noexcept
void setScheme(const QString &scheme)
QMultiMap< QByteArrayView, Cookie > cookies() const
The Cutelyst namespace holds all public Cutelyst API.
const Key & key() const const
QStringList args() const noexcept
QJsonObject bodyJsonObject() const
QByteArrayView trimmed() const const
void setCaptures(const QStringList &captures)
qsizetype length() const const
void setArguments(const QStringList &arguments)
QJsonDocument bodyJsonDocument() const
void prepend(parameter_type value)
QHostInfo fromName(const QString &name)
ParamsMultiMap queryParameters() const
bool isPost() const noexcept
QByteArray method() const noexcept
ParamsMultiMap mangleParams(const ParamsMultiMap &args, bool append=false) const
bool xhr() const noexcept
QString fromLatin1(QByteArrayView str)
qsizetype indexOf(QByteArrayView bv, qsizetype from) const const
quint16 port() const noexcept
QStringList captures() const noexcept
void setQuery(const QString &query, ParsingMode mode)
QString queryKeywords() const
char at(qsizetype n) const const
bool isPut() const noexcept
QVariantMap bodyParametersVariant() const
QByteArray cookie(QByteArrayView name) const
void setHost(const QString &host, ParsingMode mode)
bool secure() const noexcept
bool isPatch() const noexcept
QUrl uriWith(const ParamsMultiMap &args, bool append=false) const
const_iterator constEnd() const const
const_iterator constBegin() const const
qsizetype size() const const
HostInfoError error() const const
QVariantMap queryParametersVariant() const
QString remoteUser() const noexcept
bool isHead() const noexcept
QMultiMap< Key, T > & unite(QMultiMap< Key, T > &&other)
QString path() const noexcept
Engine * engine() const noexcept
QMultiMap< QStringView, Upload * > uploadsMap() const
QString hostName() const const