Skip to content

Commit d8d010c

Browse files
committed
Check for null before invoking handlers. Also add unit test to validate that handlers can be null.
Resolves #121
1 parent ea217e6 commit d8d010c

3 files changed

Lines changed: 68 additions & 10 deletions

File tree

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System.IO;
2+
using System.Text;
3+
using System.Threading.Tasks;
4+
using Xunit;
5+
6+
namespace HttpMultipartParser.UnitTests
7+
{
8+
/// <summary>
9+
/// Unit tests for StreamingMultipartFormDataParser.
10+
/// </summary>
11+
public class StreamingMultipartFormDataParserUnitTests
12+
{
13+
private static readonly string _testData = TestUtil.TrimAllLines(
14+
@"--boundary
15+
Content-Disposition: form-data; name=""parameter1""
16+
17+
This is a sample parameter
18+
--boundary
19+
Content-Disposition: form-data; name=""file1""; filename=""file1.txt""
20+
Content-Type: text/plain
21+
22+
This is the content of a sample file
23+
--boundary--"
24+
);
25+
26+
[Fact]
27+
public void CanHandleNullDelegates()
28+
{
29+
using (Stream stream = TestUtil.StringToStream(_testData, Encoding.UTF8))
30+
{
31+
var parser = new StreamingMultipartFormDataParser(stream);
32+
33+
// Intentionally setting these handlers to null to verify that we can parse the stream despite missing handlers
34+
// See: https://github.com/Http-Multipart-Data-Parser/Http-Multipart-Data-Parser/issues/121
35+
parser.ParameterHandler = null;
36+
parser.FileHandler = null;
37+
38+
parser.Run();
39+
}
40+
}
41+
42+
[Fact]
43+
public async Task CanHandleNullDelegatesAsync()
44+
{
45+
using (Stream stream = TestUtil.StringToStream(_testData, Encoding.UTF8))
46+
{
47+
var parser = new StreamingMultipartFormDataParser(stream);
48+
49+
// Intentionally setting these handlers to null to verify that we can parse the stream despite missing handlers
50+
// See: https://github.com/Http-Multipart-Data-Parser/Http-Multipart-Data-Parser/issues/121
51+
parser.ParameterHandler = null;
52+
parser.FileHandler = null;
53+
54+
await parser.RunAsync();
55+
}
56+
}
57+
}
58+
}

