Skip to content

Commit 08b3fc5

Browse files
committed
Merge branch 'release/4.1.0'
2 parents ff2c7f7 + a6d3a0f commit 08b3fc5

9 files changed

Lines changed: 124 additions & 56 deletions

Source/HttpMultipartParser.UnitTests/ParserScenarios/MultipleFilesWithNoName.cs renamed to Source/HttpMultipartParser.UnitTests/ParserScenarios/MultipleFilesWithEmptyName.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace HttpMultipartParser.UnitTests.ParserScenarios
1010
/// <summary>
1111
/// Test case for multiple files with no name.
1212
/// </summary>
13-
public class MultipleFilesWithNoName
13+
public class MultipleFilesWithEmptyName
1414
{
1515
private static readonly string MultipleFilesSameName_testData = TestUtil.TrimAllLines(@"--boundry
1616
Content-Disposition: form-data; name="""";filename=""file1.txt"";
@@ -39,7 +39,7 @@ This is text file 3 1234567890
3939
}
4040
);
4141

42-
public MultipleFilesWithNoName()
42+
public MultipleFilesWithEmptyName()
4343
{
4444
}
4545

@@ -50,7 +50,7 @@ public MultipleFilesWithNoName()
5050
[Fact]
5151
public void MultipleFilesWithNoNameTest()
5252
{
53-
using (Stream stream = TestUtil.StringToStream(MultipleFilesSameName_testData, Encoding.UTF8))
53+
using (Stream stream = TestUtil.StringToStream(_testCase.Request, Encoding.UTF8))
5454
{
5555
var parser = MultipartFormDataParser.Parse(stream, "boundry", Encoding.UTF8, 16);
5656
Assert.True(_testCase.Validate(parser));
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Xunit;
7+
8+
namespace HttpMultipartParser.UnitTests.ParserScenarios
9+
{
10+
/// <summary>
11+
/// Test case for multiple files with omitted name.
12+
/// </summary>
13+
public class MultipleFilesWithOmittedName
14+
{
15+
private static readonly string MultipleFilesWithOmittedName_testData = TestUtil.TrimAllLines(@"--boundry
16+
Content-Disposition: form-data; filename=""file1.txt"";
17+
Content-Type: text/plain
18+
19+
THIS IS TEXT FILE 1
20+
--boundry
21+
Content-Disposition: form-data; filename=""file2.txt"";
22+
Content-Type: text/plain
23+
24+
THIS IS TEXT FILE 2 !!!
25+
--boundry
26+
Content-Disposition: form-data; filename=""file3.txt"";
27+
Content-Type: text/plain
28+
29+
This is text file 3 1234567890
30+
--boundry--");
31+
32+
private static readonly TestData _testCase = new TestData(
33+
MultipleFilesWithOmittedName_testData,
34+
Enumerable.Empty<ParameterPart>().ToList(),
35+
new List<FilePart> {
36+
new FilePart( null, "file1.txt", TestUtil.StringToStreamNoBom("THIS IS TEXT FILE 1")),
37+
new FilePart( null, "file2.txt", TestUtil.StringToStreamNoBom("THIS IS TEXT FILE 2 !!!")),
38+
new FilePart( null, "file3.txt", TestUtil.StringToStreamNoBom("This is text file 3 1234567890"))
39+
}
40+
);
41+
42+
public MultipleFilesWithOmittedName()
43+
{
44+
}
45+
46+
/// <summary>
47+
/// Checks that multiple files don't get in the way of parsing each other
48+
/// and that everything parses correctly.
49+
/// </summary>
50+
[Fact]
51+
public void MultipleFilesWithOmittedNameTest()
52+
{
53+
using (Stream stream = TestUtil.StringToStream(_testCase.Request, Encoding.UTF8))
54+
{
55+
var parser = MultipartFormDataParser.Parse(stream, "boundry", Encoding.UTF8, 16);
56+
Assert.True(_testCase.Validate(parser));
57+
}
58+
}
59+
60+
[Fact]
61+
public async Task MultipleFilesWithOmittedNameAsync()
62+
{
63+
using (Stream stream = TestUtil.StringToStream(_testCase.Request, Encoding.UTF8))
64+
{
65+
var parser = await MultipartFormDataParser.ParseAsync(stream, "boundry", Encoding.UTF8, 16).ConfigureAwait(false);
66+
Assert.True(_testCase.Validate(parser));
67+
}
68+
}
69+
}
70+
}

Source/HttpMultipartParser.UnitTests/ParserScenarios/MultipleFilesWithSameName.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public MultipleFilesWithSameName()
5050
[Fact]
5151
public void MultipleFilesWithSameNameTest()
5252
{
53-
using (Stream stream = TestUtil.StringToStream(MultipleFilesSameName_testData, Encoding.UTF8))
53+
using (Stream stream = TestUtil.StringToStream(_testCase.Request, Encoding.UTF8))
5454
{
5555
var parser = MultipartFormDataParser.Parse(stream, "boundry", Encoding.UTF8, 16);
5656
Assert.True(_testCase.Validate(parser));

Source/HttpMultipartParser/BinaryStreamStack.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,7 @@ public void Push(byte[] data)
142142
/// </param>
143143
public void Push(byte[] data, int offset, int count)
144144
{
145-
var stream = Utilities.MemoryStreamManager.GetStream();
146-
stream.Write(data, offset, count);
147-
stream.Position = 0;
148-
145+
var stream = Utilities.MemoryStreamManager.GetStream($"{typeof(BinaryStreamStack).FullName}.{nameof(Push)}", data, offset, count);
149146
streams.Push(new BinaryReader(stream, CurrentEncoding));
150147
}
151148

@@ -306,7 +303,7 @@ public byte[] ReadByteLine(out bool hitStreamEnd)
306303
byte[] ignore = CurrentEncoding.GetBytes(new[] { '\r' });
307304
byte[] search = CurrentEncoding.GetBytes(new[] { '\n' });
308305
int searchPos = 0;
309-
using (var builder = Utilities.MemoryStreamManager.GetStream())
306+
using (var builder = Utilities.MemoryStreamManager.GetStream($"{typeof(BinaryStreamStack).FullName}.{nameof(ReadByteLine)}"))
310307
{
311308
while (true)
312309
{

Source/HttpMultipartParser/HttpMultipartParser.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
<ItemGroup>
4040
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
41-
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="1.3.2" />
41+
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="1.3.3" />
4242
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
4343
<PackageReference Include="System.Buffers" Version="4.5.0" />
4444
</ItemGroup>

Source/HttpMultipartParser/MultipartFormDataParser.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ private void ParseStream(Stream stream, string boundary, Encoding encoding, int
562562
if (partNumber == 0)
563563
{
564564
// create file with first partNo
565-
Files.Add(new FilePart(name, fileName, Utilities.MemoryStreamManager.GetStream(), type, disposition));
565+
Files.Add(new FilePart(name, fileName, Utilities.MemoryStreamManager.GetStream($"{typeof(MultipartFormDataParser).FullName}.{nameof(ParseStream)}"), type, disposition));
566566
}
567567

568568
Files[Files.Count - 1].Data.Write(buffer, 0, bytes);
@@ -607,7 +607,7 @@ private async Task ParseStreamAsync(Stream stream, string boundary, Encoding enc
607607
if (partNumber == 0)
608608
{
609609
// create file with first partNo
610-
Files.Add(new FilePart(name, fileName, Utilities.MemoryStreamManager.GetStream(), type, disposition));
610+
Files.Add(new FilePart(name, fileName, Utilities.MemoryStreamManager.GetStream($"{typeof(MultipartFormDataParser).FullName}.{nameof(ParseStreamAsync)}"), type, disposition));
611611
}
612612

613613
Files[Files.Count - 1].Data.Write(buffer, 0, bytes);

Source/HttpMultipartParser/RebufferableBinaryReader.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ public int Read(char[] buffer, int index, int count)
265265
/// </returns>
266266
public byte[] ReadByteLine()
267267
{
268-
using (var builder = Utilities.MemoryStreamManager.GetStream())
268+
using (var builder = Utilities.MemoryStreamManager.GetStream($"{typeof(RebufferableBinaryReader).FullName}.{nameof(ReadByteLine)}"))
269269
{
270270
while (true)
271271
{
@@ -424,7 +424,7 @@ public async Task<int> ReadAsync(char[] buffer, int index, int count, Cancellati
424424
/// </returns>
425425
public async Task<byte[]> ReadByteLineAsync(CancellationToken cancellationToken = default)
426426
{
427-
using (var builder = Utilities.MemoryStreamManager.GetStream())
427+
using (var builder = Utilities.MemoryStreamManager.GetStream($"{typeof(RebufferableBinaryReader).FullName}.{nameof(ReadByteLineAsync)}"))
428428
{
429429
while (true)
430430
{

Source/HttpMultipartParser/StreamingMultipartFormDataParser.cs

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ private async Task ParseAsync(RebufferableBinaryReader reader, CancellationToken
545545
/// Parses a section of the stream that is known to be file data.
546546
/// </summary>
547547
/// <param name="parameters">
548-
/// The header parameters of this file, expects "name" and "filename" to be valid keys.
548+
/// The header parameters of this file.
549549
/// </param>
550550
/// <param name="reader">
551551
/// The StreamReader to read the data from.
@@ -554,17 +554,17 @@ private void ParseFilePart(Dictionary<string, string> parameters, RebufferableBi
554554
{
555555
int partNumber = 0; // begins count parts of file from 0
556556

557-
string name = parameters["name"];
558-
string filename = parameters["filename"];
559-
557+
// Read the parameters
558+
parameters.TryGetValue("name", out string name);
559+
parameters.TryGetValue("filename", out string filename);
560560
parameters.TryGetValue("content-type", out string contentType);
561-
if (contentType == null) contentType = "text/plain";
562-
563561
parameters.TryGetValue("content-disposition", out string contentDisposition);
562+
563+
// Default values if expected parameters are missing
564+
if (contentType == null) contentType = "text/plain";
564565
if (contentDisposition == null) contentDisposition = "form-data";
565566

566-
// We want to create a stream and fill it with the data from the
567-
// file.
567+
// We want to create a stream and fill it with the data from the file.
568568
var curBuffer = Utilities.ArrayPool.Rent(BinaryBufferSize);
569569
var prevBuffer = Utilities.ArrayPool.Rent(BinaryBufferSize);
570570
var fullBuffer = Utilities.ArrayPool.Rent(BinaryBufferSize * 2);
@@ -655,7 +655,7 @@ private void ParseFilePart(Dictionary<string, string> parameters, RebufferableBi
655655
// We also want to chop off the newline that is inserted by the protocl.
656656
// We can do this by reducing endPos by the length of newline in this environment
657657
// and encoding
658-
FileHandler(name, filename, contentType, contentDisposition, fullBuffer, endPos - bufferNewlineLength, partNumber);
658+
FileHandler(name, filename, contentType, contentDisposition, fullBuffer, endPos - bufferNewlineLength, partNumber++);
659659

660660
int writeBackOffset = endPos + endPosLength + boundaryNewlineOffset;
661661
int writeBackAmount = (prevLength + curLength) - writeBackOffset;
@@ -665,8 +665,7 @@ private void ParseFilePart(Dictionary<string, string> parameters, RebufferableBi
665665
}
666666

667667
// No end, consume the entire previous buffer
668-
FileHandler(name, filename, contentType, contentDisposition, prevBuffer, prevLength, partNumber);
669-
partNumber++; // increase part counter
668+
FileHandler(name, filename, contentType, contentDisposition, prevBuffer, prevLength, partNumber++);
670669

671670
// Now we want to swap the two buffers, we don't care
672671
// what happens to the data from prevBuffer so we set
@@ -706,13 +705,14 @@ private async Task ParseFilePartAsync(Dictionary<string, string> parameters, Reb
706705
{
707706
int partNumber = 0; // begins count parts of file from 0
708707

709-
string name = parameters["name"];
710-
string filename = parameters["filename"];
711-
708+
// Read the parameters
709+
parameters.TryGetValue("name", out string name);
710+
parameters.TryGetValue("filename", out string filename);
712711
parameters.TryGetValue("content-type", out string contentType);
713-
if (contentType == null) contentType = "text/plain";
714-
715712
parameters.TryGetValue("content-disposition", out string contentDisposition);
713+
714+
// Default values if expected parameters are missing
715+
if (contentType == null) contentType = "text/plain";
716716
if (contentDisposition == null) contentDisposition = "form-data";
717717

718718
// We want to create a stream and fill it with the data from the
@@ -807,7 +807,7 @@ private async Task ParseFilePartAsync(Dictionary<string, string> parameters, Reb
807807
// We also want to chop off the newline that is inserted by the protocl.
808808
// We can do this by reducing endPos by the length of newline in this environment
809809
// and encoding
810-
FileHandler(name, filename, contentType, contentDisposition, fullBuffer, endPos - bufferNewlineLength, partNumber);
810+
FileHandler(name, filename, contentType, contentDisposition, fullBuffer, endPos - bufferNewlineLength, partNumber++);
811811

812812
int writeBackOffset = endPos + endPosLength + boundaryNewlineOffset;
813813
int writeBackAmount = (prevLength + curLength) - writeBackOffset;
@@ -817,8 +817,7 @@ private async Task ParseFilePartAsync(Dictionary<string, string> parameters, Reb
817817
}
818818

819819
// No end, consume the entire previous buffer
820-
FileHandler(name, filename, contentType, contentDisposition, prevBuffer, prevLength, partNumber);
821-
partNumber++; // increase part counter
820+
FileHandler(name, filename, contentType, contentDisposition, prevBuffer, prevLength, partNumber++);
822821

823822
// Now we want to swap the two buffers, we don't care
824823
// what happens to the data from prevBuffer so we set
@@ -979,16 +978,17 @@ private void ParseSection(RebufferableBinaryReader reader)
979978
throw new MultipartParseException("Unexpected end of section");
980979
}
981980

982-
// This line parses the header values into a set of key/value pairs. For example:
983-
// Content-Disposition: form-data; name="textdata"
984-
// ["content-disposition"] = "form-data"
985-
// ["name"] = "textdata"
986-
// Content-Disposition: form-data; name="file"; filename="data.txt"
987-
// ["content-disposition"] = "form-data"
988-
// ["name"] = "file"
989-
// ["filename"] = "data.txt"
990-
// Content-Type: text/plain
991-
// ["content-type"] = "text/plain"
981+
// This line parses the header values into a set of key/value pairs.
982+
// For example:
983+
// Content-Disposition: form-data; name="textdata"
984+
// ["content-disposition"] = "form-data"
985+
// ["name"] = "textdata"
986+
// Content-Disposition: form-data; name="file"; filename="data.txt"
987+
// ["content-disposition"] = "form-data"
988+
// ["name"] = "file"
989+
// ["filename"] = "data.txt"
990+
// Content-Type: text/plain
991+
// ["content-type"] = "text/plain"
992992
Dictionary<string, string> values = SplitBySemicolonIgnoringSemicolonsInQuotes(line)
993993
.Select(x => x.Split(new[] { ':', '=' }, 2))
994994

@@ -1072,16 +1072,17 @@ private async Task ParseSectionAsync(RebufferableBinaryReader reader, Cancellati
10721072
throw new MultipartParseException("Unexpected end of section");
10731073
}
10741074

1075-
// This line parses the header values into a set of key/value pairs. For example:
1076-
// Content-Disposition: form-data; name="textdata"
1077-
// ["content-disposition"] = "form-data"
1078-
// ["name"] = "textdata"
1079-
// Content-Disposition: form-data; name="file"; filename="data.txt"
1080-
// ["content-disposition"] = "form-data"
1081-
// ["name"] = "file"
1082-
// ["filename"] = "data.txt"
1083-
// Content-Type: text/plain
1084-
// ["content-type"] = "text/plain"
1075+
// This line parses the header values into a set of key/value pairs.
1076+
// For example:
1077+
// Content-Disposition: form-data; name="textdata"
1078+
// ["content-disposition"] = "form-data"
1079+
// ["name"] = "textdata"
1080+
// Content-Disposition: form-data; name="file"; filename="data.txt"
1081+
// ["content-disposition"] = "form-data"
1082+
// ["name"] = "file"
1083+
// ["filename"] = "data.txt"
1084+
// Content-Type: text/plain
1085+
// ["content-type"] = "text/plain"
10851086
Dictionary<string, string> values = SplitBySemicolonIgnoringSemicolonsInQuotes(line)
10861087
.Select(x => x.Split(new[] { ':', '=' }, 2))
10871088

build.cake

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
#tool dotnet:?package=BenchmarkDotNet.Tool&version=0.12.0
66

77
// Install tools.
8-
#tool nuget:?package=GitVersion.CommandLine&version=5.1.3
9-
#tool nuget:?package=GitReleaseManager&version=0.10.3
8+
#tool nuget:?package=GitVersion.CommandLine&version=5.2.4
9+
#tool nuget:?package=GitReleaseManager&version=0.11.0
1010
#tool nuget:?package=OpenCover&version=4.7.922
11-
#tool nuget:?package=ReportGenerator&version=4.5.0
11+
#tool nuget:?package=ReportGenerator&version=4.5.2
1212
#tool nuget:?package=coveralls.io&version=1.4.2
1313
#tool nuget:?package=xunit.runner.console&version=2.4.1
1414

0 commit comments

Comments
 (0)