32 static void skipSpace(
const char input[],
int *pos,
int end)
35 while (idx < end && (input[idx] ==
' ' || input[idx] ==
'\t')) {
44 static bool nextLine(
const char input[],
int *pos,
int end)
47 while (idx < end && input[idx] !=
'\r' && input[idx] !=
'\n') {
52 while (idx < end && qMax(rCount, nCount) < 2 && (input[idx] ==
'\r' || input[idx] ==
'\n')) {
53 input[idx] ==
'\r' ? rCount++ : nCount++;
56 if (idx < end && qMax(rCount, nCount) == 2 && qMin(rCount, nCount) == 1) {
60 if ((rCount == 1 && input[idx] ==
'\r') || (nCount == 1 && input[idx] ==
'\n')) {
66 return idx < end && rCount < 2 && nCount < 2;
74 const int last = data.length() - 1;
75 const char *d = data.constData();
77 while ( (i = data.indexOf(
'%', i)) != -1) {
97 return QByteArray(&m_buffer[token.first], token.second - token.first);
104 return QByteArray(&m_buffer[token.first], token.second - token.first);
110 for (
int i = 0; i < m_tokens.count(); i++) {
112 ret.append(QByteArray(&m_buffer[token.first], token.second - token.first));
127 static const HeaderFieldTemplate headerFieldTemplates[] = {
128 {
"accept-ranges",
false},
130 {
"cache-control",
true},
131 {
"connection",
true},
132 {
"content-disposition",
false},
133 {
"content-encoding",
true},
134 {
"content-language",
true},
135 {
"content-length",
false},
136 {
"content-location",
false},
137 {
"content-md5",
false},
138 {
"content-type",
false},
143 {
"keep-alive",
true},
144 {
"last-modified",
false},
149 {
"proxy-authenticate",
false},
151 {
"proxy-connection",
true},
154 {
"set-cookie",
false},
157 {
"transfer-encoding",
true},
160 {
"www-authenticate",
false}
163 for (uint i = 0; i <
sizeof(headerFieldTemplates) /
sizeof(HeaderFieldTemplate); i++) {
164 const HeaderFieldTemplate &ft = headerFieldTemplates[i];
171 char *buf = m_buffer;
173 int startIdx = begin;
174 bool multiValuedEndedWithComma =
false;
175 QByteArray headerKey;
178 if (buf[idx] ==
' ' || buf [idx] ==
'\t') {
180 if (headerKey.isEmpty()) {
184 int backIdx = idx - 1;
185 while (backIdx >= begin && (buf[backIdx] ==
'\r' || buf[backIdx] ==
'\n')) {
186 buf[backIdx--] =
' ';
190 if (
operator[](headerKey).isMultiValued) {
191 if (multiValuedEndedWithComma) {
197 if (
operator[](headerKey).beginEnd.last().first == startIdx) {
199 operator[](headerKey).beginEnd.removeLast();
212 while (idx < (end - 1) && buf[idx] !=
':' && buf[idx] !=
'\r' && buf[idx] !=
'\n') {
213 buf[idx] = tolower(buf[idx]);
216 if (buf[idx] !=
':') {
221 headerKey = QByteArray(&buf[startIdx], idx - startIdx);
222 if (!contains(headerKey)) {
234 if (!
operator[](headerKey).isMultiValued) {
237 while (idx < end && buf[idx] !=
'\r' && buf[idx] !=
'\n') {
240 if (!
operator[](headerKey).beginEnd.isEmpty()) {
242 if (
operator[](headerKey).beginEnd.last().first == startIdx) {
244 operator[](headerKey).beginEnd.removeLast();
254 while (idx < end && buf[idx] !=
'\r' && buf[idx] !=
'\n' && buf[idx] !=
',') {
257 if (idx != startIdx) {
260 multiValuedEndedWithComma = buf[idx] ==
',';
262 while (idx < end && buf[idx] ==
',') {
267 if (buf[idx] >= end || buf[idx] ==
'\r' || buf[idx] ==
'\n') {
279 TokenIterator HeaderTokenizer::iterator(
const char *key)
const
281 QByteArray keyBa = QByteArray::fromRawData(key, strlen(key));
282 if (contains(keyBa)) {
291 while (pos < str.length() && (str[pos] == QLatin1Char(
' ') || str[pos] == QLatin1Char(
'\t'))) {
312 for (
int i = qstrlen(specials) - 1; i >= 0; i--) {
313 if (ch == QLatin1Char(specials[i])) {
342 while (pos < str.length() && (str[pos] != term)) {
344 valid = (valid && !
specialChar(str[pos], specials));
348 if (pos < str.length()) {
357 while (out.endsWith(QLatin1Char(
' ')) || out.endsWith(QLatin1Char(
'\t'))) {
361 if (out.contains(QLatin1Char(
' '))) {
372 const QChar term = QLatin1Char(
';');
377 if (pos < str.length() && str[pos] == QLatin1Char(
'"')) {
384 bool endquote =
false;
387 while (pos < str.length()) {
388 if (str[pos] == QLatin1Char(
'\\') && pos + 1 < str.length()) {
392 }
else if (str[pos] == QLatin1Char(
'"')) {
396 }
else if (!str[pos].isPrint()) {
410 while (pos < str.length() && (str[pos] != term)) {
411 if ((str[pos] != QLatin1Char(
' ')) && (str[pos] != QLatin1Char(
'\t'))) {
418 if (pos < str.length()) {
430 kDebug(7113) <<
"disposition: " << disposition;
432 const QString strDisposition =
extractUntil(disposition, QLatin1Char(
';'), pos, typeSpecials).toLower();
439 if (strDisposition.isEmpty()) {
443 parameters.insert(QLatin1String(
"type"), strDisposition);
445 while (pos < disposition.length()) {
451 kDebug(7113) <<
"parse error in key, abort parsing";
456 if (key.endsWith(QLatin1Char(
'*'))) {
457 val =
extractUntil(disposition, QLatin1Char(
';'), pos, valueSpecials);
464 kDebug(7113) <<
"parse error in value, abort parsing";
470 const int spos = key.indexOf(QLatin1Char(
'*'));
471 if (spos == key.length() - 1) {
473 encparams.insert(key, val);
474 }
else if (spos >= 0) {
475 contparams.insert(key, val);
476 }
else if (parameters.contains(key)) {
477 kDebug(7113) <<
"duplicate key" << key <<
"found, ignoring everything more";
478 parameters.remove(key);
481 parameters.insert(key, val);
486 while (i != contparams.end()) {
488 int spos = key.indexOf(QLatin1Char(
'*'));
489 bool hasencoding =
false;
491 if (key.at(spos + 1) != QLatin1Char(
'0')) {
497 int klen = key.length();
498 if (klen > spos + 2) {
500 if ((klen > spos + 3) || ((klen == spos + 3) && (key.at(spos + 2) != QLatin1Char(
'*')))) {
501 kDebug(7113) <<
"removing invalid key " << key <<
"with val" << i.value() << key.at(spos + 2);
502 i = contparams.erase(i);
514 key.chop(hasencoding ? 2 : 1);
516 while ((partsi = contparams.find(key + QString::number(seqnum))) != contparams.end()) {
517 val += partsi.value();
518 contparams.erase(partsi);
521 i = contparams.erase(i);
525 encparams.insert(key, val);
527 if (parameters.contains(key)) {
528 kDebug(7113) <<
"duplicate key" << key <<
"found, ignoring everything more";
529 parameters.remove(key);
533 parameters.insert(key, val);
541 int spos = val.indexOf(QLatin1Char(
'\''));
545 int npos = val.indexOf(QLatin1Char(
'\''), spos + 1);
550 const QString charset = val.left(spos);
551 const QString lang = val.mid(spos + 1, npos - spos - 1);
552 const QByteArray encodedVal = val.mid(npos + 1).toLatin1();
557 const QByteArray rawval = QByteArray::fromPercentEncoding(encodedVal);
559 if (charset.isEmpty() || (charset == QLatin1String(
"us-ascii"))) {
561 for (
int j = rawval.length() - 1; (j >= 0) && valid; j--) {
562 valid = (rawval.at(j) >= 32);
567 val = QString::fromLatin1(rawval.constData());
569 QTextCodec *codec = QTextCodec::codecForName(charset.toLatin1());
572 val = codec->toUnicode(rawval);
575 parameters.insert(i.key(), val);
585 const QLatin1String fn(
"filename");
586 if (parameters.contains(fn)) {
589 const QString val = QDir::toNativeSeparators(parameters[fn]);
590 int slpos = val.lastIndexOf(QDir::separator());
593 parameters.insert(fn, val.mid(slpos + 1));
static QString extractMaybeQuotedUntil(const QString &str, int &pos)
static bool nextLine(const char input[], int *pos, int end)
static const char valueSpecials[]
static QMap< QString, QString > contentDispositionParserInternal(const QString &disposition)
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
static bool isValidPercentEncoding(const QByteArray &data)
static void skipSpace(const char input[], int *pos, int end)
static const char typeSpecials[]
QByteArray current() const
static void skipLWS(const QString &str, int &pos)
QList< QByteArray > all() const
static QMap< QString, QString > contentDispositionParser(const QString &disposition)
static QString extractUntil(const QString &str, QChar term, int &pos, const char *specials)
read and parse the input until the given terminator
static bool specialChar(const QChar &ch, const char *specials)
static const char attrSpecials[]