Skip to content

Commit

Permalink
Fixed Multipart to properly ensure the epilogue ends w/ a new-line wh…
Browse files Browse the repository at this point in the history
…en EnsureNewLine is true

Partial fix for issue #499
  • Loading branch information
jstedfast committed Aug 21, 2019
1 parent d323cb9 commit ee8e536
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 8 deletions.
16 changes: 8 additions & 8 deletions MimeKit/Multipart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -356,10 +356,10 @@ internal static string FoldPreambleOrEpilogue (FormatOptions options, string tex
return builder.ToString ();
}

static void WriteBytes (FormatOptions options, Stream stream, byte[] bytes, CancellationToken cancellationToken)
static void WriteBytes (FormatOptions options, Stream stream, byte[] bytes, bool ensureNewLine, CancellationToken cancellationToken)
{
var cancellable = stream as ICancellableStream;
var filter = options.CreateNewLineFilter ();
var filter = options.CreateNewLineFilter (ensureNewLine);
int index, length;

var output = filter.Flush (bytes, 0, bytes.Length, out index, out length);
Expand All @@ -372,9 +372,9 @@ static void WriteBytes (FormatOptions options, Stream stream, byte[] bytes, Canc
}
}

static Task WriteBytesAsync (FormatOptions options, Stream stream, byte[] bytes, CancellationToken cancellationToken)
static Task WriteBytesAsync (FormatOptions options, Stream stream, byte[] bytes, bool ensureNewLine, CancellationToken cancellationToken)
{
var filter = options.CreateNewLineFilter ();
var filter = options.CreateNewLineFilter (ensureNewLine);
int index, length;

var output = filter.Flush (bytes, 0, bytes.Length, out index, out length);
Expand Down Expand Up @@ -444,7 +444,7 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength =
var cancellable = stream as ICancellableStream;

if (RawPreamble != null && RawPreamble.Length > 0)
WriteBytes (options, stream, RawPreamble, cancellationToken);
WriteBytes (options, stream, RawPreamble, true, cancellationToken);

var boundary = Encoding.ASCII.GetBytes ("--" + Boundary + "--");

Expand Down Expand Up @@ -513,7 +513,7 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength =
}

if (RawEpilogue != null && RawEpilogue.Length > 0)
WriteBytes (options, stream, RawEpilogue, cancellationToken);
WriteBytes (options, stream, RawEpilogue, EnsureNewLine, cancellationToken);
}

/// <summary>
Expand Down Expand Up @@ -555,7 +555,7 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength =
}

if (RawPreamble != null && RawPreamble.Length > 0)
await WriteBytesAsync (options, stream, RawPreamble, cancellationToken).ConfigureAwait (false);
await WriteBytesAsync (options, stream, RawPreamble, true, cancellationToken).ConfigureAwait (false);

var boundary = Encoding.ASCII.GetBytes ("--" + Boundary + "--");

Expand Down Expand Up @@ -589,7 +589,7 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength =
await stream.WriteAsync (options.NewLineBytes, 0, options.NewLineBytes.Length, cancellationToken).ConfigureAwait (false);

if (RawEpilogue != null && RawEpilogue.Length > 0)
await WriteBytesAsync (options, stream, RawEpilogue, cancellationToken).ConfigureAwait (false);
await WriteBytesAsync (options, stream, RawEpilogue, EnsureNewLine, cancellationToken).ConfigureAwait (false);
}

#region ICollection implementation
Expand Down
79 changes: 79 additions & 0 deletions UnitTests/MimeMessageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,85 @@ ENCODING mime
}
}

[Test]
public async Task TestReserializationEpilogue ()
{
string rawMessageText = @"From: Example Test <[email protected]>
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary=""simple boundary""
This is the preamble.
--simple boundary
Content-TypeS: text/plain
This is a test.
--simple boundary
Content-Type: text/plain
Content-Disposition: attachment
Content-Transfer-Encoding: 7bit
Another test.
--simple boundary--
This is the epilogue.".Replace ("\r\n", "\n");

using (var source = new MemoryStream (Encoding.UTF8.GetBytes (rawMessageText))) {
var parser = new MimeParser (source, MimeFormat.Default);
var message = parser.ParseMessage ();

using (var serialized = new MemoryStream ()) {
var options = FormatOptions.Default.Clone ();
options.NewLineFormat = NewLineFormat.Unix;

message.WriteTo (options, serialized);

var result = Encoding.UTF8.GetString (serialized.ToArray ());

Assert.AreEqual (rawMessageText, result, "Reserialized message is not identical to the original.");
}

using (var serialized = new MemoryStream ()) {
var options = FormatOptions.Default.Clone ();
options.NewLineFormat = NewLineFormat.Unix;

await message.WriteToAsync (options, serialized);

var result = Encoding.UTF8.GetString (serialized.ToArray ());

Assert.AreEqual (rawMessageText, result, "Reserialized (async) message is not identical to the original.");
}

using (var serialized = new MemoryStream ()) {
var options = FormatOptions.Default.Clone ();
options.NewLineFormat = NewLineFormat.Unix;
options.EnsureNewLine = true;

message.WriteTo (options, serialized);

var result = Encoding.UTF8.GetString (serialized.ToArray ());

Assert.AreEqual (rawMessageText + "\n", result, "Reserialized message is not identical to the original (EnsureNewLine).");
}

using (var serialized = new MemoryStream ()) {
var options = FormatOptions.Default.Clone ();
options.NewLineFormat = NewLineFormat.Unix;
options.EnsureNewLine = true;

await message.WriteToAsync (options, serialized);

var result = Encoding.UTF8.GetString (serialized.ToArray ());

Assert.AreEqual (rawMessageText + "\n", result, "Reserialized (async) message is not identical to the original (EnsureNewLine).");
}
}
}

[Test]
public void TestMailMessageToMimeMessage ()
{
Expand Down

0 comments on commit ee8e536

Please sign in to comment.