From ce8e0ce086b0be93d25b985e1c4cdf3fe6d7bc21 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Wed, 22 Feb 2023 23:38:16 -0600 Subject: [PATCH] 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 --- .../src/Constraints/RegexRouteConstraint.cs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/Http/Routing/src/Constraints/RegexRouteConstraint.cs b/src/Http/Routing/src/Constraints/RegexRouteConstraint.cs index bc3ee556e974..a136ac70c15a 100644 --- a/src/Http/Routing/src/Constraints/RegexRouteConstraint.cs +++ b/src/Http/Routing/src/Constraints/RegexRouteConstraint.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text.RegularExpressions; @@ -15,7 +16,7 @@ namespace Microsoft.AspNetCore.Routing.Constraints; public class RegexRouteConstraint : IRouteConstraint, IParameterLiteralNodeMatchingPolicy { private static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(10); - private readonly string _regexPattern; + private readonly Func? _regexFactory; private Regex? _constraint; /// @@ -27,7 +28,6 @@ public RegexRouteConstraint(Regex regex) ArgumentNullException.ThrowIfNull(regex); _constraint = regex; - _regexPattern = regex.ToString(); } /// @@ -35,12 +35,17 @@ public RegexRouteConstraint(Regex regex) /// /// A string containing the regex pattern. public RegexRouteConstraint( - [StringSyntax(StringSyntaxAttribute.Regex, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase)] + [StringSyntax(StringSyntaxAttribute.Regex, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase)] string regexPattern) { ArgumentNullException.ThrowIfNull(regexPattern); - _regexPattern = regexPattern; + // Create regex instance lazily to avoid compiling regexes at app startup. Delay creation until Constraint is first evaluated. + // The regex instance is created by a delegate here to allow the regex engine to be trimmed when this constructor is trimmed. + _regexFactory = () => new Regex( + regexPattern, + RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, + RegexMatchTimeout); } /// @@ -50,12 +55,13 @@ public Regex Constraint { get { - // Create regex instance lazily to avoid compiling regexes at app startup. Delay creation until constraint is first evaluated. - // This is not thread safe. No side effect but multiple instances of a regex instance could be created from a burst of requests. - _constraint ??= new Regex( - _regexPattern, - RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, - RegexMatchTimeout); + if (_constraint is null) + { + Debug.Assert(_regexFactory is not null); + + // This is not thread-safe. No side effect, but multiple instances of a regex instance could be created from a burst of requests. + _constraint = _regexFactory(); + } return _constraint; }