Skip to content

Commit 3cd6f48

Browse files
committed
Merge branch 'main' into fix/#3545
2 parents 2043bd4 + 4eedecf commit 3cd6f48

File tree

9 files changed

+84
-12
lines changed

9 files changed

+84
-12
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ jobs:
212212
java-version: '17'
213213

214214
- name: Setup Android SDK
215-
uses: android-actions/setup-android@00854ea68c109d98c75d956347303bf7c45b0277 # v3.2.1
215+
uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3.2.2
216216

217217
- run: dotnet workload install android maui-android
218218

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
### Fixes
66

77
- prevent event duplication and missing attachements when `JavaBackgroundThread` crashes occur ([#3756](https://github.com/getsentry/sentry-dotnet/pull/3756))
8+
- Fixed ArgumentNullException in FormRequestPayloadExtractor when handling invalid form data on ASP.NET ([#3734](https://github.com/getsentry/sentry-dotnet/pull/3734))
89

910
### Dependencies
1011

1112
- Bump Cocoa SDK from v8.36.0 to v8.39.0 ([#3727](https://github.com/getsentry/sentry-dotnet/pull/3727))
12-
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8390)
13-
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.36.0...8.39.0)
13+
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8390)
14+
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.36.0...8.39.0)
1415
- Bump Native SDK from v0.7.11 to v0.7.12 ([#3731](https://github.com/getsentry/sentry-dotnet/pull/3731))
1516
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#0712)
1617
- [diff](https://github.com/getsentry/sentry-native/compare/0.7.11...0.7.12)

src/Sentry.AspNet/Internal/SystemWebHttpRequest.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Collections.Specialized;
12
using Sentry.Extensibility;
23

34
namespace Sentry.AspNet.Internal;
@@ -12,8 +13,19 @@ internal class SystemWebHttpRequest : IHttpRequest
1213

1314
public Stream? Body => _request?.InputStream;
1415

15-
public IEnumerable<KeyValuePair<string, IEnumerable<string>>>? Form
16-
=> _request.Form.AllKeys.Select(kv => new KeyValuePair<string, IEnumerable<string>>(kv, _request.Form.GetValues(kv)));
16+
public IEnumerable<KeyValuePair<string, IEnumerable<string>>>? Form => GetFormData(_request.Form);
1717

1818
public SystemWebHttpRequest(HttpRequest request) => _request = request;
19+
20+
internal static IEnumerable<KeyValuePair<string, IEnumerable<string>>> GetFormData(NameValueCollection formdata)
21+
{
22+
return StripNulls(formdata.AllKeys).Select(key => new KeyValuePair<string, IEnumerable<string>>(
23+
key, StripNulls(formdata.GetValues(key)
24+
)));
25+
26+
// Poorly constructed form submissions can result in null keys/values on .NET Framework.
27+
// See: https://github.com/getsentry/sentry-dotnet/issues/3701
28+
IEnumerable<string> StripNulls(IEnumerable<string>? values) => values?.Where(x => x is not null) ?? [];
29+
}
30+
1931
}

src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
<!-- Generate bindings -->
9292
<Target Name="_GenerateSentryCocoaBindings" AfterTargets="SetupCocoaSDK"
9393
Condition="$([MSBuild]::IsOSPlatform('OSX')) and Exists('$(SentryCocoaFrameworkHeaders)')"
94+
Inputs="../../modules/sentry-cocoa.properties"
9495
Outputs="ApiDefinitions.cs;StructsAndEnums.cs">
9596
<MSBuild Projects="$(MSBuildProjectFile)" Targets="_InnerGenerateSentryCocoaBindings" Properties="TargetFramework=once" />
9697
</Target>

src/Sentry/Extensibility/FormRequestPayloadExtractor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ public class FormRequestPayloadExtractor : BaseRequestPayloadExtractor
1010
/// <summary>
1111
/// Supports <see cref="IHttpRequest"/> with content type application/x-www-form-urlencoded.
1212
/// </summary>
13-
protected override bool IsSupported(IHttpRequest request)
14-
=> SupportedContentType
15-
.Equals(request.ContentType, StringComparison.InvariantCulture);
13+
protected override bool IsSupported(IHttpRequest request) =>
14+
SupportedContentType.Equals(request.ContentType, StringComparison.InvariantCulture)
15+
|| (request.ContentType?.StartsWith($"{SupportedContentType};", StringComparison.InvariantCulture) == true);
1616

1717
/// <summary>
1818
/// Extracts the request form data as a dictionary.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System.Collections.Specialized;
2+
using Sentry.AspNet.Internal;
3+
4+
namespace Sentry.AspNet.Tests.Internal;
5+
6+
public class SystemWebHttpRequestTests
7+
{
8+
[Fact]
9+
public void GetFormData_GoodData_ReturnsCorrectValues()
10+
{
11+
// Arrange
12+
var formCollection = new NameValueCollection
13+
{
14+
{ "key1", "value1" },
15+
{ "key2", "value2" }
16+
};
17+
18+
// Act
19+
var form = SystemWebHttpRequest.GetFormData(formCollection).ToDict();
20+
21+
// Assert
22+
form.Should().NotBeNull();
23+
form.Should().Contain(kvp => kvp.Key == "key1" && kvp.Value.Contains("value1"));
24+
form.Should().Contain(kvp => kvp.Key == "key2" && kvp.Value.Contains("value2"));
25+
}
26+
27+
[Fact]
28+
public void GetFormData_BadData_ReturnsCorrectValues()
29+
{
30+
// Arrange
31+
var formCollection = new NameValueCollection
32+
{
33+
{ "key1", "value1" },
34+
{ "key2", "value2" },
35+
{ null, "badkey" },
36+
{ "badvalue", null },
37+
{ null, null }
38+
};
39+
40+
// Act
41+
var form = SystemWebHttpRequest.GetFormData(formCollection).ToDict();
42+
43+
// Assert
44+
form.Should().NotBeNull();
45+
form.Should().Contain(kvp => kvp.Key == "key1" && kvp.Value.Contains("value1"));
46+
form.Should().Contain(kvp => kvp.Key == "key2" && kvp.Value.Contains("value2"));
47+
}
48+
}

test/Sentry.AspNetCore.Tests/BaseRequestPayloadExtractorTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public void ExtractPayload_OriginalStreamPosition_Reset()
3232
{
3333
const int originalPosition = 100;
3434
_ = TestFixture.Stream.Position.Returns(originalPosition);
35+
TestFixture.HttpRequestCore.ContentType.Returns(SupportedContentType);
3536

3637
var sut = TestFixture.GetSut();
3738

@@ -40,6 +41,8 @@ public void ExtractPayload_OriginalStreamPosition_Reset()
4041
TestFixture.Stream.Received().Position = originalPosition;
4142
}
4243

44+
protected abstract string SupportedContentType { get; }
45+
4346
[Fact]
4447
public void ExtractPayload_OriginalStream_NotClosed()
4548
{

test/Sentry.AspNetCore.Tests/DefaultRequestPayloadExtractorTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ namespace Sentry.AspNetCore.Tests;
22

33
public class DefaultRequestPayloadExtractorTests : BaseRequestPayloadExtractorTests<DefaultRequestPayloadExtractor>
44
{
5+
protected override string SupportedContentType => string.Empty;
6+
57
[Fact]
68
public void ExtractPayload_StringData_ReadCorrectly()
79
{

test/Sentry.AspNetCore.Tests/FormRequestPayloadExtractorTests.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,20 @@ namespace Sentry.AspNetCore.Tests;
55

66
public class FormRequestPayloadExtractorTests : BaseRequestPayloadExtractorTests<FormRequestPayloadExtractor>
77
{
8+
protected override string SupportedContentType => "application/x-www-form-urlencoded";
9+
810
public FormRequestPayloadExtractorTests()
911
{
1012
TestFixture = new Fixture();
11-
_ = TestFixture.HttpRequest.ContentType.Returns("application/x-www-form-urlencoded");
1213
}
1314

14-
[Fact]
15-
public void ExtractPayload_SupportedContentType_ReadForm()
15+
[Theory]
16+
[InlineData("application/x-www-form-urlencoded")]
17+
[InlineData("application/x-www-form-urlencoded; charset=utf-8")]
18+
public void ExtractPayload_SupportedContentType_ReadForm(string contentType)
1619
{
20+
TestFixture.HttpRequest.ContentType.Returns(contentType);
21+
1722
var expected = new Dictionary<string, StringValues> { { "key", new StringValues("val") } };
1823
var f = new FormCollection(expected);
1924
_ = TestFixture.HttpRequestCore.Form.Returns(f);
@@ -32,7 +37,7 @@ public void ExtractPayload_SupportedContentType_ReadForm()
3237
[Fact]
3338
public void ExtractPayload_UnsupportedContentType_DoesNotReadStream()
3439
{
35-
_ = TestFixture.HttpRequest.ContentType.Returns("application/json");
40+
TestFixture.HttpRequest.ContentType.Returns("application/json");
3641

3742
var sut = TestFixture.GetSut();
3843

0 commit comments

Comments
 (0)