13using namespace Qt::Literals::StringLiterals;
15inline QByteArray decodeBasicAuth(
const QByteArray &auth);
19QVector<Headers::HeaderKeyValue>::const_iterator
20 findHeaderConst(
const QVector<Headers::HeaderKeyValue> &headers, QByteArrayView key)
noexcept
23 return key.compare(entry.key, Qt::CaseInsensitive) == 0;
25 return std::find_if(headers.cbegin(), headers.cend(), matchKey);
30 : m_data(other.m_data)
36 return header(
"Content-Disposition");
51 if (filename.isEmpty()) {
60 return header(
"Content-Encoding");
65 setHeader(
"Content-Encoding"_ba, encoding);
70 QByteArray ret =
header(
"Content-Type");
72 ret = ret.mid(0, ret.indexOf(
';')).toLower();
90 ret =
contentType.mid(pos + 8, endPos).trimmed().toUpper();
99 auto result = findHeaderConst(m_data,
"Content-Type");
100 if (result == m_data.end() || (result->value.isEmpty() && !charset.isEmpty())) {
110 if (charset.isEmpty()) {
124 }
else if (!charset.isEmpty()) {
132 return header(
"Content-Type").startsWith(
"text/");
138 return ct.compare(
"text/html") == 0 || ct.compare(
"application/xhtml+xml") == 0 ||
139 ct.compare(
"application/vnd.wap.xhtml+xml") == 0;
145 return ct.compare(
"application/xhtml+xml") == 0 ||
146 ct.compare(
"application/vnd.wap.xhtml+xml") == 0;
152 return ct.compare(
"text/xml") == 0 || ct.compare(
"application/xml") == 0 || ct.endsWith(
"xml");
157 auto value =
header(
"Content-Type");
158 if (!value.isEmpty()) {
159 return value.compare(
"application/json") == 0;
166 auto value =
header(
"Content-Length");
167 if (!value.isEmpty()) {
168 return value.toLongLong();
175 setHeader(
"Content-Length"_ba, QByteArray::number(value));
183 QLocale::c().toString(
date.toUTC(), u
"ddd, dd MMM yyyy hh:mm:ss 'GMT").toLatin1();
191 auto value =
header(
"Date");
192 if (!value.isEmpty()) {
193 if (value.endsWith(
" GMT")) {
194 ret = QLocale::c().toDateTime(QString::fromLatin1(value.left(value.size() - 4)),
195 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
197 ret = QLocale::c().toDateTime(QString::fromLatin1(value),
198 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
200 ret.setTimeSpec(Qt::UTC);
208 return header(
"If-Modified-Since");
214 auto value =
header(
"If-Modified-Since");
215 if (!value.isEmpty()) {
216 if (value.endsWith(
" GMT")) {
217 ret = QLocale::c().toDateTime(QString::fromLatin1(value.left(value.size() - 4)),
218 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
220 ret = QLocale::c().toDateTime(QString::fromLatin1(value),
221 QStringLiteral(
"ddd, dd MMM yyyy hh:mm:ss"));
223 ret.setTimeSpec(Qt::UTC);
231 auto value =
header(
"If-Modified-Since");
232 if (!value.isEmpty()) {
233 return value != QLocale::c()
234 .toString(
lastModified.toUTC(), u
"ddd, dd MMM yyyy hh:mm:ss 'GMT")
242 auto value =
header(
"If-Match");
243 if (!value.isEmpty()) {
244 const auto clientETag = QByteArrayView(value);
245 return clientETag.sliced(1, clientETag.size() - 2) == etag ||
246 clientETag.sliced(3, clientETag.size() - 4) == etag;
253 auto value =
header(
"If-None-Match");
254 if (!value.isEmpty()) {
255 const auto clientETag = QByteArrayView(value);
256 return clientETag.sliced(1, clientETag.size() - 2) == etag ||
257 clientETag.sliced(3, clientETag.size() - 4) == etag;
269 return header(
"Last-Modified");
281 auto dt = QLocale::c().toString(
lastModified.toUTC(), u
"ddd, dd MMM yyyy hh:mm:ss 'GMT");
298 return header(
"Connection");
308 return header(
"User-Agent");
318 int fragmentPos = uri.indexOf(
'#');
319 if (fragmentPos != -1) {
321 setHeader(
"Referer"_ba, uri.mid(0, fragmentPos));
334 setHeader(
"Proxy-Authenticate"_ba, value);
339 return header(
"Authorization");
346 int pos = auth.indexOf(
"Bearer ");
349 ret = auth.mid(pos, auth.indexOf(
',', pos) - pos);
367 if (username.contains(u
':')) {
368 qCWarning(CUTELYST_CORE) <<
"Headers::Basic authorization user name can't contain ':'";
372 const QString result = username + u
':' + password;
373 ret =
"Basic " + result.toLatin1().toBase64();
380 return header(
"Proxy-Authorization");
395 if (
auto result = findHeaderConst(m_data, key); result != m_data.end()) {
396 return result->value;
403 return QString::fromLatin1(
header(key));
406QByteArray
Headers::header(QByteArrayView key,
const QByteArray &defaultValue)
const noexcept
408 if (
auto result = findHeaderConst(m_data, key); result != m_data.end()) {
409 return result->value;
416 return QString::fromLatin1(
header(key, defaultValue));
422 for (
auto result = findHeaderConst(m_data, key); result != m_data.end(); ++result) {
423 ret.append(result->value);
431 for (
auto result = findHeaderConst(m_data, key); result != m_data.end(); ++result) {
432 ret.append(QString::fromLatin1(result->value));
440 return key.compare(entry.key, Qt::CaseInsensitive) == 0;
443 if (
auto result = std::find_if(m_data.begin(), m_data.end(), matchKey);
444 result != m_data.end()) {
445 result->value = value;
448 QVector<HeaderKeyValue>::ConstIterator begin =
449 std::remove_if(result, m_data.end(), matchKey);
450 m_data.erase(begin, m_data.cend());
463 m_data.push_back({key, value});
468 m_data.push_back({key, values.join(
", ")});
474 [key](
HeaderKeyValue entry) {
return key.compare(entry.key, Qt::CaseInsensitive) == 0; });
479 auto result = findHeaderConst(m_data, key);
480 return result != m_data.end();
483QByteArrayList Headers::keys()
const
487 for (
const auto &
header : m_data) {
489 for (
const auto &key : ret) {
490 if (
header.key.compare(key, Qt::CaseInsensitive) == 0) {
511 const auto otherData = other.data();
512 if (m_data.size() != otherData.size()) {
516 for (
const auto &myValue : m_data) {
517 if (!other.data().contains(myValue)) {
525QByteArray decodeBasicAuth(
const QByteArray &auth)
528 int pos = auth.indexOf(
"Basic ");
531 ret = auth.mid(pos, auth.indexOf(
',', pos) - pos);
532 ret = QByteArray::fromBase64(ret);
540 const QByteArray authorization = decodeBasicAuth(auth);
541 if (!authorization.isEmpty()) {
542 int pos = authorization.indexOf(
':');
544 ret.user = QString::fromLatin1(authorization);
546 ret.user = QString::fromLatin1(authorization.left(pos));
547 ret.password = QString::fromLatin1(authorization.mid(pos + 1));
553QDebug operator<<(QDebug debug,
const Headers &headers)
555 const auto data = headers.
data();
556 const bool oldSetting = debug.autoInsertSpaces();
557 debug.nospace() <<
"Headers[";
558 for (
auto it = data.begin(); it != data.end(); ++it) {
559 debug <<
'(' << it->key +
'=' + it->value <<
')';
562 debug.setAutoInsertSpaces(oldSetting);
563 return debug.maybeSpace();
The Cutelyst namespace holds all public Cutelyst API.