Commit bd3bc77e authored by Daniel Vrátil's avatar Daniel Vrátil 🤖

Optimize parsing headers

Summary:
Reduce the amount of allocations by not resizing the 'head' bytearray
after extracting each header.

Reviewers: vkrause

Reviewed By: vkrause

Subscribers: mlaurent, #kde_pim

Tags: #kde_pim

Differential Revision: https://phabricator.kde.org/D8245
parent f9d80155
......@@ -2023,39 +2023,52 @@ bool parseDateTime(const char *&scursor, const char *const send,
return true;
}
Headers::Base *extractFirstHeader(QByteArray &head)
namespace {
Headers::Base *extractHeader(const QByteArray &head, const int headerStart, int &endOfFieldBody)
{
Headers::Base *header = {};
int startOfFieldBody = head.indexOf(':', headerStart);
if (startOfFieldBody < 0) {
return nullptr;
}
const QByteArray rawType = QByteArray::fromRawData(head.constData() + headerStart, startOfFieldBody - headerStart);
startOfFieldBody++; //skip the ':'
if (startOfFieldBody < head.size() - 1 && head[startOfFieldBody] == ' ') { // skip the space after the ':', if there's any
startOfFieldBody++;
}
bool folded = false;
Headers::Base *header = nullptr;
endOfFieldBody = findHeaderLineEnd(head, startOfFieldBody, &folded);
// rawFieldBody references actual data from 'head'
QByteArray rawFieldBody = QByteArray::fromRawData(head.constData() + startOfFieldBody, endOfFieldBody - startOfFieldBody);
if (folded) {
rawFieldBody = unfoldHeader(rawFieldBody);
}
int startOfFieldBody = head.indexOf(':');
// We might get an invalid mail without a field name, don't crash on that.
if (!rawType.isEmpty()) {
header = HeaderFactory::createHeader(rawType);
}
if (!header) {
//qWarning() << "Returning Generic header of type" << rawType;
header = new Headers::Generic(rawType.constData(), rawType.size());
}
header->from7BitString(rawFieldBody);
if (startOfFieldBody > -1) { //there is another header
// Split the original data
head[startOfFieldBody] = '\0';
// rawType references the actual data from 'head'
QByteArray rawType = QByteArray::fromRawData(head.constData(), startOfFieldBody);
return header;
}
startOfFieldBody++; //skip the ':'
if (head[startOfFieldBody] == ' ') { // skip the space after the ':', if there
startOfFieldBody++;
}
int endOfFieldBody = findHeaderLineEnd(head, startOfFieldBody, &folded);
// rawFieldBody references actual data from 'heaed'
QByteArray rawFieldBody = QByteArray::fromRawData(head.constData() + startOfFieldBody, endOfFieldBody - startOfFieldBody);
if (folded) {
rawFieldBody = unfoldHeader(rawFieldBody);
}
// We might get an invalid mail without a field name, don't crash on that.
if (!rawType.isEmpty()) {
header = HeaderFactory::createHeader(rawType);
}
if (!header) {
//qWarning() << "Returning Generic header of type" << rawType;
header = new Headers::Generic(rawType.constData());
}
header->from7BitString(rawFieldBody);
}
Headers::Base *extractFirstHeader(QByteArray &head)
{
int endOfFieldBody = 0;
auto header = extractHeader(head, 0, endOfFieldBody);
if (header) {
head.remove(0, endOfFieldBody + 1);
} else {
head.clear();
......@@ -2090,11 +2103,17 @@ void extractHeaderAndBody(const QByteArray &content, QByteArray &header, QByteAr
QVector<Headers::Base*> parseHeaders(const QByteArray &head)
{
QVector<Headers::Base*> ret;
Headers::Base *h;
QByteArray copy = head;
while ((h = extractFirstHeader(copy))) {
ret << h;
int cursor = 0;
while (cursor < head.size()) {
const int headerStart = cursor;
int endOfFieldBody;
if (auto header = extractHeader(head, headerStart, endOfFieldBody)) {
ret << header;
cursor = endOfFieldBody + 1;
} else {
break;
}
}
return ret;
......
......@@ -38,7 +38,7 @@ using namespace KMime;
using namespace KMime::Headers;
#define mk_header(hdr) \
if (qstricmp(type.constData(), hdr ::staticType()) == 0) \
if (qstrnicmp(type.constData(), hdr ::staticType(), type.size()) == 0) \
return new hdr
Headers::Base *HeaderFactory::createHeader(const QByteArray &type)
......
......@@ -1167,9 +1167,9 @@ Generic::Generic() : Generics::Unstructured(new GenericPrivate)
{
}
Generic::Generic(const char *t) : Generics::Unstructured(new GenericPrivate)
Generic::Generic(const char *t, int len) : Generics::Unstructured(new GenericPrivate)
{
setType(t);
setType(t, len);
}
Generic::~Generic()
......@@ -1197,15 +1197,16 @@ const char *Generic::type() const
return d_func()->type;
}
void Generic::setType(const char *type)
void Generic::setType(const char *type, int len)
{
Q_D(Generic);
if (d->type) {
delete[] d->type;
}
if (type) {
d->type = new char[strlen(type) + 1];
strcpy(d->type, type);
const int l = (len < 0 ? strlen(type) : len) + 1;
d->type = new char[l];
qstrncpy(d->type, type, l);
} else {
d->type = nullptr;
}
......
......@@ -1207,7 +1207,7 @@ class KMIME_EXPORT Generic : public Generics::Unstructured
{
public:
Generic();
Generic(const char *t);
Generic(const char *t, int len = -1);
~Generic();
void clear() override;
......@@ -1216,7 +1216,7 @@ public:
const char *type() const override;
void setType(const char *type);
void setType(const char *type, int len = -1);
private:
Q_DECLARE_PRIVATE(Generic)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment