11 #include <QStringList>
15 inline QString normalizeHeaderKey(
const QString &field);
16 inline QByteArray decodeBasicAuth(
const QString &auth);
25 return m_data.value(QStringLiteral(
"CONTENT_DISPOSITION"));
30 m_data.replace(QStringLiteral(
"CACHE_CONTROL"), value);
40 if (filename.isEmpty()) {
49 return m_data.value(QStringLiteral(
"CONTENT_ENCODING"));
54 m_data.replace(QStringLiteral(
"CONTENT_ENCODING"), encoding);
60 const auto it = m_data.constFind(QStringLiteral(
"CONTENT_TYPE"));
61 if (it != m_data.constEnd()) {
62 const QString &ct = it.value();
63 ret = ct.mid(0, ct.indexOf(QLatin1Char(
';'))).toLower();
70 m_data.replace(QStringLiteral(
"CONTENT_TYPE"),
contentType);
76 const auto it = m_data.constFind(QStringLiteral(
"CONTENT_TYPE"));
77 if (it != m_data.constEnd()) {
79 int pos =
contentType.indexOf(u
"charset=", 0, Qt::CaseInsensitive);
82 ret =
contentType.mid(pos + 8, endPos).trimmed().toUpper();
91 const auto it = m_data.constFind(QStringLiteral(
"CONTENT_TYPE"));
92 if (it == m_data.constEnd() || (it.value().isEmpty() && !charset.isEmpty())) {
93 m_data.replace(QStringLiteral(
"CONTENT_TYPE"), QLatin1String(
"charset=") + charset);
98 int pos =
contentType.indexOf(QLatin1String(
"charset="), 0, Qt::CaseInsensitive);
100 int endPos =
contentType.indexOf(QLatin1Char(
';'), pos);
102 if (charset.isEmpty()) {
103 int lastPos =
contentType.lastIndexOf(QLatin1Char(
';'), pos);
105 m_data.remove(QStringLiteral(
"CONTENT_TYPE"));
116 }
else if (!charset.isEmpty()) {
117 contentType.append(QLatin1String(
"; charset=") + charset);
119 m_data.replace(QStringLiteral(
"CONTENT_TYPE"),
contentType);
124 return m_data.value(QStringLiteral(
"CONTENT_TYPE")).startsWith(u
"text/");
130 return ct.compare(u
"text/html") == 0 ||
131 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 ||
146 ct.compare(u
"application/xml") == 0||
152 const auto it = m_data.constFind(QStringLiteral(
"CONTENT_TYPE"));
153 if (it != m_data.constEnd()) {
154 return it.value().compare(u
"application/json") == 0;
161 auto it = m_data.constFind(QStringLiteral(
"CONTENT_LENGTH"));
162 if (it != m_data.constEnd()) {
163 return it.value().toLongLong();
170 m_data.replace(QStringLiteral(
"CONTENT_LENGTH"), QString::number(value));
177 QString dt = QLocale::c().toString(
date.toUTC(),
178 u
"ddd, dd MMM yyyy hh:mm:ss 'GMT");
179 m_data.replace(QStringLiteral(
"DATE"), dt);
186 auto it = m_data.constFind(QStringLiteral(
"DATE"));
187 if (it != m_data.constEnd()) {
188 const QString &
date = it.value();
190 if (
date.endsWith(u
" GMT")) {
191 ret = QLocale::c().toDateTime(
date.left(
date.size() - 4),
192 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
194 ret = QLocale::c().toDateTime(
date,
195 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
197 ret.setTimeSpec(Qt::UTC);
205 return m_data.value(QStringLiteral(
"IF_MODIFIED_SINCE"));
211 auto it = m_data.constFind(QStringLiteral(
"IF_MODIFIED_SINCE"));
212 if (it != m_data.constEnd()) {
213 const QString &ifModifiedStr = it.value();
215 if (ifModifiedStr.endsWith(u
" GMT")) {
216 ret = QLocale::c().toDateTime(ifModifiedStr.left(ifModifiedStr.size() - 4),
217 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
219 ret = QLocale::c().toDateTime(ifModifiedStr,
220 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
222 ret.setTimeSpec(Qt::UTC);
230 auto it = m_data.constFind(QStringLiteral(
"IF_MODIFIED_SINCE"));
231 if (it != m_data.constEnd()) {
232 return it.value() != QLocale::c().toString(
lastModified.toUTC(),
233 u
"ddd, dd MMM yyyy hh:mm:ss 'GMT");
240 auto it = m_data.constFind(QStringLiteral(
"IF_MATCH"));
241 if (it != m_data.constEnd()) {
242 const auto clientETag = QStringView(it.value());
243 return clientETag.mid(1, clientETag.size() - 2) == etag ||
244 clientETag.mid(3, clientETag.size() - 4) == etag;
251 auto it = m_data.constFind(QStringLiteral(
"IF_NONE_MATCH"));
252 if (it != m_data.constEnd()) {
253 const auto clientETag = QStringView(it.value());
254 return clientETag.mid(1, clientETag.size() - 2) == etag ||
255 clientETag.mid(3, clientETag.size() - 4) == etag;
262 m_data.replace(QStringLiteral(
"ETAG"), QLatin1Char(
'"') + etag + QLatin1Char(
'"'));
267 return m_data.value(QStringLiteral(
"LAST_MODIFIED"));
272 m_data.replace(QStringLiteral(
"LAST_MODIFIED"), value);
280 u
"ddd, dd MMM yyyy hh:mm:ss 'GMT");
287 return m_data.value(QStringLiteral(
"SERVER"));
292 m_data.replace(QStringLiteral(
"SERVER"), value);
297 return m_data.value(QStringLiteral(
"CONNECTION"));
302 return m_data.value(QStringLiteral(
"HOST"));
307 return m_data.value(QStringLiteral(
"USER_AGENT"));
312 return m_data.value(QStringLiteral(
"REFERER"));
317 int fragmentPos = uri.indexOf(QLatin1Char(
'#'));
318 if (fragmentPos != -1) {
320 m_data.replace(QStringLiteral(
"REFERER"), uri.mid(0, fragmentPos));
322 m_data.replace(QStringLiteral(
"REFERER"), uri);
328 m_data.replace(QStringLiteral(
"WWW_AUTHENTICATE"), value);
333 m_data.replace(QStringLiteral(
"PROXY_AUTHENTICATE"), value);
338 return m_data.value(QStringLiteral(
"AUTHORIZATION"));
344 auto it = m_data.constFind(QStringLiteral(
"AUTHORIZATION"));
345 if (it != m_data.constEnd() && it.value().startsWith(u
"Bearer ")) {
346 ret = it.value().mid(7);
353 return QString::fromLatin1(decodeBasicAuth(
authorization()));
364 if (username.contains(QLatin1Char(
':'))) {
365 qCWarning(CUTELYST_CORE) <<
"Headers::Basic authorization user name can't contain ':'";
369 const QString result = username + QLatin1Char(
':') + password;
370 ret = QLatin1String(
"Basic ") + QString::fromLatin1(result.toLatin1().toBase64());
371 m_data.replace(QStringLiteral(
"AUTHORIZATION"), ret);
377 return m_data.value(QStringLiteral(
"PROXY_AUTHORIZATION"));
392 return m_data.value(normalizeHeaderKey(field));
397 return m_data.value(normalizeHeaderKey(field), defaultValue);
402 m_data.replace(normalizeHeaderKey(field), value);
407 setHeader(field, values.join(QLatin1String(
", ")));
412 m_data.insert(normalizeHeaderKey(field), value);
417 m_data.insert(normalizeHeaderKey(field), values.join(QLatin1String(
", ")));
422 m_data.remove(normalizeHeaderKey(field));
427 return m_data.contains(normalizeHeaderKey(field));
432 return m_data.value(normalizeHeaderKey(key));
435 QString normalizeHeaderKey(
const QString &field)
439 while (i < key.size()) {
443 key[i] = c.toUpper();
445 }
else if (c == u
'-') {
453 QByteArray decodeBasicAuth(
const QString &auth)
456 if (!auth.isEmpty() && auth.startsWith(u
"Basic ")) {
457 int pos = auth.lastIndexOf(u
' ');
459 ret = QByteArray::fromBase64(auth.mid(pos).toLatin1());
468 const QByteArray authorization = decodeBasicAuth(auth);
469 if (!authorization.isEmpty()) {
470 int pos = authorization.indexOf(
':');
472 ret.user = QString::fromLatin1(authorization);
474 ret.user = QString::fromLatin1(authorization.left(pos));
475 ret.password = QString::fromLatin1(authorization.mid(pos + 1));
481 QDebug operator<<(QDebug debug,
const Headers &headers)
483 const QMultiHash<QString, QString> data = headers.
data();
484 const bool oldSetting = debug.autoInsertSpaces();
485 debug.nospace() <<
"Headers[";
486 for (
auto it = data.constBegin();
487 it != data.constEnd(); ++it) {
491 debug.setAutoInsertSpaces(oldSetting);
492 return debug.maybeSpace();
static QString camelCaseHeader(const QString &headerKey)
The Cutelyst namespace holds all public Cutelyst API.