8#include "multipartformdataparser.h"
14#include <QJsonDocument>
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;
78 return d->engineRequest->remotePort;
86 if (!(d->parserStatus & RequestPrivate::UrlParsed)) {
88 if (d->engineRequest->serverAddress.isEmpty()) {
91 uri.setAuthority(d->engineRequest->serverAddress);
94 uri.setScheme(d->engineRequest->isSecure ? QStringLiteral(
"https")
95 : QStringLiteral(
"http"));
98 uri.setPath(
QLatin1Char(
'/') + d->engineRequest->path);
100 if (!d->engineRequest->query.isEmpty()) {
105 d->parserStatus |= RequestPrivate::UrlParsed;
114 if (!(d->parserStatus & RequestPrivate::BaseParsed)) {
115 base = d->engineRequest->isSecure ? QStringLiteral(
"https://") : QStringLiteral(
"http://");
118 if (d->engineRequest->serverAddress.isEmpty()) {
121 base.append(d->engineRequest->serverAddress);
128 d->parserStatus |= RequestPrivate::BaseParsed;
136 return d->engineRequest->path;
178 return d->engineRequest->isSecure;
190 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
213 return RequestPrivate::paramsMultiMapToVariantMap(
bodyParameters());
219 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
231 while (it != query.constEnd() && it.key() == key) {
241 if (!(d->parserStatus & RequestPrivate::QueryParsed)) {
244 return d->queryKeywords;
255 if (!(d->parserStatus & RequestPrivate::QueryParsed)) {
258 return d->queryParam;
267 while (it != query.constEnd() && it.key() == key) {
277 if (!(d->parserStatus & RequestPrivate::CookiesParsed)) {
281 return d->cookies.value(name);
289 if (!(d->parserStatus & RequestPrivate::CookiesParsed)) {
293 auto it = d->cookies.constFind(name);
294 while (it != d->cookies.constEnd() && it.key() == name) {
304 if (!(d->parserStatus & RequestPrivate::CookiesParsed)) {
313 return d->engineRequest->headers;
319 return d->engineRequest->method;
325 return d->engineRequest->method.compare(u
"POST") == 0;
331 return d->engineRequest->method.compare(u
"GET") == 0;
337 return d->engineRequest->method.compare(u
"HEAD") == 0;
343 return d->engineRequest->method.compare(u
"PUT") == 0;
349 return d->engineRequest->method.compare(u
"PATCH") == 0;
355 return d->engineRequest->method.compare(u
"DELETE") == 0;
361 return d->engineRequest->protocol;
367 return d->engineRequest->headers.header(QStringLiteral(
"X_REQUESTED_WITH"))
368 .compare(u
"XMLHttpRequest") == 0;
374 return d->engineRequest->remoteUser;
380 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
389 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
392 return d->uploadsMap;
399 const auto range = map.equal_range(name);
400 for (
auto i = range.first; i != range.second; ++i) {
412 auto it = args.constEnd();
413 while (it != args.constBegin()) {
415 ret.
replace(it.key(), it.value());
427 auto it = query.constEnd();
428 while (it != query.constBegin()) {
443void RequestPrivate::parseUrlQuery()
const
446 if (engineRequest->query.size()) {
448 if (engineRequest->query.indexOf(
'=') < 0) {
450 queryKeywords = Utils::decodePercentEncoding(&aux);
452 if (parserStatus & RequestPrivate::UrlParsed) {
453 queryParam = Utils::decodePercentEncoding(engineRequest->query.data(),
454 engineRequest->query.size());
456 QByteArray aux = engineRequest->query;
458 queryParam = Utils::decodePercentEncoding(aux.
data(), aux.
size());
462 parserStatus |= RequestPrivate::QueryParsed;
465void RequestPrivate::parseBody()
const
468 parserStatus |= RequestPrivate::BodyParsed;
472 bool sequencial = body->isSequential();
473 qint64 posOrig = body->pos();
474 if (sequencial && posOrig) {
475 qCWarning(CUTELYST_REQUEST) <<
"Can not parse sequential post body out of beginning";
476 parserStatus |= RequestPrivate::BodyParsed;
480 const QString contentTypeKey = QStringLiteral(
"CONTENT_TYPE");
481 const QString contentType = engineRequest->headers.header(contentTypeKey);
489 QByteArray line = body->readAll();
490 bodyParam = Utils::decodePercentEncoding(line.
data(), line.
size());
498 for (
Upload *upload : ups) {
499 if (upload->filename().isEmpty() &&
500 upload->headers().header(contentTypeKey).isEmpty()) {
504 uploadsMap.insert(upload->name(), upload);
520 parserStatus |= RequestPrivate::BodyParsed;
523static inline bool isSlit(QChar c)
525 return c == u
';' || c == u
',';
528int findNextSplit(
const QString &text,
int from,
int length)
530 while (from < length) {
531 if (isSlit(text.
at(from))) {
539static inline bool isLWS(QChar c)
541 return c == u
' ' || c == u
'\t' || c == u
'\r' || c == u
'\n';
544static int nextNonWhitespace(
const QString &text,
int from,
int length)
550 while (from < length) {
551 if (isLWS(text.
at(from)))
561static std::pair<QString, QString> nextField(
const QString &text,
int &position)
563 std::pair<QString, QString> ret;
568 const int length = text.
length();
569 position = nextNonWhitespace(text, position, length);
571 int semiColonPosition = findNextSplit(text, position, length);
572 if (semiColonPosition < 0)
573 semiColonPosition = length;
575 int equalsPosition = text.
indexOf(QLatin1Char(
'='), position);
576 if (equalsPosition < 0 || equalsPosition > semiColonPosition) {
580 ret.first = QStringView(text).mid(position, equalsPosition - position).trimmed().toString();
581 int secondLength = semiColonPosition - equalsPosition - 1;
582 if (secondLength > 0) {
583 ret.second = QStringView(text).mid(equalsPosition + 1, secondLength).trimmed().toString();
586 position = semiColonPosition;
590void RequestPrivate::parseCookies()
const
592 const QString cookieString = engineRequest->headers.header(QStringLiteral(
"COOKIE"));
594 const int length = cookieString.
length();
595 while (position < length) {
596 const auto field = nextField(cookieString, position);
597 if (field.first.isEmpty()) {
603 if (field.second.isEmpty()) {
607 cookies.insert(field.first, field.second);
611 parserStatus |= RequestPrivate::CookiesParsed;
614QVariantMap RequestPrivate::paramsMultiMapToVariantMap(
const ParamsMultiMap ¶ms)
617 auto end = params.constEnd();
618 while (params.constBegin() != end) {
620 ret.insert(ret.constBegin(), end.key(), end.value());
625#include "moc_request.cpp"
QIODevice * body
The QIODevice containing the body (if any) of the request.
QMultiMap< QString, Upload * > uploadsMap() const
QVariantMap bodyParametersVariant() const
QString method() const noexcept
QVariantMap queryParametersVariant() const
QString addressString() const
bool isGet() const noexcept
QString queryKeywords() const
QVector< Upload * > uploads() const
ParamsMultiMap bodyParameters() const
QVariant bodyData() const
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
QUrl uriWith(const ParamsMultiMap &args, bool append=false) const
bool isPost() const noexcept
QString remoteUser() const noexcept
QString protocol() const noexcept
QJsonDocument bodyJsonDocument() const
ParamsMultiMap mangleParams(const ParamsMultiMap &args, bool append=false) const
void setCaptures(const QStringList &captures)
Headers headers() const noexcept
ParamsMultiMap queryParameters() const
QString cookie(const QString &name) const
bool isPatch() const noexcept
Engine * engine() const noexcept
Request(EngineRequest *engineRequest)
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)
ParamsMultiMap cookies() const
Cutelyst Upload handles file upload request
The Cutelyst namespace holds all public Cutelyst API.
QVector< Upload * > Uploads
QMultiMap< QString, QString > ParamsMultiMap
QString toString() const const
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(const T &value)
typename QMap< Key, T >::const_iterator constFind(const Key &key, const T &value) const const
typename QMap< Key, T >::iterator replace(const Key &key, const T &value)
QMultiMap< Key, T > & unite(const QMultiMap< Key, T > &other)
const QChar at(int position) const const
QString fromLatin1(const char *str, int size)
QString fromUtf8(const char *str, int size)
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
void setQuery(const QString &query, ParsingMode mode)
QString url(FormattingOptions options) const const
void addQueryItem(const QString &key, const QString &value)
QVariant fromValue(const T &value)
QJsonDocument toJsonDocument() const const
void push_back(const T &value)