14inline QString normalizeHeaderKey(
const QString &field);
15inline QByteArray decodeBasicAuth(
const QString &auth);
19 : m_data(other.m_data)
25 return m_data.value(QStringLiteral(
"CONTENT_DISPOSITION"));
30 m_data.replace(QStringLiteral(
"CACHE_CONTROL"), value);
40 if (filename.isEmpty()) {
50 return m_data.value(QStringLiteral(
"CONTENT_ENCODING"));
55 m_data.replace(QStringLiteral(
"CONTENT_ENCODING"), encoding);
61 const auto it = m_data.constFind(QStringLiteral(
"CONTENT_TYPE"));
62 if (it != m_data.constEnd()) {
63 const QString &ct = it.value();
64 ret = ct.mid(0, ct.indexOf(QLatin1Char(
';'))).toLower();
71 m_data.replace(QStringLiteral(
"CONTENT_TYPE"),
contentType);
77 const auto it = m_data.constFind(QStringLiteral(
"CONTENT_TYPE"));
78 if (it != m_data.constEnd()) {
80 int pos =
contentType.indexOf(u
"charset=", 0, Qt::CaseInsensitive);
83 ret =
contentType.mid(pos + 8, endPos).trimmed().toUpper();
92 const auto it = m_data.constFind(QStringLiteral(
"CONTENT_TYPE"));
93 if (it == m_data.constEnd() || (it.value().isEmpty() && !charset.isEmpty())) {
94 m_data.replace(QStringLiteral(
"CONTENT_TYPE"), QLatin1String(
"charset=") + charset);
99 int pos =
contentType.indexOf(QLatin1String(
"charset="), 0, Qt::CaseInsensitive);
101 int endPos =
contentType.indexOf(QLatin1Char(
';'), pos);
103 if (charset.isEmpty()) {
104 int lastPos =
contentType.lastIndexOf(QLatin1Char(
';'), pos);
106 m_data.remove(QStringLiteral(
"CONTENT_TYPE"));
117 }
else if (!charset.isEmpty()) {
118 contentType.append(QLatin1String(
"; charset=") + charset);
120 m_data.replace(QStringLiteral(
"CONTENT_TYPE"),
contentType);
125 return m_data.value(QStringLiteral(
"CONTENT_TYPE")).startsWith(u
"text/");
131 return ct.compare(u
"text/html") == 0 || ct.compare(u
"application/xhtml+xml") == 0 ||
132 ct.compare(u
"application/vnd.wap.xhtml+xml") == 0;
138 return ct.compare(u
"application/xhtml+xml") == 0 ||
139 ct.compare(u
"application/vnd.wap.xhtml+xml") == 0;
145 return ct.compare(u
"text/xml") == 0 || ct.compare(u
"application/xml") == 0 ||
151 const auto it = m_data.constFind(QStringLiteral(
"CONTENT_TYPE"));
152 if (it != m_data.constEnd()) {
153 return it.value().compare(u
"application/json") == 0;
160 auto it = m_data.constFind(QStringLiteral(
"CONTENT_LENGTH"));
161 if (it != m_data.constEnd()) {
162 return it.value().toLongLong();
169 m_data.replace(QStringLiteral(
"CONTENT_LENGTH"), QString::number(value));
176 QString dt = QLocale::c().toString(
date.toUTC(), u
"ddd, dd MMM yyyy hh:mm:ss 'GMT");
177 m_data.replace(QStringLiteral(
"DATE"), dt);
184 auto it = m_data.constFind(QStringLiteral(
"DATE"));
185 if (it != m_data.constEnd()) {
186 const QString &
date = it.value();
188 if (
date.endsWith(u
" GMT")) {
189 ret = QLocale::c().toDateTime(
date.left(
date.size() - 4),
190 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
192 ret = QLocale::c().toDateTime(
date, QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
194 ret.setTimeSpec(Qt::UTC);
202 return m_data.value(QStringLiteral(
"IF_MODIFIED_SINCE"));
208 auto it = m_data.constFind(QStringLiteral(
"IF_MODIFIED_SINCE"));
209 if (it != m_data.constEnd()) {
210 const QString &ifModifiedStr = it.value();
212 if (ifModifiedStr.endsWith(u
" GMT")) {
213 ret = QLocale::c().toDateTime(ifModifiedStr.left(ifModifiedStr.size() - 4),
214 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
217 QLocale::c().toDateTime(ifModifiedStr, QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
219 ret.setTimeSpec(Qt::UTC);
227 auto it = m_data.constFind(QStringLiteral(
"IF_MODIFIED_SINCE"));
228 if (it != m_data.constEnd()) {
230 QLocale::c().toString(
lastModified.toUTC(), u
"ddd, dd MMM yyyy hh:mm:ss 'GMT");
237 auto it = m_data.constFind(QStringLiteral(
"IF_MATCH"));
238 if (it != m_data.constEnd()) {
239 const auto clientETag = QStringView(it.value());
240 return clientETag.mid(1, clientETag.size() - 2) == etag ||
241 clientETag.mid(3, clientETag.size() - 4) == etag;
248 auto it = m_data.constFind(QStringLiteral(
"IF_NONE_MATCH"));
249 if (it != m_data.constEnd()) {
250 const auto clientETag = QStringView(it.value());
251 return clientETag.mid(1, clientETag.size() - 2) == etag ||
252 clientETag.mid(3, clientETag.size() - 4) == etag;
259 m_data.replace(QStringLiteral(
"ETAG"), QLatin1Char(
'"') + etag + QLatin1Char(
'"'));
264 return m_data.value(QStringLiteral(
"LAST_MODIFIED"));
269 m_data.replace(QStringLiteral(
"LAST_MODIFIED"), value);
276 auto dt = QLocale::c().toString(
lastModified.toUTC(), u
"ddd, dd MMM yyyy hh:mm:ss 'GMT");
283 return m_data.value(QStringLiteral(
"SERVER"));
288 m_data.replace(QStringLiteral(
"SERVER"), value);
293 return m_data.value(QStringLiteral(
"CONNECTION"));
298 return m_data.value(QStringLiteral(
"HOST"));
303 return m_data.value(QStringLiteral(
"USER_AGENT"));
308 return m_data.value(QStringLiteral(
"REFERER"));
313 int fragmentPos = uri.indexOf(QLatin1Char(
'#'));
314 if (fragmentPos != -1) {
316 m_data.replace(QStringLiteral(
"REFERER"), uri.mid(0, fragmentPos));
318 m_data.replace(QStringLiteral(
"REFERER"), uri);
324 m_data.replace(QStringLiteral(
"WWW_AUTHENTICATE"), value);
329 m_data.replace(QStringLiteral(
"PROXY_AUTHENTICATE"), value);
334 return m_data.value(QStringLiteral(
"AUTHORIZATION"));
340 auto it = m_data.constFind(QStringLiteral(
"AUTHORIZATION"));
341 if (it != m_data.constEnd() && it.value().startsWith(u
"Bearer ")) {
342 ret = it.value().mid(7);
349 return QString::fromLatin1(decodeBasicAuth(
authorization()));
360 if (username.contains(QLatin1Char(
':'))) {
361 qCWarning(CUTELYST_CORE) <<
"Headers::Basic authorization user name can't contain ':'";
365 const QString result = username + QLatin1Char(
':') + password;
366 ret = QLatin1String(
"Basic ") + QString::fromLatin1(result.toLatin1().toBase64());
367 m_data.replace(QStringLiteral(
"AUTHORIZATION"), ret);
373 return m_data.value(QStringLiteral(
"PROXY_AUTHORIZATION"));
388 return m_data.value(normalizeHeaderKey(field));
393 return m_data.value(normalizeHeaderKey(field), defaultValue);
398 m_data.replace(normalizeHeaderKey(field), value);
403 setHeader(field, values.join(QLatin1String(
", ")));
408 m_data.insert(normalizeHeaderKey(field), value);
413 m_data.insert(normalizeHeaderKey(field), values.join(QLatin1String(
", ")));
418 m_data.remove(normalizeHeaderKey(field));
423 return m_data.contains(normalizeHeaderKey(field));
428 return m_data.value(normalizeHeaderKey(key));
431QString normalizeHeaderKey(
const QString &field)
435 while (i < key.size()) {
439 key[i] = c.toUpper();
441 }
else if (c == u
'-') {
449QByteArray decodeBasicAuth(
const QString &auth)
452 if (!auth.isEmpty() && auth.startsWith(u
"Basic ")) {
453 int pos = auth.lastIndexOf(u
' ');
455 ret = QByteArray::fromBase64(auth.mid(pos).toLatin1());
464 const QByteArray authorization = decodeBasicAuth(auth);
465 if (!authorization.isEmpty()) {
466 int pos = authorization.indexOf(
':');
468 ret.user = QString::fromLatin1(authorization);
470 ret.user = QString::fromLatin1(authorization.left(pos));
471 ret.password = QString::fromLatin1(authorization.mid(pos + 1));
477QDebug operator<<(QDebug debug,
const Headers &headers)
479 const QMultiHash<QString, QString> data = headers.
data();
480 const bool oldSetting = debug.autoInsertSpaces();
481 debug.nospace() <<
"Headers[";
482 for (
auto it = data.constBegin(); it != data.constEnd(); ++it) {
486 debug.setAutoInsertSpaces(oldSetting);
487 return debug.maybeSpace();
static QString camelCaseHeader(const QString &headerKey)
The Cutelyst namespace holds all public Cutelyst API.