Skip to content

Commit 4e83b57

Browse files
committed
Merge branch 'feature/extra_blank_lines' into develop
2 parents 5b9a919 + 1e3da4b commit 4e83b57

File tree

2 files changed

+94
-2
lines changed

2 files changed

+94
-2
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Text;
4+
using System.Threading.Tasks;
5+
using Xunit;
6+
7+
namespace HttpMultipartParser.UnitTests.ParserScenarios
8+
{
9+
public class BlankLinesBeforeFirstBoundary
10+
{
11+
private static readonly string _testData = TestUtil.TrimAllLines(
12+
@"--boundary
13+
Content-Disposition: form-data; name=""text""
14+
15+
textdata
16+
--boundary--"
17+
);
18+
19+
// This test case has a few blank lines before the first boundary marker
20+
// This unusual scenario is described in GH-116
21+
// https://github.com/Http-Multipart-Data-Parser/Http-Multipart-Data-Parser/issues/116
22+
private static readonly TestData _testCase = new TestData(
23+
$"\n\n\n{_testData}", // Intentionally add a few blank lines before the data. These blank lines should be ignored by the parser when attempting to detect the boundary marker
24+
new List<ParameterPart> {
25+
new ParameterPart("text", "textdata"),
26+
},
27+
new List<FilePart>()
28+
);
29+
30+
public BlankLinesBeforeFirstBoundary()
31+
{
32+
foreach (var filePart in _testCase.ExpectedFileData)
33+
{
34+
filePart.Data.Position = 0;
35+
}
36+
}
37+
38+
/// <summary>
39+
/// Tests for correct detection of the boundary in the input stream.
40+
/// </summary>
41+
[Fact]
42+
public void CanAutoDetectBoundary()
43+
{
44+
using (Stream stream = TestUtil.StringToStream(_testCase.Request, Encoding.UTF8))
45+
{
46+
var parser = MultipartFormDataParser.Parse(stream);
47+
Assert.True(_testCase.Validate(parser));
48+
}
49+
}
50+
51+
/// <summary>
52+
/// Tests for correct detection of the boundary in the input stream.
53+
/// </summary>
54+
[Fact]
55+
public async Task CanAutoDetectBoundaryAsync()
56+
{
57+
using (Stream stream = TestUtil.StringToStream(_testCase.Request, Encoding.UTF8))
58+
{
59+
var parser = await MultipartFormDataParser.ParseAsync(stream, Encoding.UTF8).ConfigureAwait(false);
60+
Assert.True(_testCase.Validate(parser));
61+
}
62+
}
63+
}
64+
}

Source/HttpMultipartParser/StreamingBinaryMultipartFormDataParser.cs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,11 @@ public async Task RunAsync(CancellationToken cancellationToken = default)
244244
/// current position of the reader is the start of the file and therefore
245245
/// the beginning of the boundary.
246246
/// </summary>
247+
/// <remarks>
248+
/// As of version 8.2.0 (released in June 2023), we ignore blank lines at the
249+
/// start of the stream. In previous version, an exception was thrown if any
250+
/// blank line was present before the boundary marker.
251+
/// </remarks>
247252
/// <param name="reader">
248253
/// The binary reader to parse.
249254
/// </param>
@@ -254,7 +259,16 @@ private static string DetectBoundary(RebufferableBinaryReader reader)
254259
{
255260
// Presumably the boundary is --|||||||||||||| where -- is the stuff added on to
256261
// the front as per the protocol and ||||||||||||| is the part we care about.
257-
var line = reader.ReadLine();
262+
263+
// The following loop ignores blank lines that may be present before the first line of the form.
264+
// It's highly unusual to find blank lines at the start of the data but it's a possible scenario described in GH-116.
265+
// Please note that we intentionally do NOT check for "string.IsNullOrEmpty(line)" because NULL does
266+
// not indicate a blank line. It indicates that we have reached the end of the stream.
267+
var line = string.Empty;
268+
while (line == string.Empty)
269+
{
270+
line = reader.ReadLine();
271+
}
258272

259273
// The line must not be empty and must starts with "--".
260274
if (string.IsNullOrEmpty(line)) throw new MultipartParseException("Unable to determine boundary: either the stream is empty or we reached the end of the stream");
@@ -283,6 +297,11 @@ private static string DetectBoundary(RebufferableBinaryReader reader)
283297
/// current position of the reader is the start of the file and therefore
284298
/// the beginning of the boundary.
285299
/// </summary>
300+
/// <remarks>
301+
/// As of version 8.2.0 (released in June 2023), we ignore blank lines at the
302+
/// start of the stream. In previous version, an exception was thrown if any
303+
/// blank line was present before the boundary marker.
304+
/// </remarks>
286305
/// <param name="reader">
287306
/// The binary reader to parse.
288307
/// </param>
@@ -296,7 +315,16 @@ private static async Task<string> DetectBoundaryAsync(RebufferableBinaryReader r
296315
{
297316
// Presumably the boundary is --|||||||||||||| where -- is the stuff added on to
298317
// the front as per the protocol and ||||||||||||| is the part we care about.
299-
var line = await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false);
318+
319+
// The following loop ignores blank lines that may be present before the first line of the form.
320+
// It's highly unusual to find blank lines at the start of the data but it's a possible scenario described in GH-116.
321+
// Please note that we intentionally do NOT check for "string.IsNullOrEmpty(line)" because NULL does
322+
// not indicate a blank line. It indicates that we have reached the end of the stream.
323+
var line = string.Empty;
324+
while (line == string.Empty)
325+
{
326+
line = await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false);
327+
}
300328

301329
// The line must not be empty and must starts with "--".
302330
if (string.IsNullOrEmpty(line)) throw new MultipartParseException("Unable to determine boundary: either the stream is empty or we reached the end of the stream");

0 commit comments

Comments
 (0)