24 #include <QStringList> 28 inline QString normalizeHeaderKey(
const QString &field);
29 inline QByteArray decodeBasicAuth(
const QString &auth);
30 inline std::pair<QString, QString> decodeBasicAuthPair(
const QString &auth);
39 return m_data.value(QStringLiteral(
"CONTENT_DISPOSITION"));
44 m_data.insert(QStringLiteral(
"CONTENT_DISPOSITION"), contentDisposition);
49 if (filename.isEmpty()) {
58 return m_data.value(QStringLiteral(
"CONTENT_ENCODING"));
63 m_data.insert(QStringLiteral(
"CONTENT_ENCODING"), encoding);
69 const auto it = m_data.constFind(QStringLiteral(
"CONTENT_TYPE"));
70 if (it != m_data.constEnd()) {
71 const QString &ct = it.value();
72 ret = ct.mid(0, ct.indexOf(QLatin1Char(
';'))).toLower();
79 m_data.insert(QStringLiteral(
"CONTENT_TYPE"), contentType);
85 const auto it = m_data.constFind(QStringLiteral(
"CONTENT_TYPE"));
86 if (it != m_data.constEnd()) {
88 int pos = contentType.indexOf(QLatin1String(
"charset="), 0, Qt::CaseInsensitive);
90 int endPos = contentType.indexOf(QLatin1Char(
';'), pos);
91 ret = contentType.mid(pos + 8, endPos).trimmed().toUpper();
100 const auto it = m_data.constFind(QStringLiteral(
"CONTENT_TYPE"));
101 if (it == m_data.constEnd() || (it.value().isEmpty() && !charset.isEmpty())) {
102 m_data.insert(QStringLiteral(
"CONTENT_TYPE"), QLatin1String(
"charset=") + charset);
107 int pos = contentType.indexOf(QLatin1String(
"charset="), 0, Qt::CaseInsensitive);
109 int endPos = contentType.indexOf(QLatin1Char(
';'), pos);
111 if (charset.isEmpty()) {
112 int lastPos = contentType.lastIndexOf(QLatin1Char(
';'), pos);
114 m_data.remove(QStringLiteral(
"CONTENT_TYPE"));
117 contentType.remove(lastPos, contentType.length() - lastPos);
120 contentType.replace(pos + 8, contentType.length() - pos + 8, charset);
123 contentType.replace(pos + 8, endPos, charset);
125 }
else if (!charset.isEmpty()) {
126 contentType.append(QLatin1String(
"; charset=") + charset);
128 m_data.insert(QStringLiteral(
"CONTENT_TYPE"), contentType);
133 return m_data.value(QStringLiteral(
"CONTENT_TYPE")).startsWith(QLatin1String(
"text/"));
139 return ct == QLatin1String(
"text/html") ||
140 ct == QLatin1String(
"application/xhtml+xml") ||
141 ct == QLatin1String(
"application/vnd.wap.xhtml+xml");
147 return ct == QLatin1String(
"application/xhtml+xml") ||
148 ct == QLatin1String(
"application/vnd.wap.xhtml+xml");
154 return ct == QLatin1String(
"text/xml") ||
155 ct == QLatin1String(
"application/xml") ||
156 ct.endsWith(QLatin1String(
"xml"));
161 auto it = m_data.constFind(QStringLiteral(
"CONTENT_LENGTH"));
162 if (it != m_data.constEnd()) {
163 return it.value().toLongLong();
170 m_data.insert(QStringLiteral(
"CONTENT_LENGTH"), QString::number(value));
177 const QString dt = QLocale::c().toString(date.toUTC(),
178 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss 'GMT"));
179 m_data.insert(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(QLatin1String(
" 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 header(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(QLatin1String(
" 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 return m_data.value(QStringLiteral(
"LAST_MODIFIED"));
235 m_data.insert(QStringLiteral(
"LAST_MODIFIED"), value);
242 const auto dt = QLocale::c().toString(lastModified.toUTC(),
243 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss 'GMT"));
250 return m_data.value(QStringLiteral(
"SERVER"));
255 m_data.insert(QStringLiteral(
"SERVER"), value);
260 return m_data.value(QStringLiteral(
"CONNECTION"));
265 return m_data.value(QStringLiteral(
"HOST"));
270 return m_data.value(QStringLiteral(
"USER_AGENT"));
275 return m_data.value(QStringLiteral(
"REFERER"));
280 int fragmentPos = uri.indexOf(QLatin1Char(
'#'));
281 if (fragmentPos != -1) {
283 m_data.insert(QStringLiteral(
"REFERER"), uri.mid(0, fragmentPos));
285 m_data.insert(QStringLiteral(
"REFERER"), uri);
291 m_data.insert(QStringLiteral(
"WWW_AUTHENTICATE"), value);
296 m_data.insert(QStringLiteral(
"PROXY_AUTHENTICATE"), value);
301 return m_data.value(QStringLiteral(
"AUTHORIZATION"));
306 return QString::fromLatin1(decodeBasicAuth(
authorization()));
317 if (username.contains(QLatin1Char(
':'))) {
318 qCWarning(CUTELYST_CORE) <<
"Headers::Basic authorization user name can't contain ':'";
322 const QString result = username + QLatin1Char(
':') + password;
323 ret = QStringLiteral(
"Basic ") + QString::fromLatin1(result.toLatin1().toBase64());
324 m_data.insert(QStringLiteral(
"AUTHORIZATION"), ret);
330 return m_data.value(QStringLiteral(
"PROXY_AUTHORIZATION"));
345 return m_data.value(normalizeHeaderKey(field));
350 return m_data.value(normalizeHeaderKey(field), defaultValue);
355 m_data.insert(normalizeHeaderKey(field), value);
360 setHeader(field, values.join(QStringLiteral(
", ")));
365 m_data.insertMulti(normalizeHeaderKey(field), value);
370 m_data.insertMulti(normalizeHeaderKey(field), values.join(QStringLiteral(
", ")));
375 m_data.remove(normalizeHeaderKey(field));
380 return m_data.contains(normalizeHeaderKey(field));
393 QString normalizeHeaderKey(
const QString &field)
397 while (i < key.size()) {
403 }
else if (c == QLatin1Char(
'-')) {
404 c = QLatin1Char(
'_');
411 QByteArray decodeBasicAuth(
const QString &auth)
414 if (!auth.isEmpty() && auth.startsWith(QLatin1String(
"Basic "))) {
415 int pos = auth.lastIndexOf(QLatin1Char(
' '));
417 ret = QByteArray::fromBase64(auth.mid(pos).toLatin1());
423 std::pair<QString, QString> decodeBasicAuthPair(
const QString &auth)
425 std::pair<QString, QString> ret;
427 if (!authorization.isEmpty()) {
428 int pos = authorization.indexOf(
':');
430 ret.first = QString::fromLatin1(authorization);
432 ret = { QString::fromLatin1(authorization.left(pos)),
433 QString::fromLatin1(authorization.mid(pos + 1)) };
439 QDebug operator<<(QDebug debug,
const Headers &headers)
441 const QHash<QString, QString>
data = headers.
data();
442 const bool oldSetting = debug.autoInsertSpaces();
443 debug.nospace() <<
"Headers(";
444 for (
auto it = data.constBegin();
445 it != data.constEnd(); ++it) {
449 debug.setAutoInsertSpaces(oldSetting);
450 return debug.maybeSpace();
static QString camelCaseHeader(const QString &headerKey)
The Cutelyst namespace holds all public Cutelyst API.