Skip to content

Commit ec2c7b4

Browse files
author
John Luo
authored
Merge pull request #25219 from dotnet-maestro-bot/merge/release/5.0-to-master
[automated] Merge branch 'release/5.0' => 'master'
2 parents 332f150 + 81ed8a4 commit ec2c7b4

File tree

150 files changed

+4073
-663
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

150 files changed

+4073
-663
lines changed

AspNetCore.sln

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Diagno
15071507
EndProject
15081508
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Diagnostics.HealthChecks.Tests", "src\HealthChecks\HealthChecks\test\Microsoft.Extensions.Diagnostics.HealthChecks.Tests.csproj", "{7509AA1E-3093-4BEE-984F-E11579E98A11}"
15091509
EndProject
1510+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.JSInterop.Tests", "src\JSInterop\Microsoft.JSInterop\test\Microsoft.JSInterop.Tests.csproj", "{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}"
1511+
EndProject
15101512
Global
15111513
GlobalSection(SolutionConfigurationPlatforms) = preSolution
15121514
Debug|Any CPU = Debug|Any CPU
@@ -7179,6 +7181,18 @@ Global
71797181
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Release|x64.Build.0 = Release|Any CPU
71807182
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Release|x86.ActiveCfg = Release|Any CPU
71817183
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Release|x86.Build.0 = Release|Any CPU
7184+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
7185+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
7186+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|x64.ActiveCfg = Debug|Any CPU
7187+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|x64.Build.0 = Debug|Any CPU
7188+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|x86.ActiveCfg = Debug|Any CPU
7189+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|x86.Build.0 = Debug|Any CPU
7190+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
7191+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|Any CPU.Build.0 = Release|Any CPU
7192+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|x64.ActiveCfg = Release|Any CPU
7193+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|x64.Build.0 = Release|Any CPU
7194+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|x86.ActiveCfg = Release|Any CPU
7195+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|x86.Build.0 = Release|Any CPU
71827196
EndGlobalSection
71837197
GlobalSection(SolutionProperties) = preSolution
71847198
HideSolutionNode = FALSE
@@ -7934,6 +7948,7 @@ Global
79347948
{B06040BC-DA28-4923-8CAC-20EB517D471B} = {22D7D74B-565D-4047-97B4-F149B1A13350}
79357949
{55CACC1F-FE96-47C8-8073-91F4CAA55C75} = {2A91479A-4ABE-4BB7-9A5E-CA3B9CCFC69E}
79367950
{7509AA1E-3093-4BEE-984F-E11579E98A11} = {7CB09412-C9B0-47E8-A8C3-311AA4CFDE04}
7951+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E} = {16898702-3E33-41C1-B8D8-4CE3F1D46BD9}
79377952
EndGlobalSection
79387953
GlobalSection(ExtensibilityGlobals) = postSolution
79397954
SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F}

eng/Dependencies.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ and are generated based on the last package release.
6464
<LatestPackageReference Include="System.ComponentModel.Annotations" />
6565
<LatestPackageReference Include="System.Diagnostics.DiagnosticSource" />
6666
<LatestPackageReference Include="System.Diagnostics.EventLog" />
67+
<LatestPackageReference Include="System.DirectoryServices.Protocols" />
6768
<LatestPackageReference Include="System.Drawing.Common" />
6869
<LatestPackageReference Include="System.IO.Pipelines" />
6970
<LatestPackageReference Include="System.Net.Http" />

eng/Version.Details.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@
205205
<Uri>https://github.com/dotnet/runtime</Uri>
206206
<Sha>907f7da59b40c80941b02ac2a46650adf3f606bc</Sha>
207207
</Dependency>
208+
<Dependency Name="System.DirectoryServices.Protocols" Version="5.0.0-rc.1.20417.14">
209+
<Uri>https://github.com/dotnet/runtime</Uri>
210+
<Sha>907f7da59b40c80941b02ac2a46650adf3f606bc</Sha>
211+
</Dependency>
208212
<Dependency Name="System.Drawing.Common" Version="5.0.0-rc.1.20417.14">
209213
<Uri>https://github.com/dotnet/runtime</Uri>
210214
<Sha>907f7da59b40c80941b02ac2a46650adf3f606bc</Sha>

