File: CorsHttpMethodActionConstraint.cs
Web Access
Project: src\src\Mvc\Mvc.Cors\src\Microsoft.AspNetCore.Mvc.Cors.csproj (Microsoft.AspNetCore.Mvc.Cors)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.ObjectModel;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.Extensions.Primitives;
 
namespace Microsoft.AspNetCore.Mvc.Cors;
 
internal sealed class CorsHttpMethodActionConstraint : HttpMethodActionConstraint
{
    private readonly string OriginHeader = "Origin";
    private readonly string AccessControlRequestMethod = "Access-Control-Request-Method";
 
    public CorsHttpMethodActionConstraint(HttpMethodActionConstraint constraint)
        : base(constraint.HttpMethods)
    {
    }
 
    public override bool Accept(ActionConstraintContext context)
    {
        ArgumentNullException.ThrowIfNull(context);
 
        var methods = (ReadOnlyCollection<string>)HttpMethods;
        if (methods.Count == 0)
        {
            return true;
        }
 
        var request = context.RouteContext.HttpContext.Request;
        // Perf: Check http method before accessing the Headers collection.
        if (Http.HttpMethods.IsOptions(request.Method) &&
            request.Headers.ContainsKey(OriginHeader) &&
            request.Headers.TryGetValue(AccessControlRequestMethod, out var accessControlRequestMethod) &&
            !StringValues.IsNullOrEmpty(accessControlRequestMethod))
        {
            // Read interface .Count once rather than per iteration
            var methodsCount = methods.Count;
            for (var i = 0; i < methodsCount; i++)
            {
                var supportedMethod = methods[i];
                if (string.Equals(supportedMethod, accessControlRequestMethod, StringComparison.OrdinalIgnoreCase))
                {
                    return true;
                }
            }
 
            return false;
        }
 
        return base.Accept(context);
    }
}