18 #include "request_p.h" 20 #include "enginerequest.h" 22 #include "multipartformdataparser.h" 26 #include <QJsonDocument> 28 #include <QJsonObject> 33 d_ptr(new RequestPrivate)
35 d_ptr->engineRequest = engineRequest;
41 qDeleteAll(d_ptr->uploads);
49 return d->engineRequest->remoteAddress;
57 quint32 data = d->engineRequest->remoteAddress.toIPv4Address(&ok);
59 return QHostAddress(data).toString();
61 return d->engineRequest->remoteAddress.toString();
71 if (!d->remoteHostname.isEmpty()) {
72 ret = d->remoteHostname;
76 const QHostInfo ptr = QHostInfo::fromName(d->engineRequest->remoteAddress.toString());
77 if (ptr.error() != QHostInfo::NoError) {
78 qCDebug(CUTELYST_REQUEST) <<
"DNS lookup for the client hostname failed" << d->engineRequest->remoteAddress;
82 d->remoteHostname = ptr.hostName();
83 ret = d->remoteHostname;
90 return d->engineRequest->remotePort;
98 if (!(d->parserStatus & RequestPrivate::UrlParsed)) {
100 if (d->engineRequest->serverAddress.isEmpty()) {
101 uri.setHost(QHostInfo::localHostName());
103 uri.setAuthority(d->engineRequest->serverAddress);
106 uri.setScheme(d->engineRequest->isSecure ? QStringLiteral(
"https") : QStringLiteral(
"http"));
111 if (!d->engineRequest->query.isEmpty()) {
112 uri.setQuery(QString::fromLatin1(d->engineRequest->query));
116 d->parserStatus |= RequestPrivate::UrlParsed;
124 QString
base = d->base;
125 if (!(d->parserStatus & RequestPrivate::BaseParsed)) {
126 base = d->engineRequest->isSecure ? QStringLiteral(
"https://") : QStringLiteral(
"http://");
129 if (d->engineRequest->serverAddress.isEmpty()) {
130 base.append(QHostInfo::localHostName());
132 base.append(d->engineRequest->serverAddress);
139 d->parserStatus |= RequestPrivate::BaseParsed;
147 return d->engineRequest->path;
189 return d->engineRequest->isSecure;
201 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
214 return bodyData().toJsonDocument().object();
219 return bodyData().toJsonDocument().array();
224 return RequestPrivate::paramsMultiMapToVariantMap(
bodyParameters());
230 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
242 while (it != query.
constEnd() && it.key() == key) {
243 ret.prepend(it.value());
252 if (!(d->parserStatus & RequestPrivate::QueryParsed)) {
255 return d->queryKeywords;
266 if (!(d->parserStatus & RequestPrivate::QueryParsed)) {
269 return d->queryParam;
278 while (it != query.
constEnd() && it.key() == key) {
279 ret.prepend(it.value());
288 if (!(d->parserStatus & RequestPrivate::CookiesParsed)) {
292 return d->cookies.value(name);
300 if (!(d->parserStatus & RequestPrivate::CookiesParsed)) {
304 auto it = d->cookies.constFind(name);
305 while (it != d->cookies.constEnd() && it.key() == name) {
306 ret.prepend(it.value());
315 if (!(d->parserStatus & RequestPrivate::CookiesParsed)) {
324 return d->engineRequest->headers;
330 return d->engineRequest->method;
336 return d->engineRequest->method == QStringLiteral(
"POST");
342 return d->engineRequest->method == QStringLiteral(
"GET");
348 return d->engineRequest->method == QStringLiteral(
"HEAD");
354 return d->engineRequest->method == QStringLiteral(
"PUT");
360 return d->engineRequest->method == QStringLiteral(
"PATCH");
366 return d->engineRequest->method == QStringLiteral(
"DELETE");
372 return d->engineRequest->protocol;
378 return d->engineRequest->headers.header(QStringLiteral(
"X_REQUESTED_WITH")) == QStringLiteral(
"XMLHttpRequest");
384 return d->engineRequest->remoteUser;
390 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
399 if (!(d->parserStatus & RequestPrivate::BodyParsed)) {
402 return d->uploadsMap;
409 const auto range = map.equal_range(name);
410 for (
auto i = range.first; i != range.second; ++i) {
422 auto it =
args.constEnd();
423 while (it !=
args.constBegin()) {
425 ret.
insert(it.key(), it.value());
440 urlQuery.addQueryItem(it.key(), it.value());
442 ret.setQuery(urlQuery);
453 void RequestPrivate::parseUrlQuery()
const 456 if (engineRequest->query.size()) {
458 if (engineRequest->query.indexOf(
'=') < 0) {
459 QByteArray aux = engineRequest->query;
460 queryKeywords = Utils::decodePercentEncoding(&aux);
462 queryParam = parseUrlEncoded(engineRequest->query);
465 parserStatus |= RequestPrivate::QueryParsed;
468 void RequestPrivate::parseBody()
const 471 parserStatus |= RequestPrivate::BodyParsed;
475 bool sequencial = body->isSequential();
476 qint64 posOrig = body->pos();
477 if (sequencial && posOrig) {
478 qCWarning(CUTELYST_REQUEST) <<
"Can not parse sequential post body out of beginning";
479 parserStatus |= RequestPrivate::BodyParsed;
483 const QString contentType = engineRequest->headers.contentType();
484 if (contentType ==
QLatin1String(
"application/x-www-form-urlencoded")) {
491 bodyParam = parseUrlEncoded(body->readLine());
492 bodyData = QVariant::fromValue(bodyParam);
493 }
else if (contentType ==
QLatin1String(
"multipart/form-data")) {
499 for (
Upload *upload : ups) {
500 if (upload->filename().isEmpty() && upload->contentType().isEmpty()) {
501 bodyParam.insertMulti(upload->name(), QString::fromUtf8(upload->readAll()));
504 uploadsMap.insertMulti(upload->name(), upload);
507 bodyData = QVariant::fromValue(uploadsMap);
508 }
else if (contentType ==
QLatin1String(
"application/json")) {
513 bodyData = QJsonDocument::fromJson(body->readAll());
520 parserStatus |= RequestPrivate::BodyParsed;
523 static inline bool isSlit(QChar c)
528 int findNextSplit(
const QString &text,
int from,
int length)
530 while (from < length) {
531 if (isSlit(text.at(from))) {
539 static inline bool isLWS(QChar c)
544 static int nextNonWhitespace(
const QString &text,
int from,
int length)
550 while (from < length) {
551 if (isLWS(text.at(from)))
558 return text.length();
561 static 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 = text.midRef(position, equalsPosition - position).trimmed().toString();
581 int secondLength = semiColonPosition - equalsPosition - 1;
582 if (secondLength > 0) {
583 ret.second = text.midRef(equalsPosition + 1, secondLength).trimmed().toString();
586 position = semiColonPosition;
590 void 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.insertMulti(field.first, field.second);
611 parserStatus |= RequestPrivate::CookiesParsed;
614 ParamsMultiMap RequestPrivate::parseUrlEncoded(
const QByteArray &line)
619 while (from < line.length()) {
620 const int pos = line.indexOf(
'&', from);
624 len = line.length() - from;
629 if (len == 0 || (len == 1 && line[from] ==
'=')) {
635 QByteArray data = line.mid(from, len);
637 int equal = data.indexOf(
'=');
639 QByteArray key = data.mid(0, equal);
640 if (++equal < data.size()) {
641 QByteArray value = data.mid(equal);
642 ret.
insertMulti(Utils::decodePercentEncoding(&key),
643 Utils::decodePercentEncoding(&value));
645 ret.
insertMulti(Utils::decodePercentEncoding(&key),
649 ret.
insertMulti(Utils::decodePercentEncoding(&data),
662 QVariantMap RequestPrivate::paramsMultiMapToVariantMap(
const ParamsMultiMap ¶ms)
668 ret.insertMulti(ret.constBegin(), end.key(), end.value());
673 #include "moc_request.cpp" Request(EngineRequest *engineRequest)
QHostAddress address() const
QStringList captures() const
QVariant bodyData() const
QMap< Key, T > & unite(const QMap< Key, T > &other)
QString remoteUser() const
QMap::const_iterator constBegin() const const
QJsonArray bodyJsonArray() const
QIODevice * body
The QIODevice containing the body (if any) of the request.
QMap::const_iterator constFind(const Key &key) const const
void setMatch(const QString &match)
Cutelyst Upload handles file upload request
ParamsMultiMap queryParams() const
ParamsMultiMap bodyParameters() const
QVector< Upload * > uploads() const
QMap::iterator insertMulti(const Key &key, const T &value)
QString addressString() const
QMap::const_iterator constEnd() const const
ParamsMultiMap cookies() const
The Cutelyst namespace holds all public Cutelyst API.
QJsonObject bodyJsonObject() const
QMap< QString, Upload * > uploadsMap() const
void setCaptures(const QStringList &captures)
void setArguments(const QStringList &arguments)
QJsonDocument bodyJsonDocument() const
ParamsMultiMap queryParameters() const
ParamsMultiMap mangleParams(const ParamsMultiMap &args, bool append=false) const
QString queryKeywords() const
QStringList arguments() const
QString cookie(const QString &name) const
QVariantMap bodyParametersVariant() const
QVector< Upload * > Uploads
QMap::iterator insert(const Key &key, const T &value)
QUrl uriWith(const ParamsMultiMap &args, bool append=false) const
QVariantMap queryParametersVariant() const