eng/Versions.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
<SystemComponentModelAnnotationsPackageVersion>5.0.0-rc.1.20417.14</SystemComponentModelAnnotationsPackageVersion>
109109
<SystemDiagnosticsDiagnosticSourcePackageVersion>5.0.0-rc.1.20417.14</SystemDiagnosticsDiagnosticSourcePackageVersion>
110110
<SystemDiagnosticsEventLogPackageVersion>5.0.0-rc.1.20417.14</SystemDiagnosticsEventLogPackageVersion>
111+
<SystemDirectoryServicesProtocolsPackageVersion>5.0.0-rc.1.20417.14</SystemDirectoryServicesProtocolsPackageVersion>
111112
<SystemDrawingCommonPackageVersion>5.0.0-rc.1.20417.14</SystemDrawingCommonPackageVersion>
112113
<SystemIOPipelinesPackageVersion>5.0.0-rc.1.20417.14</SystemIOPipelinesPackageVersion>
113114
<SystemNetHttpJsonPackageVersion>5.0.0-rc.1.20417.14</SystemNetHttpJsonPackageVersion>

src/Antiforgery/src/Internal/DefaultAntiforgeryTokenStore.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Diagnostics;
6+
using System.IO;
67
using System.Threading.Tasks;
78
using Microsoft.AspNetCore.Http;
89
using Microsoft.Extensions.Options;
@@ -57,7 +58,24 @@ public async Task<AntiforgeryTokenSet> GetRequestTokensAsync(HttpContext httpCon
5758
{
5859
// Check the content-type before accessing the form collection to make sure
5960
// we report errors gracefully.
60-
var form = await httpContext.Request.ReadFormAsync();
61+
IFormCollection form;
62+
try
63+
{
64+
form = await httpContext.Request.ReadFormAsync();
65+
}
66+
catch (InvalidDataException ex)
67+
{
68+
// ReadFormAsync can throw InvalidDataException if the form content is malformed.
69+
// Wrap it in an AntiforgeryValidationException and allow the caller to handle it as just another antiforgery failure.
70+
throw new AntiforgeryValidationException(Resources.AntiforgeryToken_UnableToReadRequest, ex);
71+
}
72+
catch (IOException ex)
73+
{
74+
// Reading the request body (which happens as part of ReadFromAsync) may throw an exception if a client disconnects.
75+
// Wrap it in an AntiforgeryValidationException and allow the caller to handle it as just another antiforgery failure.
76+
throw new AntiforgeryValidationException(Resources.AntiforgeryToken_UnableToReadRequest, ex);
77+
}
78+
6179
requestToken = form[_options.FormFieldName];
6280
}
6381

src/Antiforgery/src/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@
136136
<data name="AntiforgeryToken_TokensSwapped" xml:space="preserve">
137137
<value>Validation of the provided antiforgery token failed. The cookie token and the request token were swapped.</value>
138138
</data>
139+
<data name="AntiforgeryToken_UnableToReadRequest" xml:space="preserve">
140+
<value>Unable to read the antiforgery request token from the posted form.</value>
141+
</data>
139142
<data name="AntiforgeryToken_UsernameMismatch" xml:space="preserve">
140143
<value>The provided antiforgery token was meant for user "{0}", but the current user is "{1}".</value>
141144
</data>

src/Antiforgery/test/DefaultAntiforgeryTokenStoreTest.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Threading;
68
using System.Threading.Tasks;
79
using Microsoft.AspNetCore.Http;
810
using Microsoft.Extensions.Primitives;
@@ -235,6 +237,56 @@ public async Task GetRequestTokens_BothHeaderValueAndFormFieldsEmpty_ReturnsNull
235237
Assert.Null(tokenSet.RequestToken);
236238
}
237239

