93 lines
3.8 KiB
C#
93 lines
3.8 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
namespace Microsoft.AspNetCore.Routing.Constraints
|
|
{
|
|
/// <summary>
|
|
/// Constrains the HTTP method of request or a route.
|
|
/// </summary>
|
|
public class HttpMethodRouteConstraint : IRouteConstraint
|
|
{
|
|
/// <summary>
|
|
/// Creates a new instance of <see cref="HttpMethodRouteConstraint"/> that accepts the HTTP methods specified
|
|
/// by <paramref name="allowedMethods"/>.
|
|
/// </summary>
|
|
/// <param name="allowedMethods">The allowed HTTP methods.</param>
|
|
public HttpMethodRouteConstraint(params string[] allowedMethods)
|
|
{
|
|
if (allowedMethods == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(allowedMethods));
|
|
}
|
|
|
|
AllowedMethods = new List<string>(allowedMethods);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the HTTP methods allowed by the constraint.
|
|
/// </summary>
|
|
public IList<string> AllowedMethods { get; }
|
|
|
|
/// <inheritdoc />
|
|
public virtual bool Match(
|
|
HttpContext httpContext,
|
|
IRouter route,
|
|
string routeKey,
|
|
RouteValueDictionary values,
|
|
RouteDirection routeDirection)
|
|
{
|
|
if (routeKey == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(routeKey));
|
|
}
|
|
|
|
if (values == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(values));
|
|
}
|
|
|
|
switch (routeDirection)
|
|
{
|
|
case RouteDirection.IncomingRequest:
|
|
// Only required for constraining incoming requests
|
|
if (httpContext == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(httpContext));
|
|
}
|
|
|
|
return AllowedMethods.Contains(httpContext.Request.Method, StringComparer.OrdinalIgnoreCase);
|
|
|
|
case RouteDirection.UrlGeneration:
|
|
// We need to see if the user specified the HTTP method explicitly. Consider these two routes:
|
|
//
|
|
// a) Route: template = "/{foo}", Constraints = { httpMethod = new HttpMethodRouteConstraint("GET") }
|
|
// b) Route: template = "/{foo}", Constraints = { httpMethod = new HttpMethodRouteConstraint("POST") }
|
|
//
|
|
// A user might know ahead of time that a URI he/she is generating might be used with a particular HTTP
|
|
// method. If a URI will be used for an HTTP POST but we match on (a) while generating the URI, then
|
|
// the HTTP GET-specific route will be used for URI generation, which might have undesired behavior.
|
|
//
|
|
// To prevent this, a user might call GetVirtualPath(..., { httpMethod = "POST" }) to
|
|
// signal that he is generating a URI that will be used for an HTTP POST, so he wants the URI
|
|
// generation to be performed by the (b) route instead of the (a) route, consistent with what would
|
|
// happen on incoming requests.
|
|
object obj;
|
|
if (!values.TryGetValue(routeKey, out obj))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return AllowedMethods.Contains(Convert.ToString(obj), StringComparer.OrdinalIgnoreCase);
|
|
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(routeDirection));
|
|
}
|
|
}
|
|
}
|
|
}
|