Skip to content

Commit ff2c7f7

Browse files
committed
Merge branch 'release/4.0.0'
2 parents be17ac8 + 6f99d00 commit ff2c7f7

File tree

12 files changed

+260
-86
lines changed

12 files changed

+260
-86
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ StyleCopReport.xml
7272
*_p.c
7373
*_h.h
7474
*.ilk
75-
*.meta
7675
*.obj
7776
*.iobj
7877
*.pch

GitReleaseManager.yaml

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,38 @@ create:
44
footer-content: You can download this release from [nuget.org](https://www.nuget.org/packages/Http-Multipart-Data-Parser/{milestone})
55
footer-includes-milestone: true
66
milestone-replace-text: '{milestone}'
7+
close:
8+
use-issue-comments: true
9+
issue-comment: |-
10+
:tada: This issue has been resolved in version {milestone} :tada:
11+
12+
The release is available on:
13+
14+
- [GitHub Release](https://github.com/{owner}/{repository}/releases/tag/{milestone})
15+
- [NuGet Package](https://www.nuget.org/packages/Http-Multipart-Data-Parser/{milestone})
16+
17+
Your **[GitReleaseManager](https://github.com/GitTools/GitReleaseManager)** bot :package::rocket:
718
export:
819
include-created-date-in-title: true
920
created-date-string-format: MMMM dd, yyyy
1021
perform-regex-removal: true
1122
regex-text: '### Where to get it(\r\n)*You can .*\)'
1223
multiline-regex: true
1324
issue-labels-include:
14-
- Breaking Change
15-
- Bug
16-
- New Feature
17-
- Improvement
18-
- Documentation
25+
- Breaking Change
26+
- Bug
27+
- New Feature
28+
- Improvement
29+
- Documentation
30+
- Security
1931
issue-labels-exclude:
20-
- Question
21-
- Duplicate
22-
- Invalid
23-
- Wontfix
32+
- Question
33+
- Duplicate
34+
- Invalid
35+
- Wontfix
36+
- Build
37+
- Internal Refactoring
2438
issue-labels-alias:
25-
- name: Documentation
26-
header: Documentation
27-
plural: Documentation
39+
- name: Documentation
40+
header: Documentation
41+
plural: Documentation

GitVersion.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
mode: ContinuousDelivery
22
branches:
3+
feature:
4+
regex: feature(s)?[/-]
5+
mode: ContinuousDeployment
36
develop:
47
regex: dev(elop)?(ment)?$
58
mode: ContinuousDeployment

Source/HttpMultipartParser.UnitTests/HttpMultipartParser.UnitTests.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>net461;net472;netcoreapp2.1</TargetFrameworks>
4+
<TargetFrameworks>net461;net472;netcoreapp3.1</TargetFrameworks>
55
<AssemblyName>HttpMultipartParser.UnitTests</AssemblyName>
66
<RootNamespace>HttpMultipartParser.UnitTests</RootNamespace>
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
10+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
1111
<PackageReference Include="xunit" Version="2.4.1" />
1212
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
1313
<PrivateAssets>all</PrivateAssets>
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 no name.
12+
/// </summary>
13+
public class MultipleFilesWithNoName
14+
{
15+
private static readonly string MultipleFilesSameName_testData = TestUtil.TrimAllLines(@"--boundry
16+
Content-Disposition: form-data; name="""";filename=""file1.txt"";
17+
Content-Type: text/plain
18+
19+
THIS IS TEXT FILE 1
20+
--boundry
21+
Content-Disposition: form-data; name="""";filename=""file2.txt"";
22+
Content-Type: text/plain
23+
24+
THIS IS TEXT FILE 2 !!!
25+
--boundry
26+
Content-Disposition: form-data; name="""";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+
MultipleFilesSameName_testData,
34+
Enumerable.Empty<ParameterPart>().ToList(),
35+
new List<FilePart> {
36+
new FilePart( "", "file1.txt", TestUtil.StringToStreamNoBom("THIS IS TEXT FILE 1")),
37+
new FilePart( "", "file2.txt", TestUtil.StringToStreamNoBom("THIS IS TEXT FILE 2 !!!")),
38+
new FilePart( "", "file3.txt", TestUtil.StringToStreamNoBom("This is text file 3 1234567890"))
39+
}
40+
);
41+
42+
public MultipleFilesWithNoName()
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 MultipleFilesWithNoNameTest()
52+
{
53+
using (Stream stream = TestUtil.StringToStream(MultipleFilesSameName_testData, 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 MultipleFilesWithNoNameAsync()
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+
}
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 same name.
12+
/// </summary>
13+
public class MultipleFilesWithSameName
14+
{
15+
private static readonly string MultipleFilesSameName_testData = TestUtil.TrimAllLines(@"--boundry
16+
Content-Disposition: form-data; name=""file1.txt"";filename=""file1.txt"";
17+
Content-Type: text/plain
18+
19+
THIS IS TEXT FILE 1
20+
--boundry
21+
Content-Disposition: form-data; name=""file2.txt"";filename=""file2.txt"";
22+
Content-Type: text/plain
23+
24+
THIS IS TEXT FILE 2 !!!
25+
--boundry
26+
Content-Disposition: form-data; name=""file2.txt"";filename=""file2.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+
MultipleFilesSameName_testData,
34+
Enumerable.Empty<ParameterPart>().ToList(),
35+
new List<FilePart> {
36+
new FilePart( "file1.txt", "file1.txt", TestUtil.StringToStreamNoBom("THIS IS TEXT FILE 1")),
37+
new FilePart( "file2.txt", "file2.txt", TestUtil.StringToStreamNoBom("THIS IS TEXT FILE 2 !!!")),
38+
new FilePart( "file2.txt", "file2.txt", TestUtil.StringToStreamNoBom("This is text file 3 1234567890"))
39+
}
40+
);
41+
42+
public MultipleFilesWithSameName()
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 MultipleFilesWithSameNameTest()
52+
{
53+
using (Stream stream = TestUtil.StringToStream(MultipleFilesSameName_testData, 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 MultipleFilesWithSameNameTestAsync()
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/TestData.cs

Lines changed: 60 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,20 @@ public TestData(
5959
/// </returns>
6060
public bool Validate(MultipartFormDataParser parser)
6161
{
62-
// Deal with all the parameters who are only expected to have one value.
62+
var result = ValidateSingleValueParameters(parser);
63+
result &= ValidateMultipleValuesParameters(parser);
64+
result &= ValidateFiles(parser);
65+
66+
return result;
67+
}
68+
69+
#endregion
70+
71+
#region Private methods
72+
73+
private bool ValidateSingleValueParameters(MultipartFormDataParser parser)
74+
{
75+
// Deal with the parameters that are expected to have only one value.
6376
var expectedParametersWithSingleValue = ExpectedParams
6477
.GroupBy(p => p.Name)
6578
.Where(g => g.Count() == 1)
@@ -86,10 +99,15 @@ public bool Validate(MultipartFormDataParser parser)
8699
}
87100
}
88101

89-
// Deal with the parameters who are expected to have more then one value
102+
return true;
103+
}
104+
105+
private bool ValidateMultipleValuesParameters(MultipartFormDataParser parser)
106+
{
107+
// Deal with the parameters that are expected to have more than one value
90108
var expectedParametersWithMultiValues = ExpectedParams
91-
.GroupBy(p => p.Name)
92-
.Where(a => a.Count() > 1);
109+
.GroupBy(p => p.Name)
110+
.Where(a => a.Count() > 1);
93111

94112
foreach (var expectedParameters in expectedParametersWithMultiValues)
95113
{
@@ -107,60 +125,48 @@ public bool Validate(MultipartFormDataParser parser)
107125
}
108126
}
109127

110-
// Validate files
111-
foreach (var filePart in ExpectedFileData)
128+
return true;
129+
}
130+
131+
private bool ValidateFiles(MultipartFormDataParser parser)
132+
{
133+
// Validate files.
134+
135+
// PLEASE NOTE: we can't rely on the name and/or the file name because they are not guaranteed to be unique.
136+
// Therefore we assume that the first expected file should match the first actual file,
137+
// the second expected file should match the second actual files, etc.
138+
139+
if (ExpectedFileData.Count != parser.Files.Count) return false;
140+
141+
for (int i = 0; i < ExpectedFileData.Count; i++)
112142
{
113-
var foundPairMatch = false;
114-
foreach (var file in parser.Files)
143+
var expectedFile = ExpectedFileData[i];
144+
var actualFile = parser.Files[i];
145+
146+
if (expectedFile.Name != actualFile.Name) return false;
147+
if (expectedFile.FileName != actualFile.FileName) return false;
148+
if (expectedFile.ContentType != actualFile.ContentType) return false;
149+
if (expectedFile.ContentDisposition != actualFile.ContentDisposition) return false;
150+
151+
// Read the data from the files and see if it's the same
152+
if (expectedFile.Data.CanSeek && expectedFile.Data.Position != 0) expectedFile.Data.Position = 0;
153+
if (actualFile.Data.CanSeek && actualFile.Data.Position != 0) actualFile.Data.Position = 0;
154+
155+
string expectedFileData;
156+
// The last boolean parameter MUST be set to true: it ensures the stream is left open
157+
using (var reader = new StreamReader(expectedFile.Data, Encoding.UTF8, false, 1024, true))
158+
{
159+
expectedFileData = reader.ReadToEnd();
160+
}
161+
162+
string actualFileData;
163+
// The last boolean parameter MUST be set to true: it ensures the stream is left open
164+
using (var reader = new StreamReader(actualFile.Data, Encoding.UTF8, false, 1024, true))
115165
{
116-
if (filePart.Name == file.Name)
117-
{
118-
foundPairMatch = true;
119-
120-
FilePart expectedFile = filePart;
121-
FilePart actualFile = file;
122-
123-
if (expectedFile.Name != actualFile.Name || expectedFile.FileName != actualFile.FileName)
124-
{
125-
return false;
126-
}
127-
128-
if (expectedFile.ContentType != actualFile.ContentType ||
129-
expectedFile.ContentDisposition != actualFile.ContentDisposition)
130-
{
131-
return false;
132-
}
133-
134-
// Read the data from the files and see if it's the same
135-
if (expectedFile.Data.CanSeek)
136-
{
137-
expectedFile.Data.Position = 0;
138-
}
139-
140-
string expectedFileData;
141-
// The last boolean parameter MUST be set to true: it ensures the stream is left open
142-
using (var reader = new StreamReader(expectedFile.Data, Encoding.UTF8, false, 1024, true))
143-
{
144-
expectedFileData = reader.ReadToEnd();
145-
}
146-
147-
string actualFileData;
148-
// The last boolean parameter MUST be set to true: it ensures the stream is left open
149-
using (var reader = new StreamReader(actualFile.Data, Encoding.UTF8, false, 1024, true))
150-
{
151-
actualFileData = reader.ReadToEnd();
152-
}
153-
154-
if (expectedFileData != actualFileData)
155-
{
156-
return false;
157-
}
158-
159-
break;
160-
}
166+
actualFileData = reader.ReadToEnd();
161167
}
162168

163-
if (!foundPairMatch)
169+
if (expectedFileData != actualFileData)
164170
{
165171
return false;
166172
}

Source/HttpMultipartParser/HttpMultipartParser.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFrameworks>net461;net472;netstandard2.0</TargetFrameworks>
@@ -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.0" />
41+
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="1.3.2" />
4242
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
4343
<PackageReference Include="System.Buffers" Version="4.5.0" />
4444
</ItemGroup>
@@ -49,7 +49,7 @@
4949
</ItemGroup>
5050

5151
<ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) ">
52-
<PackageReference Include="Microsoft.CSharp" Version="4.6.0" />
52+
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
5353
</ItemGroup>
5454

5555
<PropertyGroup Condition=" !$(TargetFramework.StartsWith('netstandard')) ">

0 commit comments

Comments
 (0)