240+
[Fact]
241+
public async Task GetRequestTokens_ReadFormAsyncThrowsIOException_ThrowsAntiforgeryValidationException()
242+
{
243+
// Arrange
244+
var ioException = new IOException();
245+
var httpContext = new Mock<HttpContext>();
246+
247+
httpContext.Setup(r => r.Request.Cookies).Returns(Mock.Of<IRequestCookieCollection>());
248+
httpContext.SetupGet(r => r.Request.HasFormContentType).Returns(true);
249+
httpContext.Setup(r => r.Request.ReadFormAsync(It.IsAny<CancellationToken>())).Throws(ioException);
250+
251+
var options = new AntiforgeryOptions
252+
{
253+
Cookie = { Name = "cookie-name" },
254+
FormFieldName = "form-field-name",
255+
HeaderName = null,
256+
};
257+
258+
var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options));
259+
260+
// Act & Assert
261+
var ex = await Assert.ThrowsAsync<AntiforgeryValidationException>(() => tokenStore.GetRequestTokensAsync(httpContext.Object));
262+
Assert.Same(ioException, ex.InnerException);
263+
}
264+
265+
[Fact]
266+
public async Task GetRequestTokens_ReadFormAsyncThrowsInvalidDataException_ThrowsAntiforgeryValidationException()
267+
{
268+
// Arrange
269+
var exception = new InvalidDataException();
270+
var httpContext = new Mock<HttpContext>();
271+
272+
httpContext.Setup(r => r.Request.Cookies).Returns(Mock.Of<IRequestCookieCollection>());
273+
httpContext.SetupGet(r => r.Request.HasFormContentType).Returns(true);
274+
httpContext.Setup(r => r.Request.ReadFormAsync(It.IsAny<CancellationToken>())).Throws(exception);
275+
276+
var options = new AntiforgeryOptions
277+
{
278+
Cookie = { Name = "cookie-name" },
279+
FormFieldName = "form-field-name",
280+
HeaderName = null,
281+
};
282+
283+
var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options));
284+
285+
// Act & Assert
286+
var ex = await Assert.ThrowsAsync<AntiforgeryValidationException>(() => tokenStore.GetRequestTokensAsync(httpContext.Object));
287+
Assert.Same(exception, ex.InnerException);
288+
}
289+
238290
[Theory]
239291
[InlineData(false, CookieSecurePolicy.SameAsRequest, null)]
240292
[InlineData(true, CookieSecurePolicy.SameAsRequest, true)]

src/Components/Components/src/ComponentFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ private Action<IServiceProvider, IComponent> CreateInitializer(Type type)
6363
(
6464
propertyName: property.Name,
6565
propertyType: property.PropertyType,
66-
setter: MemberAssignment.CreatePropertySetter(type, property, cascading: false)
66+
setter: new PropertySetter(type, property)
6767
)).ToArray();
6868

6969
return Initialize;

src/Components/Components/src/Reflection/ComponentProperties.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public static void SetProperties(in ParameterView parameters, object target)
144144
}
145145
}
146146

