Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
24e1f0b
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Mar 27, 2026
7733eb3
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Apr 8, 2026
fda28ce
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Apr 8, 2026
24a1527
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Apr 8, 2026
257ae80
Merge commit 'db6fa8cadde8bde4256fadf719ed1576ac50f709'
Apr 8, 2026
ed7f450
Merge commit '316760cbfcaf21efb85fb9d87f094f3e95b532e9'
Apr 8, 2026
d6c0967
Merge commit '129467bb514f72e720f233b1b080ce8b51475b56'
Apr 8, 2026
fec65f9
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Apr 8, 2026
d5798c6
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Apr 10, 2026
1f54bed
Merge from public
wtgodbe Apr 10, 2026
da32cf9
Merged PR 60002: [release/9.0] Merge from public
wtgodbe Apr 10, 2026
51bee2a
Merge commit 'cc15228bd8f897783884ca2de546055e51256bbc'
Apr 13, 2026
424ab53
Merged PR 60039: [internal/release/9.0] Fix bad merge conflict resolu…
wtgodbe Apr 13, 2026
f5ffc63
Merged PR 58157: Close connection after processing CL+TE
BrennanConroy Apr 14, 2026
206a12e
Merged PR 60026: [release/9.0] fix(ResponseCaching): Add validation t…
DeagleGross Apr 14, 2026
b0b333d
Merged PR 60023: [release/9.0] fix(Security/Authentication): include …
DeagleGross Apr 14, 2026
adecba1
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Apr 14, 2026
77e4936
Merged PR 59460: [Form binding] Fix parsing of malformed keys (net 9.0)
javiercn Apr 14, 2026
46a7152
Merge commit '5c67db3befae7938c9d483c7f9ab1ac5cbd2eec1'
Apr 14, 2026
c6c8276
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Apr 15, 2026
ceadc1b
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Apr 15, 2026
45883b5
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Apr 15, 2026
aa63462
Merged PR 59497: [internal/release/9.0] Update dependencies from dnce…
Apr 15, 2026
b21136b
Merged PR 60208: [internal/release/9.0] - Disabled nuget audit.
vseanreesermsft Apr 18, 2026
1ad07c9
Merged PR 60232: [internal/release/9.0] Update dependencies from dnce…
Apr 18, 2026
db9d9da
Merged PR 60241: [internal/release/9.0] Update dependencies from dnce…
Apr 18, 2026
f9193be
Merged PR 60561: [internal/release/9.0] Update dependencies from dnce…
Apr 29, 2026
07a4967
Merged PR 60570: [internal/release/9.0] Update dependencies from dnce…
Apr 29, 2026
cd199d4
Merged PR 60605: [internal/release/9.0] Update dependencies from dnce…
Apr 30, 2026
4d825ae
Merged PR 60637: [internal/release/9.0] Update dependencies from dnce…
Apr 30, 2026
457fd3d
Merge commit '4d825aeb5e5023588c036709c7914008b625b0eb' into internal…
vseanreesermsft May 12, 2026
ba9cd59
Apply suggestion from @BrennanConroy
BrennanConroy May 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<Project>
<Import Project="eng\Common.props" />

<PropertyGroup>
<NuGetAudit>false</NuGetAudit>
</PropertyGroup>
<PropertyGroup>
Comment on lines +4 to 6
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
</PropertyGroup>
Expand Down
4 changes: 4 additions & 0 deletions NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
<!-- Begin: Package sources from dotnet-extensions -->
<!-- End: Package sources from dotnet-extensions -->
<!-- Begin: Package sources from dotnet-runtime -->
<add key="darc-int-dotnet-runtime-a1e6809" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-runtime-a1e6809f/nuget/v3/index.json" />
<!-- End: Package sources from dotnet-runtime -->
<!-- Begin: Package sources from dotnet-efcore -->
<add key="darc-int-dotnet-efcore-60c2e9b" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-efcore-60c2e9b8/nuget/v3/index.json" />
<!-- End: Package sources from dotnet-efcore -->
<!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
<add key="dotnet-eng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" />
Expand All @@ -30,8 +32,10 @@
<clear />
<!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.-->
<!-- Begin: Package sources from dotnet-efcore -->
<add key="darc-int-dotnet-efcore-60c2e9b" value="true" />
<!-- End: Package sources from dotnet-efcore -->
<!-- Begin: Package sources from dotnet-runtime -->
<add key="darc-int-dotnet-runtime-a1e6809" value="true" />
<!-- End: Package sources from dotnet-runtime -->
<!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
</disabledPackageSources>
Expand Down
320 changes: 160 additions & 160 deletions eng/Version.Details.xml

Large diffs are not rendered by default.

160 changes: 80 additions & 80 deletions eng/Versions.props

Large diffs are not rendered by default.

89 changes: 41 additions & 48 deletions src/Components/Endpoints/src/FormMapping/FormDataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Globalization;
using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Primitives;

namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping;
Expand All @@ -23,7 +24,6 @@ internal struct FormDataReader : IDisposable
// As an implementation detail, reuse FormKey for the values.
// It's just a thin wrapper over ReadOnlyMemory<char> that caches
// the computed hash code.
private IReadOnlyDictionary<FormKey, HashSet<FormKey>>? _formDictionaryKeysByPrefix;

private PrefixResolver _prefixResolver;

Expand All @@ -48,6 +48,8 @@ public FormDataReader(IReadOnlyDictionary<FormKey, StringValues> formCollection,

public int MaxRecursionDepth { get; set; } = 64;

public int MaxCollectionSize { get; set; } = FormReader.DefaultValueCountLimit;

public Action<string, FormattableString, string?>? ErrorHandler { get; set; }

public Action<string, object>? AttachInstanceToErrorsHandler { get; set; }
Expand Down Expand Up @@ -107,61 +109,52 @@ public void AttachInstanceToErrors(object value)

internal FormKeyCollection GetKeys()
{
if (_formDictionaryKeysByPrefix == null)
{
_formDictionaryKeysByPrefix = ProcessFormKeys();
}
// Scan the input dictionary for keys matching the current prefix followed by a bracket segment.
// This avoids building a large upfront dictionary of all prefix→key mappings.
var prefix = _currentPrefixBuffer;
var result = new HashSet<FormKey>();

if (_formDictionaryKeysByPrefix.TryGetValue(new FormKey(_currentPrefixBuffer), out var foundKeys))
foreach (var kvp in _readOnlyMemoryKeys)
{
return new FormKeyCollection(foundKeys);
}
var key = kvp.Key.Value;

return FormKeyCollection.Empty;
}
// The key must start with the current prefix (case-insensitive).
if (key.Length <= prefix.Length ||
!key.Span[..prefix.Length].Equals(prefix.Span, StringComparison.OrdinalIgnoreCase))
{
continue;
}

// Internal for testing purposes
internal IReadOnlyDictionary<FormKey, HashSet<FormKey>> ProcessFormKeys()
{
var keys = _readOnlyMemoryKeys.Keys;
var result = new Dictionary<FormKey, HashSet<FormKey>>();
// We need to iterate over all the keys in the dictionary and process each key to split it into segments where
// the prefixes are string separated by . and the keys are enclosed in []. For example if the key is
// Customer.Orders[<<OrderId>>]BillingInfo.FirstName, then we need to split it into Customer.Orders,
// [<<OrderId>>] and BillingInfo.FirstName. We then, need to group all the keys by the prefix. So, for the
// above example, we will have an entry for the prefix Customer.Orders that will include [<<OrderId>>] as the
// key.

foreach (var key in keys)
{
var startIndex = key.Value.Span.IndexOf('[');
while (startIndex >= 0)
// Immediately after the prefix, there must be a '['.
if (key.Span[prefix.Length] != '[')
{
continue;
}

// Find the closing ']' after the '['.
var remaining = key[prefix.Length..];
var closeIndex = remaining.Span[1..].IndexOf(']');
if (closeIndex == -1)
{
// Malformed key — no closing bracket. Skip it.
continue;
}

// Extract "[value]" (closeIndex is relative to position 1, so add 2 for the full segment).
var segment = remaining[..(closeIndex + 2)];
result.Add(new FormKey(segment));

// Allow one extra item through so collection/dictionary binding can still detect overflow
// and report the existing max-size error instead of silently truncating the input.
if (result.Count > MaxCollectionSize)
{
var endIndex = key.Value.Span[startIndex..].IndexOf(']') + startIndex;
if (endIndex == -1)
{
// Ignore malformed keys
break;
}

var prefix = key.Value[..startIndex];
var keyValue = key.Value[startIndex..(endIndex + 1)];
if (result.TryGetValue(new FormKey(prefix), out var foundKeys))
{
foundKeys.Add(new FormKey(keyValue));
}
else
{
result.Add(new FormKey(prefix), new HashSet<FormKey> { new FormKey(keyValue) });
}

var nextOpenBracket = key.Value.Span[(endIndex + 1)..].IndexOf('[');

startIndex = nextOpenBracket != -1 ? endIndex + 1 + nextOpenBracket : -1;
break;
}
}

return result;
return result.Count > 0
? new FormKeyCollection(result)
: FormKeyCollection.Empty;
}

// This only ever gets invoked if we have a recursive type.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ public override void Deserialize(
ErrorHandler = context.OnError,
AttachInstanceToErrorsHandler = context.MapErrorToContainer,
MaxRecursionDepth = options.MaxRecursionDepth,
MaxErrorCount = options.MaxErrorCount
MaxErrorCount = options.MaxErrorCount,
MaxCollectionSize = options.MaxCollectionSize
};

reader.PushPrefix(context.ParameterName);
Expand Down
Loading
Loading