Skip to content

Commit ce8e0ce

Browse files
authored
Allow Regex engine to be trimmed (#46813)
* Allow Regex engine to be trimmed Move the lazy Regex creation code to a delegate that is only set with the RegexRouteConstraint constructor that takes a string regexPattern. This allows for the Regex engine to be trimmed when the regexPattern constructor is trimmed. Fix #46142
1 parent 33e7a9a commit ce8e0ce

File tree

1 file changed

+16
-10
lines changed

1 file changed

+16
-10
lines changed

src/Http/Routing/src/Constraints/RegexRouteConstraint.cs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.Diagnostics.CodeAnalysis;
56
using System.Globalization;
67
using System.Text.RegularExpressions;
@@ -15,7 +16,7 @@ namespace Microsoft.AspNetCore.Routing.Constraints;
1516
public class RegexRouteConstraint : IRouteConstraint, IParameterLiteralNodeMatchingPolicy
1617
{
1718
private static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(10);
18-
private readonly string _regexPattern;
19+
private readonly Func<Regex>? _regexFactory;
1920
private Regex? _constraint;
2021

2122
/// <summary>
@@ -27,20 +28,24 @@ public RegexRouteConstraint(Regex regex)
2728
ArgumentNullException.ThrowIfNull(regex);
2829

2930
_constraint = regex;
30-
_regexPattern = regex.ToString();
3131
}
3232

3333
/// <summary>
3434
/// Constructor for a <see cref="RegexRouteConstraint"/> given a <paramref name="regexPattern"/>.
3535
/// </summary>
3636
/// <param name="regexPattern">A string containing the regex pattern.</param>
3737
public RegexRouteConstraint(
38-
[StringSyntax(StringSyntaxAttribute.Regex, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase)]
38+
[StringSyntax(StringSyntaxAttribute.Regex, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase)]
3939
string regexPattern)
4040
{
4141
ArgumentNullException.ThrowIfNull(regexPattern);
4242

43-
_regexPattern = regexPattern;
43+
// Create regex instance lazily to avoid compiling regexes at app startup. Delay creation until Constraint is first evaluated.
44+
// The regex instance is created by a delegate here to allow the regex engine to be trimmed when this constructor is trimmed.
45+
_regexFactory = () => new Regex(
46+
regexPattern,
47+
RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase,
48+
RegexMatchTimeout);
4449
}
4550

4651
/// <summary>
@@ -50,12 +55,13 @@ public Regex Constraint
5055
{
5156
get
5257
{
53-
// Create regex instance lazily to avoid compiling regexes at app startup. Delay creation until constraint is first evaluated.
54-
// This is not thread safe. No side effect but multiple instances of a regex instance could be created from a burst of requests.
55-
_constraint ??= new Regex(
56-
_regexPattern,
57-
RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase,
58-
RegexMatchTimeout);
58+
if (_constraint is null)
59+
{
60+
Debug.Assert(_regexFactory is not null);
61+
62+
// This is not thread-safe. No side effect, but multiple instances of a regex instance could be created from a burst of requests.
63+
_constraint = _regexFactory();
64+
}
5965

6066
return _constraint;
6167
}

0 commit comments

Comments
 (0)