Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions src/libraries/System.Net.Mail/src/System/Net/Mail/DotAtomReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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;
}
Expand All @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public static IEnumerable<object[]> 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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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()
{
Expand Down Expand Up @@ -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()
{
Expand Down Expand Up @@ -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\" <a..b_b@example.com>",
"(comment)\" asciin;,oqu o.tesws \"(comment)<(comment)\" asciin;,oqu o.tesws \"(comment)@(comment)this.test.this(comment)>");

IList<MailAddress> 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);
Expand All @@ -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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ public static IEnumerable<object[]> 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" };
Expand Down Expand Up @@ -134,6 +132,8 @@ public static IEnumerable<object[]> 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]
Expand Down