14inline QByteArray decodeBasicAuth(
const QByteArray &auth);
18QVector<Headers::HeaderKeyValue>::const_iterator
19 findHeaderConst(
const QVector<Headers::HeaderKeyValue> &headers, QByteArrayView key)
noexcept
22 return key.compare(entry.key, Qt::CaseInsensitive) == 0;
24 return std::find_if(headers.cbegin(), headers.cend(), matchKey);
29 : m_data(other.m_data)
35 return header(
"Content-Disposition");
50 if (filename.isEmpty()) {
59 return header(
"Content-Encoding");
64 setHeader(
"Content-Encoding"_qba, encoding);
69 QByteArray ret =
header(
"Content-Type");
71 ret = ret.mid(0, ret.indexOf(
';')).toLower();
89 ret =
contentType.mid(pos + 8, endPos).trimmed().toUpper();
98 auto result = findHeaderConst(m_data,
"Content-Type");
99 if (result == m_data.end() || (result->value.isEmpty() && !charset.isEmpty())) {
109 if (charset.isEmpty()) {
123 }
else if (!charset.isEmpty()) {
131 return header(
"Content-Type").startsWith(
"text/");
137 return ct.compare(
"text/html") == 0 || ct.compare(
"application/xhtml+xml") == 0 ||
138 ct.compare(
"application/vnd.wap.xhtml+xml") == 0;
144 return ct.compare(
"application/xhtml+xml") == 0 ||
145 ct.compare(
"application/vnd.wap.xhtml+xml") == 0;
151 return ct.compare(
"text/xml") == 0 || ct.compare(
"application/xml") == 0 || ct.endsWith(
"xml");
156 auto value =
header(
"Content-Type");
157 if (!value.isEmpty()) {
158 return value.compare(
"application/json") == 0;
165 auto value =
header(
"Content-Length");
166 if (!value.isEmpty()) {
167 return value.toLongLong();
174 setHeader(
"Content-Length"_qba, QByteArray::number(value));
182 QLocale::c().toString(
date.toUTC(), u
"ddd, dd MMM yyyy hh:mm:ss 'GMT").toLatin1();
190 auto value =
header(
"Date");
191 if (!value.isEmpty()) {
192 if (value.endsWith(
" GMT")) {
193 ret = QLocale::c().toDateTime(QString::fromLatin1(value.left(value.size() - 4)),
194 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
196 ret = QLocale::c().toDateTime(QString::fromLatin1(value),
197 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
199 ret.setTimeSpec(Qt::UTC);
207 return header(
"If-Modified-Since");
213 auto value =
header(
"If-Modified-Since");
214 if (!value.isEmpty()) {
215 if (value.endsWith(
" GMT")) {
216 ret = QLocale::c().toDateTime(QString::fromLatin1(value.left(value.size() - 4)),
217 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
219 ret = QLocale::c().toDateTime(QString::fromLatin1(value),
220 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
222 ret.setTimeSpec(Qt::UTC);
230 auto value =
header(
"If-Modified-Since");
231 if (!value.isEmpty()) {
232 return value != QLocale::c()
233 .toString(
lastModified.toUTC(), u
"ddd, dd MMM yyyy hh:mm:ss 'GMT")
241 auto value =
header(
"If-Match");
242 if (!value.isEmpty()) {
243 const auto clientETag = QByteArrayView(value);
244 return clientETag.sliced(1, clientETag.size() - 2) == etag ||
245 clientETag.sliced(3, clientETag.size() - 4) == etag;
252 auto value =
header(
"If-None-Match");
253 if (!value.isEmpty()) {
254 const auto clientETag = QByteArrayView(value);
255 return clientETag.sliced(1, clientETag.size() - 2) == etag ||
256 clientETag.sliced(3, clientETag.size() - 4) == etag;
268 return header(
"Last-Modified");
280 auto dt = QLocale::c().toString(
lastModified.toUTC(), u
"ddd, dd MMM yyyy hh:mm:ss 'GMT");
297 return header(
"Connection");
307 return header(
"User-Agent");
317 int fragmentPos = uri.indexOf(
'#');
318 if (fragmentPos != -1) {
320 setHeader(
"Referer"_qba, uri.mid(0, fragmentPos));
328 setHeader(
"Www-Authenticate"_qba, value);
333 setHeader(
"Proxy-Authenticate"_qba, value);
338 return header(
"Authorization");
345 int pos = auth.indexOf(
"Bearer ");
348 ret = auth.mid(pos, auth.indexOf(
',', pos) - pos);
366 if (username.contains(u
':')) {
367 qCWarning(CUTELYST_CORE) <<
"Headers::Basic authorization user name can't contain ':'";
371 const QString result = username + u
':' + password;
372 ret =
"Basic " + result.toLatin1().toBase64();
379 return header(
"Proxy-Authorization");
394 if (
auto result = findHeaderConst(m_data, key); result != m_data.end()) {
395 return result->value;
402 return QString::fromLatin1(
header(key));
405QByteArray
Headers::header(QByteArrayView key,
const QByteArray &defaultValue)
const noexcept
407 if (
auto result = findHeaderConst(m_data, key); result != m_data.end()) {
408 return result->value;
415 return QString::fromLatin1(
header(key, defaultValue));
421 for (
auto result = findHeaderConst(m_data, key); result != m_data.end(); ++result) {
422 ret.append(result->value);
430 for (
auto result = findHeaderConst(m_data, key); result != m_data.end(); ++result) {
431 ret.append(QString::fromLatin1(result->value));
439 return key.compare(entry.key, Qt::CaseInsensitive) == 0;
442 if (
auto result = std::find_if(m_data.begin(), m_data.end(), matchKey);
443 result != m_data.end()) {
444 result->value = value;
447 QVector<HeaderKeyValue>::ConstIterator begin =
448 std::remove_if(result, m_data.end(), matchKey);
449 m_data.erase(begin, m_data.cend());
462 m_data.push_back({key, value});
467 m_data.push_back({key, values.join(
", ")});
473 [key](
HeaderKeyValue entry) {
return key.compare(entry.key, Qt::CaseInsensitive) == 0; });
478 auto result = findHeaderConst(m_data, key);
479 return result != m_data.end();
482QByteArrayList Headers::keys()
const
486 for (
const auto &
header : m_data) {
488 for (
const auto &key : ret) {
489 if (
header.key.compare(key, Qt::CaseInsensitive) == 0) {
510 const auto otherData = other.data();
511 if (m_data.size() != otherData.size()) {
515 for (
const auto &myValue : m_data) {
516 if (!other.data().contains(myValue)) {
524QByteArray decodeBasicAuth(
const QByteArray &auth)
527 int pos = auth.indexOf(
"Basic ");
530 ret = auth.mid(pos, auth.indexOf(
',', pos) - pos);
531 ret = QByteArray::fromBase64(ret);
539 const QByteArray authorization = decodeBasicAuth(auth);
540 if (!authorization.isEmpty()) {
541 int pos = authorization.indexOf(
':');
543 ret.user = QString::fromLatin1(authorization);
545 ret.user = QString::fromLatin1(authorization.left(pos));
546 ret.password = QString::fromLatin1(authorization.mid(pos + 1));
552QDebug operator<<(QDebug debug,
const Headers &headers)
554 const auto data = headers.
data();
555 const bool oldSetting = debug.autoInsertSpaces();
556 debug.nospace() <<
"Headers[";
557 for (
auto it = data.begin(); it != data.end(); ++it) {
558 debug <<
'(' << it->key +
'=' + it->value <<
')';
561 debug.setAutoInsertSpaces(oldSetting);
562 return debug.maybeSpace();
The Cutelyst namespace holds all public Cutelyst API.