diff options
| -rw-r--r-- | src/logTypes.cpp | 59 | ||||
| -rw-r--r-- | test/test-ingest.cpp | 11 |
2 files changed, 46 insertions, 24 deletions
diff --git a/src/logTypes.cpp b/src/logTypes.cpp index 85c5f4b..d8b3a7e 100644 --- a/src/logTypes.cpp +++ b/src/logTypes.cpp @@ -1,10 +1,8 @@ #include "logTypes.hpp" -namespace scn { - scan_expected<typename ContextType::iterator> - scanner<WebStat::QuotedString>::scan(WebStat::QuotedString & value, ContextType & ctx) - { - static constexpr auto BS_MAP = []() { +namespace { + namespace { + constexpr auto BS_MAP = []() { std::array<char, 128> map {}; map['f'] = '\f'; map['n'] = '\n'; @@ -16,18 +14,10 @@ namespace scn { return map; }(); - if (auto empty = scn::scan<>(ctx.range(), R"("")")) { - return empty->begin(); - } - - auto simple = scn::scan<std::string>(ctx.range(), R"("{:[^\"]}")"); - if (simple) { - value = std::move(simple->value()); - return simple->begin(); - } - - if (auto openQuote = scn::scan<>(ctx.range(), R"(")")) { - ctx.advance_to(openQuote->begin()); + scn::scan_expected<typename scn::ContextType::iterator> + parseEscapedString(std::string & value, scn::ContextType & ctx, const auto & start) + { + ctx.advance_to(start->begin()); while (true) { if (auto closeQuote = scn::scan<>(ctx.range(), R"(")")) { return closeQuote->begin(); @@ -45,9 +35,30 @@ namespace scn { ctx.advance_to(escaped->begin()); } else { - return unexpected(simple.error()); + return scn::unexpected(start.error()); } } + return scn::unexpected(start.error()); + } + } +} + +namespace scn { + scan_expected<typename ContextType::iterator> + scanner<WebStat::QuotedString>::scan(WebStat::QuotedString & value, ContextType & ctx) + { + if (auto empty = scn::scan<>(ctx.range(), R"("")")) { + return empty->begin(); + } + + auto simple = scn::scan<std::string>(ctx.range(), R"("{:[^\"]}")"); + if (simple) { + value = std::move(simple->value()); + return simple->begin(); + } + + if (auto openQuote = scn::scan<>(ctx.range(), R"(")")) { + return parseEscapedString(value, ctx, openQuote); } return unexpected(simple.error()); } @@ -59,17 +70,17 @@ namespace scn { return null->begin(); } - if (auto empty = scn::scan<>(ctx.range(), R"("?")")) { + auto empty = scn::scan<>(ctx.range(), R"("?")"); + if (empty) { value.emplace(); return empty->begin(); } - auto result = scn::scan<std::string>(ctx.range(), R"("?{:[^"]}")"); - if (!result) { - return unexpected(result.error()); + if (auto openQuoteQM = scn::scan<>(ctx.range(), R"("?)")) { + value.emplace(); + return parseEscapedString(*value, ctx, openQuoteQM); } - value = std::move(result->value()); - return result->begin(); + return unexpected(empty.error()); } scan_expected<typename ContextType::iterator> diff --git a/test/test-ingest.cpp b/test/test-ingest.cpp index 8c82764..5fc8195 100644 --- a/test/test-ingest.cpp +++ b/test/test-ingest.cpp @@ -202,6 +202,17 @@ BOOST_AUTO_TEST_CASE(ExtractFieldsEdgeCasesUnparsable3603068405) BOOST_CHECK_EQUAL(std::get<4>(result->values()), R"LOG(/packages/dev-php/pecl-uploadprogress'yqFSRA<'">yuezhx)LOG"); } +BOOST_AUTO_TEST_CASE(ExtractFieldsEdgeCasesUnparsable3482917779) +{ + const auto result = WebStat::Ingestor::scanLogLine( + R"LOG(195.166.151.214 62.171.174.195 1774536220216585 GET "/index.php" "?lang=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/&/<?echo(md5(\"hi\"));?>+/tmp/index1.php" HTTP/1.1 404 376 5811 "-" "libredtail-http" "text/html")LOG"); + BOOST_REQUIRE(result); + const auto queryString = std::get<5>(result->values()); + BOOST_REQUIRE(queryString); + BOOST_CHECK_EQUAL(*queryString, + R"LOG(lang=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/&/<?echo(md5("hi"));?>+/tmp/index1.php)LOG"); +} + class TestIngestor : public WebStat::Ingestor { public: TestIngestor() : |