Source/HttpMultipartParser/StreamingBinaryMultipartFormDataParser.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ private void ParseFilePart(Dictionary<string, string> parameters, RebufferableBi
686686
// We also want to chop off the newline that is inserted by the protocol.
687687
// We can do this by reducing endPos by the length of newline in this environment
688688
// and encoding
689-
FileHandler(name, filename, contentType, contentDisposition, fullBuffer, endPos - bufferNewlineLength, partNumber++, additionalParameters);
689+
FileHandler?.Invoke(name, filename, contentType, contentDisposition, fullBuffer, endPos - bufferNewlineLength, partNumber++, additionalParameters);
690690

691691
int writeBackOffset = endPos + endPosLength + boundaryNewlineOffset;
692692
int writeBackAmount = (prevLength + curLength) - writeBackOffset;
@@ -696,7 +696,7 @@ private void ParseFilePart(Dictionary<string, string> parameters, RebufferableBi
696696
}
697697

698698
// No end, consume the entire previous buffer
699-
FileHandler(name, filename, contentType, contentDisposition, prevBuffer, prevLength, partNumber++, additionalParameters);
699+
FileHandler?.Invoke(name, filename, contentType, contentDisposition, prevBuffer, prevLength, partNumber++, additionalParameters);
700700

701701
// Now we want to swap the two buffers, we don't care
702702
// what happens to the data from prevBuffer so we set
@@ -843,7 +843,7 @@ private async Task ParseFilePartAsync(Dictionary<string, string> parameters, Reb
843843
// We also want to chop off the newline that is inserted by the protocl.
844844
// We can do this by reducing endPos by the length of newline in this environment
845845
// and encoding
846-
FileHandler(name, filename, contentType, contentDisposition, fullBuffer, endPos - bufferNewlineLength, partNumber++, additionalParameters);
846+
FileHandler?.Invoke(name, filename, contentType, contentDisposition, fullBuffer, endPos - bufferNewlineLength, partNumber++, additionalParameters);
847847

848848
int writeBackOffset = endPos + endPosLength + boundaryNewlineOffset;
849849
int writeBackAmount = (prevLength + curLength) - writeBackOffset;
@@ -853,7 +853,7 @@ private async Task ParseFilePartAsync(Dictionary<string, string> parameters, Reb
853853
}
854854

855855
// No end, consume the entire previous buffer
856-
FileHandler(name, filename, contentType, contentDisposition, prevBuffer, prevLength, partNumber++, additionalParameters);
856+
FileHandler?.Invoke(name, filename, contentType, contentDisposition, prevBuffer, prevLength, partNumber++, additionalParameters);
857857

858858
// Now we want to swap the two buffers, we don't care
859859
// what happens to the data from prevBuffer so we set
@@ -898,7 +898,7 @@ private void ParseParameterPart(Dictionary<string, string> parameters, Rebuffera
898898
if (line.SequenceEqual(endBoundaryBinary)) readEndBoundary = true;
899899

900900
var part = new ParameterPartBinary(parameters["name"], data);
901-
ParameterHandler(part);
901+
ParameterHandler?.Invoke(part);
902902
}
903903

904904
/// <summary>
@@ -933,7 +933,7 @@ private async Task ParseParameterPartAsync(Dictionary<string, string> parameters
933933
if (line.SequenceEqual(endBoundaryBinary)) readEndBoundary = true;
934934

935935
var part = new ParameterPartBinary(parameters["name"], data);
936-
ParameterHandler(part);
936+
ParameterHandler?.Invoke(part);
937937
}
938938

939939
/// <summary>

Source/HttpMultipartParser/StreamingMultipartFormDataParser.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,12 @@ public void Run()
129129
var streamingParser = new StreamingBinaryMultipartFormDataParser(stream, boundary, Encoding, BinaryBufferSize, binaryMimeTypes, ignoreInvalidParts);
130130
streamingParser.ParameterHandler += binaryParameterPart =>
131131
{
132-
ParameterHandler.Invoke(new ParameterPart(binaryParameterPart.Name, binaryParameterPart.ToString(Encoding)));
132+
ParameterHandler?.Invoke(new ParameterPart(binaryParameterPart.Name, binaryParameterPart.ToString(Encoding)));
133133
};
134134

135135
streamingParser.FileHandler += (name, fileName, type, disposition, buffer, bytes, partNumber, additionalProperties) =>
136136
{
137-
FileHandler.Invoke(name, fileName, type, disposition, buffer, bytes, partNumber, additionalProperties);
137+
FileHandler?.Invoke(name, fileName, type, disposition, buffer, bytes, partNumber, additionalProperties);
138138
};
139139

140140
streamingParser.Run();
@@ -154,12 +154,12 @@ public async Task RunAsync(CancellationToken cancellationToken = default)
154154
var streamingParser = new StreamingBinaryMultipartFormDataParser(stream, boundary, Encoding ?? Constants.DefaultEncoding, BinaryBufferSize, binaryMimeTypes, ignoreInvalidParts);
155155
streamingParser.ParameterHandler += binaryParameterPart =>
156156
{
157-
ParameterHandler.Invoke(new ParameterPart(binaryParameterPart.Name, binaryParameterPart.ToString(Encoding)));
157+
ParameterHandler?.Invoke(new ParameterPart(binaryParameterPart.Name, binaryParameterPart.ToString(Encoding)));
158158
};
159159

160160
streamingParser.FileHandler += (name, fileName, type, disposition, buffer, bytes, partNumber, additionalProperties) =>
161161
{
162-
FileHandler.Invoke(name, fileName, type, disposition, buffer, bytes, partNumber, additionalProperties);
162+
FileHandler?.Invoke(name, fileName, type, disposition, buffer, bytes, partNumber, additionalProperties);
163163
};
164164

165165
await streamingParser.RunAsync().ConfigureAwait(false);

0 commit comments

Comments
 (0)