File: RewriteRule.cs
Web Access
Project: src\src\Middleware\Rewrite\src\Microsoft.AspNetCore.Rewrite.csproj (Microsoft.AspNetCore.Rewrite)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Rewrite.Logging;
 
namespace Microsoft.AspNetCore.Rewrite;
 
internal sealed class RewriteRule : IRule
{
    private readonly TimeSpan _regexTimeout = TimeSpan.FromSeconds(1);
    public Regex InitialMatch { get; }
    public string Replacement { get; }
    public bool StopProcessing { get; }
    public RewriteRule(string regex, string replacement, bool stopProcessing)
    {
        ArgumentException.ThrowIfNullOrEmpty(regex);
        ArgumentException.ThrowIfNullOrEmpty(replacement);
 
        InitialMatch = new Regex(regex, RegexOptions.Compiled | RegexOptions.CultureInvariant, _regexTimeout);
        Replacement = replacement;
        StopProcessing = stopProcessing;
    }
 
    public void ApplyRule(RewriteContext context)
    {
        var path = context.HttpContext.Request.Path;
        Match initMatchResults;
        if (path == PathString.Empty)
        {
            initMatchResults = InitialMatch.Match(path.ToString());
        }
        else
        {
            initMatchResults = InitialMatch.Match(path.ToString().Substring(1));
        }
 
        if (initMatchResults.Success)
        {
            var result = initMatchResults.Result(Replacement);
            var request = context.HttpContext.Request;
 
            if (StopProcessing)
            {
                context.Result = RuleResult.SkipRemainingRules;
            }
 
            if (string.IsNullOrEmpty(result))
            {
                result = "/";
            }
 
            if (result.Contains(Uri.SchemeDelimiter, StringComparison.Ordinal))
            {
                string scheme;
                HostString host;
                PathString pathString;
                QueryString query;
                UriHelper.FromAbsolute(result, out scheme, out host, out pathString, out query, out _);
 
                request.Scheme = scheme;
                request.Host = host;
                request.Path = pathString;
                request.QueryString = query.Add(request.QueryString);
            }
            else
            {
                var split = result.IndexOf('?');
                if (split >= 0)
                {
                    var newPath = result.Substring(0, split);
                    if (newPath[0] == '/')
                    {
                        request.Path = PathString.FromUriComponent(newPath);
                    }
                    else
                    {
                        request.Path = PathString.FromUriComponent('/' + newPath);
                    }
                    request.QueryString = request.QueryString.Add(
                        QueryString.FromUriComponent(
                            result.Substring(split)));
                }
                else
                {
                    if (result[0] == '/')
                    {
                        request.Path = PathString.FromUriComponent(result);
                    }
                    else
                    {
                        request.Path = PathString.FromUriComponent('/' + result);
                    }
                }
            }
 
            context.Logger.RewrittenRequest(result);
        }
    }
}