From 01fab121c653e7c884599289c997b415fbe7d784 Mon Sep 17 00:00:00 2001 From: kant01ne Date: Wed, 11 Dec 2024 12:04:27 +0100 Subject: [PATCH 1/2] parsing invalid header takes infinite time --- test/mail/parsers/rfc_2822_test.exs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/mail/parsers/rfc_2822_test.exs b/test/mail/parsers/rfc_2822_test.exs index 82df2f3..2a7f1c9 100644 --- a/test/mail/parsers/rfc_2822_test.exs +++ b/test/mail/parsers/rfc_2822_test.exs @@ -1027,6 +1027,18 @@ defmodule Mail.Parsers.RFC2822Test do defp parse_email(email, opts \\ []), do: email |> convert_crlf |> Mail.Parsers.RFC2822.parse(opts) + test "invalid content-type should not take infinite time" do + message = + parse_email(""" + Content-type: text/html; charset=us-ascii;a + """) + + assert message.headers["content-type"] == ["text/html", {"charset", "us-ascii"}] + end + + defp parse_email(email), + do: email |> convert_crlf |> Mail.Parsers.RFC2822.parse() + defp parse_recipient(recipient), do: Mail.Parsers.RFC2822.parse_recipient_value(recipient) From cad5ea01d90da9a33c4538834e1576f9ff722ff1 Mon Sep 17 00:00:00 2001 From: Andrew Timberlake Date: Mon, 17 Mar 2025 16:49:00 +0200 Subject: [PATCH 2/2] Fix parsing of structured headers with invalid params --- lib/mail/parsers/rfc_2822.ex | 64 +++++++++++++++++------------ test/mail/parsers/rfc_2822_test.exs | 7 +--- 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/lib/mail/parsers/rfc_2822.ex b/lib/mail/parsers/rfc_2822.ex index ba67ef0..220e20d 100644 --- a/lib/mail/parsers/rfc_2822.ex +++ b/lib/mail/parsers/rfc_2822.ex @@ -486,20 +486,29 @@ defmodule Mail.Parsers.RFC2822 do acc \\ "" ) - defp parse_structured_header_value("", value, [{key, nil} | sub_types], _part, acc), - do: [value | Enum.reverse([{key, acc} | sub_types])] + defp parse_structured_header_value("", value, [{key, nil} | sub_types], _part, acc) do + [value | Enum.reverse([{key, acc} | sub_types])] + end - defp parse_structured_header_value("", nil, [], _part, acc), - do: acc + defp parse_structured_header_value("", value, sub_types, :param_name, _acc) do + [value | Enum.reverse(sub_types)] + end - defp parse_structured_header_value("", value, sub_types, _part, ""), - do: [value | Enum.reverse(sub_types)] + defp parse_structured_header_value("", nil, [], _part, acc) do + acc + end - defp parse_structured_header_value("", value, [], _part, acc), - do: [value, String.trim(acc)] + defp parse_structured_header_value("", value, [_ | _] = sub_types, _part, "") do + [value | Enum.reverse(sub_types)] + end - defp parse_structured_header_value("", value, sub_types, part, acc), - do: parse_structured_header_value("", value, sub_types, part, String.trim(acc)) + defp parse_structured_header_value("", value, [], _part, acc) do + [value, String.trim(acc)] + end + + defp parse_structured_header_value("", value, sub_types, part, acc) do + parse_structured_header_value("", value, sub_types, part, String.trim(acc)) + end defp parse_structured_header_value(<<"\"", rest::binary>>, value, sub_types, part, acc) do {string, rest} = parse_quoted_string(rest) @@ -507,8 +516,9 @@ defmodule Mail.Parsers.RFC2822 do end defp parse_structured_header_value(<<";", rest::binary>>, nil, sub_types, part, acc) - when part in [:value, :param_value], - do: parse_structured_header_value(rest, acc, sub_types, :param_name, "") + when part in [:value, :param_value] do + parse_structured_header_value(rest, acc, sub_types, :param_name, "") + end defp parse_structured_header_value( <<";", rest::binary>>, @@ -516,21 +526,23 @@ defmodule Mail.Parsers.RFC2822 do [{key, nil} | sub_types], :param_value, acc - ), - do: parse_structured_header_value(rest, value, [{key, acc} | sub_types], :param_name, "") + ) do + parse_structured_header_value(rest, value, [{key, acc} | sub_types], :param_name, "") + end - defp parse_structured_header_value(<<"=", rest::binary>>, value, sub_types, :param_name, acc), - do: - parse_structured_header_value( - rest, - value, - [{key_to_atom(acc), nil} | sub_types], - :param_value, - "" - ) - - defp parse_structured_header_value(<>, value, sub_types, part, acc), - do: parse_structured_header_value(rest, value, sub_types, part, <>) + defp parse_structured_header_value(<<"=", rest::binary>>, value, sub_types, :param_name, acc) do + parse_structured_header_value( + rest, + value, + [{key_to_atom(acc), nil} | sub_types], + :param_value, + "" + ) + end + + defp parse_structured_header_value(<>, value, sub_types, part, acc) do + parse_structured_header_value(rest, value, sub_types, part, <>) + end defp parse_quoted_string(string, acc \\ "") diff --git a/test/mail/parsers/rfc_2822_test.exs b/test/mail/parsers/rfc_2822_test.exs index 2a7f1c9..4bf58dd 100644 --- a/test/mail/parsers/rfc_2822_test.exs +++ b/test/mail/parsers/rfc_2822_test.exs @@ -1024,9 +1024,6 @@ defmodule Mail.Parsers.RFC2822Test do assert message.headers["subject"] == "Test of new header generator" end - defp parse_email(email, opts \\ []), - do: email |> convert_crlf |> Mail.Parsers.RFC2822.parse(opts) - test "invalid content-type should not take infinite time" do message = parse_email(""" @@ -1036,8 +1033,8 @@ defmodule Mail.Parsers.RFC2822Test do assert message.headers["content-type"] == ["text/html", {"charset", "us-ascii"}] end - defp parse_email(email), - do: email |> convert_crlf |> Mail.Parsers.RFC2822.parse() + defp parse_email(email, opts \\ []), + do: email |> convert_crlf |> Mail.Parsers.RFC2822.parse(opts) defp parse_recipient(recipient), do: Mail.Parsers.RFC2822.parse_recipient_value(recipient)