From 05a65a3bfa0d87a6df72804e651fdb7e8bb4c7a1 Mon Sep 17 00:00:00 2001 From: bmagistro Date: Sat, 25 Feb 2017 09:17:49 -0500 Subject: [PATCH 1/6] ensure user defined parsingContext is passed forward on calls to parse --- src/vmime/body.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vmime/body.cpp b/src/vmime/body.cpp index 8b334352..e5813375 100644 --- a/src/vmime/body.cpp +++ b/src/vmime/body.cpp @@ -128,7 +128,7 @@ size_t body::findNextBoundaryPosition void body::parseImpl - (const parsingContext& /* ctx */, + (const parsingContext& ctx, shared_ptr parser, const size_t position, const size_t end, size_t* newPosition) { @@ -286,7 +286,7 @@ void body::parseImpl if (partEnd > partStart) { vmime::text text; - text.parse(parser, partStart, partEnd); + text.parse(ctx, parser, partStart, partEnd); m_prologText = text.getWholeBuffer(); } @@ -304,7 +304,7 @@ void body::parseImpl if (partEnd < partStart) std::swap(partStart, partEnd); - part->parse(parser, partStart, partEnd, NULL); + part->parse(ctx, parser, partStart, partEnd, NULL); m_parts.push_back(part); } @@ -325,7 +325,7 @@ void body::parseImpl try { - part->parse(parser, partStart, end); + part->parse(ctx, parser, partStart, end); } catch (std::exception&) { @@ -338,7 +338,7 @@ void body::parseImpl else if (partStart < end) { vmime::text text; - text.parse(parser, partStart, end); + text.parse(ctx, parser, partStart, end); m_epilogText = text.getWholeBuffer(); } From 68fd4e1e42064117acb5f038a395f9da176241af Mon Sep 17 00:00:00 2001 From: bmagistro Date: Mon, 27 Feb 2017 11:04:33 -0500 Subject: [PATCH 2/6] add option to control parser invalid line behavior --- src/vmime/headerField.cpp | 188 +++++++++++++++++++---------------- src/vmime/parsingContext.cpp | 15 ++- src/vmime/parsingContext.hpp | 23 +++++ 3 files changed, 136 insertions(+), 90 deletions(-) diff --git a/src/vmime/headerField.cpp b/src/vmime/headerField.cpp index a89704ab..0229668d 100644 --- a/src/vmime/headerField.cpp +++ b/src/vmime/headerField.cpp @@ -103,117 +103,129 @@ shared_ptr headerField::parseNext return null; } - // This line may be a field description - if (!parserHelpers::isSpace(c)) - { - const size_t nameStart = pos; // remember the start position of the line + // This line may be a field description + if (!parserHelpers::isSpace(c)) + { + const size_t nameStart = pos; // remember the start position of the line - while (pos < end && (buffer[pos] != ':' && !parserHelpers::isSpace(buffer[pos]))) - ++pos; + while (pos < end && (buffer[pos] != ':' && !parserHelpers::isSpace(buffer[pos]))) + ++pos; - const size_t nameEnd = pos; + const size_t nameEnd = pos; - while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) - ++pos; + while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) + ++pos; - if (buffer[pos] != ':') - { - // Humm...does not seem to be a valid header line. - // Skip this error and advance to the next line - pos = nameStart; + if (buffer[pos] != ':') + { + switch (ctx.getHeaderParseErrorRecoveryMethod()) { + case vmime::headerParseRecoveryMethod::SKIP_LINE: + // Humm...does not seem to be a valid header line. + // Skip this error and advance to the next line + pos = nameStart; - while (pos < end && buffer[pos] != '\n') - ++pos; + while (pos < end && buffer[pos] != '\n') + ++pos; - if (pos < end && buffer[pos] == '\n') - ++pos; - } - else - { - // Extract the field name - const string name(buffer.begin() + nameStart, - buffer.begin() + nameEnd); + if (pos < end && buffer[pos] == '\n') + ++pos; + break; - // Skip ':' character - while (pos < end && buffer[pos] == ':') - ++pos; +// case vmime::headerParseRecoveryMethod::APPEND_TO_PREVIOUS_LINE: +// // TODO Implement this... +// break; - // Skip spaces between ':' and the field contents - while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) - ++pos; + case vmime::headerParseRecoveryMethod::ASSUME_END_OF_HEADERS: + return null; + break; + } + } + else + { + // Extract the field name + const string name(buffer.begin() + nameStart, + buffer.begin() + nameEnd); - const size_t contentsStart = pos; - size_t contentsEnd = 0; + // Skip ':' character + while (pos < end && buffer[pos] == ':') + ++pos; - bool firstLine = true; + // Skip spaces between ':' and the field contents + while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) + ++pos; - // Parse field value, taking care of line folding (value on multiple lines) - for (size_t eol = 0 ; parserHelpers::findEOL(buffer, pos, end, &eol) ; pos = eol) - { - // If the line does not start with a folding indicator (SPACE or TAB), - // and this is not the first line, then stop parsing lines - if (!firstLine && !(buffer[pos] == ' ' || buffer[pos] == '\t')) - break; + const size_t contentsStart = pos; + size_t contentsEnd = 0; - contentsEnd = eol; - firstLine = false; - } + bool firstLine = true; - if (pos == end && contentsEnd == 0) - { - // End of data, and no CRLF was found at the end - contentsEnd = end; - } + // Parse field value, taking care of line folding (value on multiple lines) + for (size_t eol = 0 ; parserHelpers::findEOL(buffer, pos, end, &eol) ; pos = eol) + { + // If the line does not start with a folding indicator (SPACE or TAB), + // and this is not the first line, then stop parsing lines + if (!firstLine && !(buffer[pos] == ' ' || buffer[pos] == '\t')) + break; - // Strip spaces from end of header lines - while (contentsEnd > contentsStart && - (buffer[contentsEnd - 1] == ' ' || buffer[contentsEnd - 1] == '\t' || - buffer[contentsEnd - 1] == '\r' || buffer[contentsEnd - 1] == '\n')) - { - contentsEnd--; - } + contentsEnd = eol; + firstLine = false; + } - // Return a new field - shared_ptr field = headerFieldFactory::getInstance()->create(name); + if (pos == end && contentsEnd == 0) + { + // End of data, and no CRLF was found at the end + contentsEnd = end; + } - field->parse(ctx, buffer, contentsStart, contentsEnd, NULL); - field->setParsedBounds(nameStart, pos); + // Strip spaces from end of header lines + while (contentsEnd > contentsStart && + (buffer[contentsEnd - 1] == ' ' || buffer[contentsEnd - 1] == '\t' || + buffer[contentsEnd - 1] == '\r' || buffer[contentsEnd - 1] == '\n')) + { + contentsEnd--; + } - if (newPosition) - *newPosition = pos; + // Return a new field + shared_ptr field = headerFieldFactory::getInstance()->create(name); - return (field); - } - } - else - { - // If the line contains only space characters, we assume it is - // the end of the headers. - while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) - ++pos; + field->parse(ctx, buffer, contentsStart, contentsEnd, NULL); + field->setParsedBounds(nameStart, pos); - if (pos < end && buffer[pos] == '\n') - { - if (newPosition) - *newPosition = pos + 1; // LF: illegal + if (newPosition) + *newPosition = pos; - return null; - } - else if (pos + 1 < end && buffer[pos] == '\r' && buffer[pos + 1] == '\n') - { - if (newPosition) - *newPosition = pos + 2; // CR+LF + return (field); + } + } + else + { + // If the line contains only space characters, we assume it is + // the end of the headers. + while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) + ++pos; - return null; - } + if (pos < end && buffer[pos] == '\n') + { + if (newPosition) + *newPosition = pos + 1; // LF: illegal - // Skip this error and advance to the next line - while (pos < end && buffer[pos] != '\n') - ++pos; + return null; + } + else if (pos + 1 < end && buffer[pos] == '\r' && buffer[pos + 1] == '\n') + { + if (newPosition) + *newPosition = pos + 2; // CR+LF - if (buffer[pos] == '\n') - ++pos; - } + return null; + } + + // Skip this error and advance to the next line + while (pos < end && buffer[pos] != '\n') + ++pos; + + if (buffer[pos] == '\n') + ++pos; + } } if (newPosition) diff --git a/src/vmime/parsingContext.cpp b/src/vmime/parsingContext.cpp index 527f4705..71454926 100644 --- a/src/vmime/parsingContext.cpp +++ b/src/vmime/parsingContext.cpp @@ -28,13 +28,13 @@ namespace vmime { -parsingContext::parsingContext() +parsingContext::parsingContext() : m_headerParseErrorRecovery(vmime::headerParseRecoveryMethod::SKIP_LINE) { } parsingContext::parsingContext(const parsingContext& ctx) - : context(ctx) + : context(ctx), m_headerParseErrorRecovery(vmime::headerParseRecoveryMethod::SKIP_LINE) { } @@ -45,5 +45,16 @@ parsingContext& parsingContext::getDefaultContext() return ctx; } +headerParseRecoveryMethod::headerLineError parsingContext::getHeaderParseErrorRecoveryMethod() const +{ + return m_headerParseErrorRecovery; +} + + +void parsingContext::setHeaderParseErrorRecoveryMethod(headerParseRecoveryMethod::headerLineError recoveryMethod) +{ + m_headerParseErrorRecovery = recoveryMethod; +} + } // vmime diff --git a/src/vmime/parsingContext.hpp b/src/vmime/parsingContext.hpp index 27d14a60..f00bccb6 100644 --- a/src/vmime/parsingContext.hpp +++ b/src/vmime/parsingContext.hpp @@ -31,6 +31,15 @@ namespace vmime { + /** Provides runtime configurable options to provide flexibility in header parsing + */ + struct headerParseRecoveryMethod { + enum headerLineError { + SKIP_LINE = 0, + /* APPEND_TO_PREVIOUS_LINE = 1, */ + ASSUME_END_OF_HEADERS = 2 + }; + }; /** Holds configuration parameters used for parsing messages. */ @@ -48,8 +57,22 @@ public: */ static parsingContext& getDefaultContext(); + /** Sets the recovery method when parsing a header encounters an error such as a failed fold or missing new line. + * + * @param recoveryMethod is one of vmime::headerParseRecoveryMethod. Defaults to vmime::headerParseRecoveryMethod::SKIP_LINE. + */ + void setHeaderParseErrorRecoveryMethod(headerParseRecoveryMethod::headerLineError recoveryMethod); + + /** Return the recovery method when parsing a header encounters an error. + * + * @return is an enum from vmime::headerParseRecoveryMethod + */ + headerParseRecoveryMethod::headerLineError getHeaderParseErrorRecoveryMethod() const; + + protected: + headerParseRecoveryMethod::headerLineError m_headerParseErrorRecovery; }; From 8fb7b007f9cbfbea3f5527d7060557d9b43c9d4a Mon Sep 17 00:00:00 2001 From: bmagistro Date: Mon, 27 Feb 2017 11:12:12 -0500 Subject: [PATCH 3/6] use original headerField.cpp to avoid whitespace differences --- src/vmime/headerField.cpp | 182 +++++++++++++++++++------------------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/src/vmime/headerField.cpp b/src/vmime/headerField.cpp index 0229668d..dc80957b 100644 --- a/src/vmime/headerField.cpp +++ b/src/vmime/headerField.cpp @@ -103,33 +103,33 @@ shared_ptr headerField::parseNext return null; } - // This line may be a field description - if (!parserHelpers::isSpace(c)) - { - const size_t nameStart = pos; // remember the start position of the line + // This line may be a field description + if (!parserHelpers::isSpace(c)) + { + const size_t nameStart = pos; // remember the start position of the line - while (pos < end && (buffer[pos] != ':' && !parserHelpers::isSpace(buffer[pos]))) + while (pos < end && (buffer[pos] != ':' && !parserHelpers::isSpace(buffer[pos]))) + ++pos; + + const size_t nameEnd = pos; + + while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) ++pos; - const size_t nameEnd = pos; - - while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) - ++pos; - - if (buffer[pos] != ':') - { - switch (ctx.getHeaderParseErrorRecoveryMethod()) { + if (buffer[pos] != ':') + { + switch (ctx.getHeaderParseErrorRecoveryMethod()) { case vmime::headerParseRecoveryMethod::SKIP_LINE: - // Humm...does not seem to be a valid header line. - // Skip this error and advance to the next line - pos = nameStart; + // Humm...does not seem to be a valid header line. + // Skip this error and advance to the next line + pos = nameStart; - while (pos < end && buffer[pos] != '\n') - ++pos; + while (pos < end && buffer[pos] != '\n') + ++pos; - if (pos < end && buffer[pos] == '\n') - ++pos; - break; + if (pos < end && buffer[pos] == '\n') + ++pos; + break; // case vmime::headerParseRecoveryMethod::APPEND_TO_PREVIOUS_LINE: // // TODO Implement this... @@ -139,93 +139,93 @@ shared_ptr headerField::parseNext return null; break; } - } - else - { - // Extract the field name - const string name(buffer.begin() + nameStart, - buffer.begin() + nameEnd); + } + else + { + // Extract the field name + const string name(buffer.begin() + nameStart, + buffer.begin() + nameEnd); - // Skip ':' character - while (pos < end && buffer[pos] == ':') - ++pos; + // Skip ':' character + while (pos < end && buffer[pos] == ':') + ++pos; - // Skip spaces between ':' and the field contents - while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) - ++pos; + // Skip spaces between ':' and the field contents + while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) + ++pos; - const size_t contentsStart = pos; - size_t contentsEnd = 0; + const size_t contentsStart = pos; + size_t contentsEnd = 0; - bool firstLine = true; + bool firstLine = true; - // Parse field value, taking care of line folding (value on multiple lines) - for (size_t eol = 0 ; parserHelpers::findEOL(buffer, pos, end, &eol) ; pos = eol) - { - // If the line does not start with a folding indicator (SPACE or TAB), - // and this is not the first line, then stop parsing lines - if (!firstLine && !(buffer[pos] == ' ' || buffer[pos] == '\t')) - break; + // Parse field value, taking care of line folding (value on multiple lines) + for (size_t eol = 0 ; parserHelpers::findEOL(buffer, pos, end, &eol) ; pos = eol) + { + // If the line does not start with a folding indicator (SPACE or TAB), + // and this is not the first line, then stop parsing lines + if (!firstLine && !(buffer[pos] == ' ' || buffer[pos] == '\t')) + break; - contentsEnd = eol; - firstLine = false; - } + contentsEnd = eol; + firstLine = false; + } - if (pos == end && contentsEnd == 0) - { - // End of data, and no CRLF was found at the end - contentsEnd = end; - } + if (pos == end && contentsEnd == 0) + { + // End of data, and no CRLF was found at the end + contentsEnd = end; + } - // Strip spaces from end of header lines - while (contentsEnd > contentsStart && - (buffer[contentsEnd - 1] == ' ' || buffer[contentsEnd - 1] == '\t' || - buffer[contentsEnd - 1] == '\r' || buffer[contentsEnd - 1] == '\n')) - { - contentsEnd--; - } + // Strip spaces from end of header lines + while (contentsEnd > contentsStart && + (buffer[contentsEnd - 1] == ' ' || buffer[contentsEnd - 1] == '\t' || + buffer[contentsEnd - 1] == '\r' || buffer[contentsEnd - 1] == '\n')) + { + contentsEnd--; + } - // Return a new field - shared_ptr field = headerFieldFactory::getInstance()->create(name); + // Return a new field + shared_ptr field = headerFieldFactory::getInstance()->create(name); - field->parse(ctx, buffer, contentsStart, contentsEnd, NULL); - field->setParsedBounds(nameStart, pos); + field->parse(ctx, buffer, contentsStart, contentsEnd, NULL); + field->setParsedBounds(nameStart, pos); - if (newPosition) - *newPosition = pos; + if (newPosition) + *newPosition = pos; - return (field); - } - } - else - { - // If the line contains only space characters, we assume it is - // the end of the headers. - while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) - ++pos; + return (field); + } + } + else + { + // If the line contains only space characters, we assume it is + // the end of the headers. + while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) + ++pos; - if (pos < end && buffer[pos] == '\n') - { - if (newPosition) - *newPosition = pos + 1; // LF: illegal + if (pos < end && buffer[pos] == '\n') + { + if (newPosition) + *newPosition = pos + 1; // LF: illegal - return null; - } - else if (pos + 1 < end && buffer[pos] == '\r' && buffer[pos + 1] == '\n') - { - if (newPosition) - *newPosition = pos + 2; // CR+LF + return null; + } + else if (pos + 1 < end && buffer[pos] == '\r' && buffer[pos + 1] == '\n') + { + if (newPosition) + *newPosition = pos + 2; // CR+LF - return null; - } + return null; + } - // Skip this error and advance to the next line - while (pos < end && buffer[pos] != '\n') - ++pos; + // Skip this error and advance to the next line + while (pos < end && buffer[pos] != '\n') + ++pos; - if (buffer[pos] == '\n') - ++pos; - } + if (buffer[pos] == '\n') + ++pos; + } } if (newPosition) From e6f2ed341a45301c5ed6b291fae810033aa8925e Mon Sep 17 00:00:00 2001 From: bmagistro Date: Thu, 9 Mar 2017 14:07:15 -0500 Subject: [PATCH 4/6] attempt 2, fix whitespace differences --- src/vmime/headerField.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/vmime/headerField.cpp b/src/vmime/headerField.cpp index dc80957b..40611a45 100644 --- a/src/vmime/headerField.cpp +++ b/src/vmime/headerField.cpp @@ -114,31 +114,31 @@ shared_ptr headerField::parseNext const size_t nameEnd = pos; while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) - ++pos; + ++pos; if (buffer[pos] != ':') { switch (ctx.getHeaderParseErrorRecoveryMethod()) { - case vmime::headerParseRecoveryMethod::SKIP_LINE: - // Humm...does not seem to be a valid header line. - // Skip this error and advance to the next line - pos = nameStart; + case vmime::headerParseRecoveryMethod::SKIP_LINE: + // Humm...does not seem to be a valid header line. + // Skip this error and advance to the next line + pos = nameStart; - while (pos < end && buffer[pos] != '\n') - ++pos; + while (pos < end && buffer[pos] != '\n') + ++pos; - if (pos < end && buffer[pos] == '\n') - ++pos; - break; + if (pos < end && buffer[pos] == '\n') + ++pos; + break; -// case vmime::headerParseRecoveryMethod::APPEND_TO_PREVIOUS_LINE: -// // TODO Implement this... -// break; +// case vmime::headerParseRecoveryMethod::APPEND_TO_PREVIOUS_LINE: +// // TODO Implement this... +// break; - case vmime::headerParseRecoveryMethod::ASSUME_END_OF_HEADERS: - return null; - break; - } + case vmime::headerParseRecoveryMethod::ASSUME_END_OF_HEADERS: + return null; + break; + } } else { From 975f555f220770d167216d40977b2c18df407302 Mon Sep 17 00:00:00 2001 From: bmagistro Date: Thu, 9 Mar 2017 14:20:43 -0500 Subject: [PATCH 5/6] attempt 2, fix whitespace differences --- src/vmime/parsingContext.cpp | 4 ++-- src/vmime/parsingContext.hpp | 40 ++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/vmime/parsingContext.cpp b/src/vmime/parsingContext.cpp index 71454926..954c5651 100644 --- a/src/vmime/parsingContext.cpp +++ b/src/vmime/parsingContext.cpp @@ -47,13 +47,13 @@ parsingContext& parsingContext::getDefaultContext() headerParseRecoveryMethod::headerLineError parsingContext::getHeaderParseErrorRecoveryMethod() const { - return m_headerParseErrorRecovery; + return m_headerParseErrorRecovery; } void parsingContext::setHeaderParseErrorRecoveryMethod(headerParseRecoveryMethod::headerLineError recoveryMethod) { - m_headerParseErrorRecovery = recoveryMethod; + m_headrParseErrorRecovery = recoveryMethod; } diff --git a/src/vmime/parsingContext.hpp b/src/vmime/parsingContext.hpp index f00bccb6..1b1cd282 100644 --- a/src/vmime/parsingContext.hpp +++ b/src/vmime/parsingContext.hpp @@ -31,15 +31,15 @@ namespace vmime { - /** Provides runtime configurable options to provide flexibility in header parsing - */ - struct headerParseRecoveryMethod { - enum headerLineError { - SKIP_LINE = 0, - /* APPEND_TO_PREVIOUS_LINE = 1, */ - ASSUME_END_OF_HEADERS = 2 - }; - }; + /** Provides runtime configurable options to provide flexibility in header parsing + */ + struct headerParseRecoveryMethod { + enum headerLineError { + SKIP_LINE = 0, + /* APPEND_TO_PREVIOUS_LINE = 1, */ + ASSUME_END_OF_HEADERS = 2 + }; + }; /** Holds configuration parameters used for parsing messages. */ @@ -57,22 +57,22 @@ public: */ static parsingContext& getDefaultContext(); - /** Sets the recovery method when parsing a header encounters an error such as a failed fold or missing new line. - * - * @param recoveryMethod is one of vmime::headerParseRecoveryMethod. Defaults to vmime::headerParseRecoveryMethod::SKIP_LINE. - */ - void setHeaderParseErrorRecoveryMethod(headerParseRecoveryMethod::headerLineError recoveryMethod); + /** Sets the recovery method when parsing a header encounters an error such as a failed fold or missing new line. + * + * @param recoveryMethod is one of vmime::headerParseRecoveryMethod. Defaults to vmime::headerParseRecoveryMethod::SKIP_LINE. + */ + void setHeaderParseErrorRecoveryMethod(headerParseRecoveryMethod::headerLineError recoveryMethod); - /** Return the recovery method when parsing a header encounters an error. - * - * @return is an enum from vmime::headerParseRecoveryMethod - */ - headerParseRecoveryMethod::headerLineError getHeaderParseErrorRecoveryMethod() const; + /** Return the recovery method when parsing a header encounters an error. + * + * @return is an enum from vmime::headerParseRecoveryMethod + */ + headerParseRecoveryMethod::headerLineError getHeaderParseErrorRecoveryMethod() const; protected: - headerParseRecoveryMethod::headerLineError m_headerParseErrorRecovery; + headerParseRecoveryMethod::headerLineError m_headerParseErrorRecovery; }; From 522ec147a34b64b623d6822751ca445405d2ca75 Mon Sep 17 00:00:00 2001 From: bmagistro Date: Thu, 9 Mar 2017 15:40:50 -0500 Subject: [PATCH 6/6] fix deleted character --- src/vmime/parsingContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmime/parsingContext.cpp b/src/vmime/parsingContext.cpp index 954c5651..c5da5151 100644 --- a/src/vmime/parsingContext.cpp +++ b/src/vmime/parsingContext.cpp @@ -53,7 +53,7 @@ headerParseRecoveryMethod::headerLineError parsingContext::getHeaderParseErrorRe void parsingContext::setHeaderParseErrorRecoveryMethod(headerParseRecoveryMethod::headerLineError recoveryMethod) { - m_headrParseErrorRecovery = recoveryMethod; + m_headerParseErrorRecovery = recoveryMethod; }