147-
static void SetProperty(object target, IPropertySetter writer, string parameterName, object value)
147+
static void SetProperty(object target, PropertySetter writer, string parameterName, object value)
148148
{
149149
try
150150
{
@@ -246,13 +246,13 @@ private static void ThrowForInvalidCaptureUnmatchedValuesParameterType(Type targ
246246
private class WritersForType
247247
{
248248
private const int MaxCachedWriterLookups = 100;
249-
private readonly Dictionary<string, IPropertySetter> _underlyingWriters;
250-
private readonly ConcurrentDictionary<string, IPropertySetter?> _referenceEqualityWritersCache;
249+
private readonly Dictionary<string, PropertySetter> _underlyingWriters;
250+
private readonly ConcurrentDictionary<string, PropertySetter?> _referenceEqualityWritersCache;
251251

252252
public WritersForType(Type targetType)
253253
{
254-
_underlyingWriters = new Dictionary<string, IPropertySetter>(StringComparer.OrdinalIgnoreCase);
255-
_referenceEqualityWritersCache = new ConcurrentDictionary<string, IPropertySetter?>(ReferenceEqualityComparer.Instance);
254+
_underlyingWriters = new Dictionary<string, PropertySetter>(StringComparer.OrdinalIgnoreCase);
255+
_referenceEqualityWritersCache = new ConcurrentDictionary<string, PropertySetter?>(ReferenceEqualityComparer.Instance);
256256

257257
foreach (var propertyInfo in GetCandidateBindableProperties(targetType))
258258
{
@@ -271,7 +271,10 @@ public WritersForType(Type targetType)
271271
$"The type '{targetType.FullName}' declares a parameter matching the name '{propertyName}' that is not public. Parameters must be public.");
272272
}
273273

274-
var propertySetter = MemberAssignment.CreatePropertySetter(targetType, propertyInfo, cascading: cascadingParameterAttribute != null);
274+
var propertySetter = new PropertySetter(targetType, propertyInfo)
275+
{
276+
Cascading = cascadingParameterAttribute != null,
277+
};
275278

276279
if (_underlyingWriters.ContainsKey(propertyName))
277280
{
@@ -298,17 +301,17 @@ public WritersForType(Type targetType)
298301
ThrowForInvalidCaptureUnmatchedValuesParameterType(targetType, propertyInfo);
299302
}
300303

301-
CaptureUnmatchedValuesWriter = MemberAssignment.CreatePropertySetter(targetType, propertyInfo, cascading: false);
304+
CaptureUnmatchedValuesWriter = new PropertySetter(targetType, propertyInfo);
302305
CaptureUnmatchedValuesPropertyName = propertyInfo.Name;
303306
}
304307
}
305308
}
306309

307-
public IPropertySetter? CaptureUnmatchedValuesWriter { get; }
310+
public PropertySetter? CaptureUnmatchedValuesWriter { get; }
308311

309312
public string? CaptureUnmatchedValuesPropertyName { get; }
310313

311-
public bool TryGetValue(string parameterName, [MaybeNullWhen(false)] out IPropertySetter writer)
314+
public bool TryGetValue(string parameterName, [MaybeNullWhen(false)] out PropertySetter writer)
312315
{
313316
// In intensive parameter-passing scenarios, one of the most expensive things we do is the
314317
// lookup from parameterName to writer. Pre-5.0 that was because of the string hashing.
Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,55 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
5+
using System.Reflection;
6+
47
namespace Microsoft.AspNetCore.Components.Reflection
58
{
6-
internal interface IPropertySetter
9+
internal sealed class PropertySetter
710
{
8-
bool Cascading { get; }
11+
private static readonly MethodInfo CallPropertySetterOpenGenericMethod =
12+
typeof(PropertySetter).GetMethod(nameof(CallPropertySetter), BindingFlags.NonPublic | BindingFlags.Static)!;
13+
14+
private readonly Action<object, object> _setterDelegate;
15+
16+
public PropertySetter(Type targetType, PropertyInfo property)
17+
{
18+
if (property.SetMethod == null)
19+
{
20+
throw new InvalidOperationException($"Cannot provide a value for property " +
21+
$"'{property.Name}' on type '{targetType.FullName}' because the property " +
22+
$"has no setter.");
23+
}
24+
25+
var setMethod = property.SetMethod;
26+
27+
var propertySetterAsAction =
28+
setMethod.CreateDelegate(typeof(Action<,>).MakeGenericType(targetType, property.PropertyType));
29+
var callPropertySetterClosedGenericMethod =
30+
CallPropertySetterOpenGenericMethod.MakeGenericMethod(targetType, property.PropertyType);
31+
_setterDelegate = (Action<object, object>)
32+
callPropertySetterClosedGenericMethod.CreateDelegate(typeof(Action<object, object>), propertySetterAsAction);
33+
}
34+
35+
public bool Cascading { get; init; }
36+
37+
public void SetValue(object target, object value) => _setterDelegate(target, value);
938

10-
void SetValue(object target, object value);
39+
private static void CallPropertySetter<TTarget, TValue>(
40+
Action<TTarget, TValue> setter,
41+
object target,
42+
object value)
43+
where TTarget : notnull
44+
{
45+
if (value == null)
46+
{
47+
setter((TTarget)target, default!);
48+
}
49+
else
50+
{
51+
setter((TTarget)target, (TValue)value);
52+
}
53+
}
1154
}
1255
}

0 commit comments

Comments
 (0)