Skip to content

Commit

Permalink
Added *MimeParser tests for EOF where subpart headers should begin
Browse files Browse the repository at this point in the history
  • Loading branch information
jstedfast committed Dec 22, 2024
1 parent e8b5545 commit 654f318
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 4 deletions.
6 changes: 4 additions & 2 deletions MimeKit/AsyncMimeReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,15 @@ async Task StepHeadersAsync (CancellationToken cancellationToken)
left = await ReadAheadAsync (2, 0, cancellationToken).ConfigureAwait (false);

if (left == 0) {
if (toplevel && headerCount == 0 && headerBlockBegin == GetOffset (inputIndex)) {
// Note: The only way to get here is if this is the first-pass throgh this loop and we're at EOF, so headerCount should ALWAYS be 0.

if (toplevel && headerCount == 0) {
// EOF has been reached before any headers have been parsed for Parse[Headers,Entity,Message]Async.
state = MimeParserState.Eos;
return;
}

// FIXME: Should this be Content or Error?
// Note: This can happen if a message is truncated immediately after a boundary marker (e.g. where subpart headers would begin).
state = MimeParserState.Content;
break;
}
Expand Down
6 changes: 4 additions & 2 deletions MimeKit/MimeReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1698,13 +1698,15 @@ unsafe void StepHeaders (byte* inbuf, CancellationToken cancellationToken)
left = ReadAhead (2, 0, cancellationToken);

if (left == 0) {
if (toplevel && headerCount == 0 && headerBlockBegin == GetOffset (inputIndex)) {
// Note: The only way to get here is if this is the first-pass throgh this loop and we're at EOF, so headerCount should ALWAYS be 0.

if (toplevel && headerCount == 0) {
// EOF has been reached before any headers have been parsed for Parse[Headers,Entity,Message].
state = MimeParserState.Eos;
return;
}

// FIXME: Should this be Content or Error?
// Note: This can happen if a message is truncated immediately after a boundary marker (e.g. where subpart headers would begin).
state = MimeParserState.Content;
break;
}
Expand Down
88 changes: 88 additions & 0 deletions UnitTests/ExperimentalMimeParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,94 @@ This is the message body.
}
}

[Test]
public void TestMultipartTruncatedImmediatelyAfterBoundary ()
{
string text = @"From: [email protected]
To: [email protected]
Subject: test of multipart boundary w/o trailing newline
Date: Tue, 12 Nov 2013 09:12:42 -0500
MIME-Version: 1.0
Message-ID: <[email protected]>
X-Mailer: Microsoft Office Outlook 12.0
Content-Type: multipart/mixed;
boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90""
------=_NextPart_000_003F_01CE98CE.6E826F90
".Replace ("\r\n", "\n");

using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) {
var parser = new ExperimentalMimeParser (stream, MimeFormat.Entity);
var message = parser.ParseMessage ();

Assert.That (message.Body, Is.InstanceOf<Multipart> (), "Expected top-level to be a multipart");
var multipart = (Multipart) message.Body;
Assert.That (multipart.Count, Is.EqualTo (1));
Assert.That (multipart[0], Is.InstanceOf<TextPart> (), "Expected first child of the multipart to be text/plain");
var body = (TextPart) multipart[0];

Assert.That (body.Text, Is.EqualTo (string.Empty));
}

using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) {
var parser = new ExperimentalMimeParser (stream, MimeFormat.Entity);
var message = parser.ParseMessage ();

Assert.That (message.Body, Is.InstanceOf<Multipart> (), "Expected top-level to be a multipart");
var multipart = (Multipart) message.Body;
Assert.That (multipart.Count, Is.EqualTo (1));
Assert.That (multipart[0], Is.InstanceOf<TextPart> (), "Expected first child of the multipart to be text/plain");
var body = (TextPart) multipart[0];

Assert.That (body.Text, Is.EqualTo (string.Empty));
}
}

[Test]
public async Task TestMultipartTruncatedImmediatelyAfterBoundaryAsync ()
{
string text = @"From: [email protected]
To: [email protected]
Subject: test of multipart boundary w/o trailing newline
Date: Tue, 12 Nov 2013 09:12:42 -0500
MIME-Version: 1.0
Message-ID: <[email protected]>
X-Mailer: Microsoft Office Outlook 12.0
Content-Type: multipart/mixed;
boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90""
------=_NextPart_000_003F_01CE98CE.6E826F90
".Replace ("\r\n", "\n");

using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) {
var parser = new ExperimentalMimeParser (stream, MimeFormat.Entity);
var message = await parser.ParseMessageAsync ();

Assert.That (message.Body, Is.InstanceOf<Multipart> (), "Expected top-level to be a multipart");
var multipart = (Multipart) message.Body;
Assert.That (multipart.Count, Is.EqualTo (1));
Assert.That (multipart[0], Is.InstanceOf<TextPart> (), "Expected first child of the multipart to be text/plain");
var body = (TextPart) multipart[0];

Assert.That (body.Text, Is.EqualTo (string.Empty));
}

