diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/DotAtomReader.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/DotAtomReader.cs index 968104159e0e39..f3f3c5b751b98f 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/DotAtomReader.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/DotAtomReader.cs @@ -11,8 +11,8 @@ namespace System.Net.Mail // RFC 2822 Section 3.2.4 - Atom, Dot-Atom // // A Dot-Atom is a string of ASCII characters separated by dots. Dots would normally not be allowed at the start - // or end, but we do allow dots at the end for compatibility with other mail clients. We also allow - // multiple consecutive dots, which would normally be invalid. + // or end, but we do allow dots at the end for compatibility with other mail clients. We don't allow + // multiple consecutive dots as specified in RFC 2822 section 3.4.1. // internal static class DotAtomReader { @@ -45,7 +45,8 @@ internal static bool TryReadReverse(string data, int index, out int outIndex, bo for (; 0 <= index; index--) { if (Ascii.IsValid(data[index]) // Any ASCII allowed - && (data[index] != MailBnfHelper.Dot && !MailBnfHelper.Atext[data[index]])) // Invalid char + && ((data[index] != MailBnfHelper.Dot && !MailBnfHelper.Atext[data[index]]) + || (data[index] == MailBnfHelper.Dot && index > 0 && data[index - 1] == MailBnfHelper.Dot))) // Invalid char { break; } @@ -64,6 +65,18 @@ internal static bool TryReadReverse(string data, int index, out int outIndex, bo return false; } } + else if (index > 0 && data[index] == MailBnfHelper.Dot && data[index - 1] == MailBnfHelper.Dot) + { + if (throwExceptionIfFail) + { + throw new FormatException(SR.Format(SR.MailHeaderFieldInvalidCharacter, MailBnfHelper.ConsecutiveDots)); + } + else + { + outIndex = default; + return false; + } + } // Check for leading dot else if (data[index + 1] == MailBnfHelper.Dot) { diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailBnfHelper.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailBnfHelper.cs index 658ef63a54173d..305733de80e2f3 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailBnfHelper.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailBnfHelper.cs @@ -44,6 +44,7 @@ internal static class MailBnfHelper internal const char EndSquareBracket = ']'; internal const char Comma = ','; internal const char Dot = '.'; + internal const string ConsecutiveDots = ".."; // NOTE: See RFC 2822 for more detail. By default, every value in the array is false and only // those values which are allowed in that particular set are then set to true. The numbers diff --git a/src/libraries/System.Net.Mail/tests/Functional/MailAddressTest.cs b/src/libraries/System.Net.Mail/tests/Functional/MailAddressTest.cs index 019ceee0d41b2b..bfd42b7d461bd0 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/MailAddressTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/MailAddressTest.cs @@ -62,6 +62,8 @@ public static IEnumerable GetInvalid_Address() yield return new object[] { "forbar" }; yield return new object[] { "" }; yield return new object[] { null }; + yield return new object[] { "fo..o@example.com" }; + yield return new object[] { "foo@exa..mple.com" }; } [Theory] diff --git a/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParserTest.cs b/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParserTest.cs index 967fbae41cf1c0..b52a60ee14ef2f 100644 --- a/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParserTest.cs +++ b/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParserTest.cs @@ -32,8 +32,6 @@ public class MailAddressParserTest private const string UnicodeQuotedString = "I have \u3069 unicode"; private const string ValidDotAtom = " a.something#-text"; private const string ValidDotAtomResult = "a.something#-text"; - private const string ValidDotAtomDoubleDots = " a.d....d"; - private const string ValidDotAtomDoubleDotsResult = "a.d....d"; private const string ValidDotAtomEndsInDot = "a.something."; private const string InvalidDotAtom = "a.something\"test"; private const string InvalidDotAtomStartsWithDot = ".test"; @@ -266,15 +264,6 @@ public void TryReadDotAtom_WithValidDotAtom_ShouldReadCorrectly() Assert.Equal(0, index); } - [Fact] - public void TryReadDotAtom_WithValidDotAtomAndDoubleDots_ShouldReadCorrectly() - { - int index = ValidDotAtomDoubleDots.Length - 1; - Assert.True(DotAtomReader.TryReadReverse(ValidDotAtomDoubleDots, index, out index, throwExceptionIfFail: true)); - - Assert.Equal(0, index); - } - [Fact] public void TryReadDotAtom_EndsInDot_ShouldReadCorrectly() { @@ -381,16 +370,6 @@ public void TryParseAddress_WithEscapedCharacters_AndQuotedLocalPart_ShouldReadC Assert.Equal("[ ncl\\@bld-001 \t ]", result.Host); } - [Fact] - public void TryParseAddress_WithNoDisplayNameAndDotAtom_ShouldReadCorrectly() - { - Assert.True(MailAddressParser.TryParseAddress("a..b_b@example.com", out ParseAddressInfo result, throwExceptionIfFail: true)); - - Assert.Equal(string.Empty, result.DisplayName); - Assert.Equal("a..b_b", result.User); - Assert.Equal("example.com", result.Host); - } - [Fact] public void TryParseAddress_WithQuotedDisplayNameandNoAngleAddress_ShouldReadCorrectly() { @@ -518,18 +497,17 @@ public void ParseAddresses_WithOnlyOneAddress_ShouldReadCorrectly() [Fact] public void ParseAddresses_WithManyComplexAddresses_ShouldReadCorrectly() { - string addresses = string.Format("{0},{1},{2},{3},{4},{5},{6}", + string addresses = string.Format("{0},{1},{2},{3},{4},{5}", "\"Dr M\u00FCller\" test@mail.com", "(comment)this.test.this(comment)@(comment)this.test.this(comment)", "jeff@example.com", "jeff2@example.org", "(comment)this.test.this(comment)<(comment)this.test.this(comment)@(comment)[ test this ](comment)>", - "\"test\" ", "(comment)\" asciin;,oqu o.tesws \"(comment)<(comment)\" asciin;,oqu o.tesws \"(comment)@(comment)this.test.this(comment)>"); IList result = MailAddressParser.ParseMultipleAddresses(addresses); - Assert.Equal(7, result.Count); + Assert.Equal(6, result.Count); Assert.Equal("Dr M\u00FCller", result[0].DisplayName); Assert.Equal("test", result[0].User); @@ -551,13 +529,9 @@ public void ParseAddresses_WithManyComplexAddresses_ShouldReadCorrectly() Assert.Equal("this.test.this", result[4].User); Assert.Equal("[ test this ]", result[4].Host); - Assert.Equal("test", result[5].DisplayName); - Assert.Equal("a..b_b", result[5].User); - Assert.Equal("example.com", result[5].Host); - - Assert.Equal(" asciin;,oqu o.tesws ", result[6].DisplayName); - Assert.Equal("\" asciin;,oqu o.tesws \"", result[6].User); - Assert.Equal("this.test.this", result[6].Host); + Assert.Equal(" asciin;,oqu o.tesws ", result[5].DisplayName); + Assert.Equal("\" asciin;,oqu o.tesws \"", result[5].User); + Assert.Equal("this.test.this", result[5].Host); } } } diff --git a/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParsingTest.cs b/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParsingTest.cs index f1755e9c8de4ad..b0436e77476e8c 100644 --- a/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParsingTest.cs +++ b/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParsingTest.cs @@ -59,8 +59,6 @@ public static IEnumerable GetValidEmailTestData() yield return new object[] { "!def!xyz%abc@example.com" }; yield return new object[] { "_somename@example.com" }; yield return new object[] { "\"te\\@st\"@example.com" }; - yield return new object[] { "a..b_b@example.com" }; - yield return new object[] { "a..b_b...@example.com" }; yield return new object[] { "\"test display\" test@(comment)[exam\\@ple](comment)" }; yield return new object[] { "NoSpaceBeforeEmail\"a\"@example.com" }; yield return new object[] { "NoSpace BeforeEmail\"a\"@example.com" }; @@ -134,6 +132,8 @@ public static IEnumerable GetInvalidEmailTestData() yield return new object[] { "\uD800 invalid@unicode.com" }; // D800 is a high surrogate yield return new object[] { null }; yield return new object[] { "" }; + yield return new object[] { "a..b_b@example.com" }; + yield return new object[] { "a..b_b...@example.com" }; } [Theory]