using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) {
var parser = new ExperimentalMimeParser (stream, MimeFormat.Entity);
var message = await parser.ParseMessageAsync ();

Assert.That (message.Body, Is.InstanceOf<Multipart> (), "Expected top-level to be a multipart");
var multipart = (Multipart) message.Body;
Assert.That (multipart.Count, Is.EqualTo (1));
Assert.That (multipart[0], Is.InstanceOf<TextPart> (), "Expected first child of the multipart to be text/plain");
var body = (TextPart) multipart[0];

Assert.That (body.Text, Is.EqualTo (string.Empty));
}
}

[Test]
public void TestMultipartBoundaryWithoutTrailingNewline ()
{
Expand Down
88 changes: 88 additions & 0 deletions UnitTests/MimeParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,94 @@ This is the message body.
}
}

[Test]
public void TestMultipartTruncatedImmediatelyAfterBoundary ()
{
string text = @"From: [email protected]
To: [email protected]
Subject: test of multipart boundary w/o trailing newline
Date: Tue, 12 Nov 2013 09:12:42 -0500
MIME-Version: 1.0
Message-ID: <[email protected]>
X-Mailer: Microsoft Office Outlook 12.0
Content-Type: multipart/mixed;
boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90""
------=_NextPart_000_003F_01CE98CE.6E826F90
".Replace ("\r\n", "\n");

using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) {
var parser = new MimeParser (stream, MimeFormat.Entity);
var message = parser.ParseMessage ();

Assert.That (message.Body, Is.InstanceOf<Multipart> (), "Expected top-level to be a multipart");
var multipart = (Multipart) message.Body;
Assert.That (multipart.Count, Is.EqualTo (1));
Assert.That (multipart[0], Is.InstanceOf<TextPart> (), "Expected first child of the multipart to be text/plain");
var body = (TextPart) multipart[0];

Assert.That (body.Text, Is.EqualTo (string.Empty));
}

using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) {
var parser = new MimeParser (stream, MimeFormat.Entity);
var message = parser.ParseMessage ();

Assert.That (message.Body, Is.InstanceOf<Multipart> (), "Expected top-level to be a multipart");
var multipart = (Multipart) message.Body;
Assert.That (multipart.Count, Is.EqualTo (1));
Assert.That (multipart[0], Is.InstanceOf<TextPart> (), "Expected first child of the multipart to be text/plain");
var body = (TextPart) multipart[0];

Assert.That (body.Text, Is.EqualTo (string.Empty));
}
}

[Test]
public async Task TestMultipartTruncatedImmediatelyAfterBoundaryAsync ()
{
string text = @"From: [email protected]
To: [email protected]
Subject: test of multipart boundary w/o trailing newline
Date: Tue, 12 Nov 2013 09:12:42 -0500
MIME-Version: 1.0
Message-ID: <[email protected]>
X-Mailer: Microsoft Office Outlook 12.0
Content-Type: multipart/mixed;
boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90""
------=_NextPart_000_003F_01CE98CE.6E826F90
".Replace ("\r\n", "\n");

using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) {
var parser = new MimeParser (stream, MimeFormat.Entity);
var message = await parser.ParseMessageAsync ();

Assert.That (message.Body, Is.InstanceOf<Multipart> (), "Expected top-level to be a multipart");
var multipart = (Multipart) message.Body;
Assert.That (multipart.Count, Is.EqualTo (1));
Assert.That (multipart[0], Is.InstanceOf<TextPart> (), "Expected first child of the multipart to be text/plain");
var body = (TextPart) multipart[0];

Assert.That (body.Text, Is.EqualTo (string.Empty));
}

using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) {
var parser = new MimeParser (stream, MimeFormat.Entity);
var message = await parser.ParseMessageAsync ();

Assert.That (message.Body, Is.InstanceOf<Multipart> (), "Expected top-level to be a multipart");
var multipart = (Multipart) message.Body;
Assert.That (multipart.Count, Is.EqualTo (1));
Assert.That (multipart[0], Is.InstanceOf<TextPart> (), "Expected first child of the multipart to be text/plain");
var body = (TextPart) multipart[0];

Assert.That (body.Text, Is.EqualTo (string.Empty));
}
}

[Test]
public void TestMultipartBoundaryWithoutTrailingNewline ()
{
Expand Down

0 comments on commit 654f318

Please sign in to comment.