/// <summary>Gets the template information.</summary> /// <param name="context">The context.</param> /// <param name="resolver">The resolver.</param> /// <param name="routes">The routes.</param> /// <returns></returns> private static async Task <ApiRoutingTemplate> GetRoutingTemplate( this ApiRequestContext context, IUriRouteResolver resolver, IApiRoutingTable routes) { RouteMatch result; ApiRoutingTemplate template = null; foreach (var route in routes.GetRoutes()) { result = await resolver.ResolveRoute(route.Template, context.Request.Path).ConfigureAwait(false); if (result?.IsMatch ?? false) { if (template == null) { template = new ApiRoutingTemplate(route.Template); } template.Locations.Add(new ApiEndpointLocation( controller: route.Location.Controller, methodInfo: route.Location.MethodInfo, httpMethod: route.Location.HttpMethod, bodyParameterType: route.Location.BodyParameterType, uriParameterType: route.Location.UriParameterType, simpleParameters: route.Location.SimpleParameters, methodReturnType: route.Location.MethodReturnType)); } } return(template); }
/// <summary>Processes the HTTP request method.</summary> /// <param name="context">The context.</param> /// <param name="routes">The routes.</param> /// <param name="resolver">The resolver.</param> /// <param name="defaultRequestConfiguration">The default request configuration.</param> /// <returns></returns> internal static async Task <bool> ProcessHttpRequestMethod(this ApiRequestContext context, IApiRoutingTable routes, IUriRouteResolver resolver, IDeepSleepRequestConfiguration defaultRequestConfiguration) { if (!context.RequestAborted.IsCancellationRequested) { // Templates exist for thies route if ((context.Routing?.Template?.Locations?.Count ?? 0) > 0) { // A route was not found for the template if (context.Routing.Route == null) { var methods = context.Routing.Template.Locations .Where(e => !string.IsNullOrWhiteSpace(e?.HttpMethod)) .Select(e => e.HttpMethod.ToUpper()) .Distinct() .ToList(); if (methods.Contains("GET") && !methods.Contains("HEAD")) { if (resolver != null) { var match = await resolver.MatchRoute( routes, "GET", context.Request.Path).ConfigureAwait(false); if (match != null) { var enableHeadForGetRequests = match.Configuration?.EnableHeadForGetRequests ?? defaultRequestConfiguration?.EnableHeadForGetRequests ?? ApiRequestContext.GetDefaultRequestConfiguration().EnableHeadForGetRequests ?? true; if (enableHeadForGetRequests) { methods.Add("HEAD"); } } } } context.Runtime.Internals.IsMethodNotFound = true; context.Response.AddHeader("Allow", string.Join(", ", methods)); context.Response.StatusCode = 405; return(false); } } return(true); } return(false); }
/// <summary>Processes the HTTP request routing.</summary> /// <param name="context">The context.</param> /// <param name="routes">The routes.</param> /// <param name="resolver">The resolver.</param> /// <param name="defaultRequestConfig">The default request configuration.</param> /// <returns></returns> internal static async Task <bool> ProcessHttpRequestRouting(this ApiRequestContext context, IApiRoutingTable routes, IUriRouteResolver resolver, IDeepSleepRequestConfiguration defaultRequestConfig) { if (!context.RequestAborted.IsCancellationRequested) { if (routes != null && resolver != null) { context.Routing.Route = await context.GetRoutingItem(resolver, routes, defaultRequestConfig).ConfigureAwait(false); context.Routing.Template = await context.GetRoutingTemplate(resolver, routes).ConfigureAwait(false); } context.Configuration = MergeConfigurations( serviceProvider: context?.RequestServices, defaultConfig: defaultRequestConfig, endpointConfig: context.Routing?.Route?.Configuration); if (context.Routing.Route?.Location?.MethodInfo != null) { var attributes = context.Routing.Route.Location.MethodInfo.GetCustomAttributes(); // Find any attribute request pipeline components // and add the to the final configuration of the request. attributes .Where(a => a as IRequestPipelineComponent != null) .Select(a => a as IRequestPipelineComponent) .ToList() .ForEach(p => context.Configuration.PipelineComponents.Add(p)); // Find any attribute validator components // and add the to the final configuration of the request. attributes .Where(a => a as IEndpointValidatorComponent != null) .Select(a => a as IEndpointValidatorComponent) .ToList() .ForEach(v => context.Configuration.Validators.Add(v)); // Find any authentication components // and add the to the final configuration of the request. var authenticationComponents = attributes .Where(a => a as IAuthenticationComponent != null) .Select(a => a as IAuthenticationComponent) .ToList(); if (authenticationComponents.Count > 0) { context.Configuration.AuthenticationProviders = authenticationComponents; } // Find any authorization components // and add the to the final configuration of the request. var authorizationComponents = attributes .Where(a => a as IAuthorizationComponent != null) .Select(a => a as IAuthorizationComponent) .ToList(); if (authorizationComponents.Count > 0) { context.Configuration.AuthorizationProviders = authorizationComponents; } } if (context.Configuration?.RequestValidation?.MaxRequestLength != null && context.ConfigureMaxRequestLength != null) { try { context.ConfigureMaxRequestLength(context.Configuration.RequestValidation.MaxRequestLength.Value); } catch { } } return(true); } return(false); }
/// <summary>Gets the route information.</summary> /// <param name="context">The context.</param> /// <param name="resolver">The resolver.</param> /// <param name="routes">The routes.</param> /// <param name="defaultRequestConfiguration">The default request configuration.</param> /// <returns></returns> private static async Task <ApiRoutingItem> GetRoutingItem(this ApiRequestContext context, IUriRouteResolver resolver, IApiRoutingTable routes, IDeepSleepRequestConfiguration defaultRequestConfiguration) { // ----------------------------------------------------------------- // We want to trick the routing engine to treat HEAD requests as GET // http://tools.ietf.org/html/rfc7231#section-4.3.2 // ----------------------------------------------------------------- ApiRoutingItem routeInfo; if (context.Request.Method.In(StringComparison.InvariantCultureIgnoreCase, "HEAD")) { routeInfo = await resolver.MatchRoute( routes, "HEAD", context.Request.Path).ConfigureAwait(false); if (routeInfo == null) { routeInfo = await resolver.MatchRoute( routes, "GET", context.Request.Path).ConfigureAwait(false); if (routeInfo != null) { var enableHeadForGetRequests = routeInfo.Configuration?.EnableHeadForGetRequests ?? defaultRequestConfiguration?.EnableHeadForGetRequests ?? ApiRequestContext.GetDefaultRequestConfiguration().EnableHeadForGetRequests ?? true; if (!enableHeadForGetRequests) { routeInfo = null; } } } } else if (context.Request.IsCorsPreflightRequest()) { if (context.Request.CrossOriginRequest.AccessControlRequestMethod.In(StringComparison.InvariantCultureIgnoreCase, "HEAD")) { routeInfo = await resolver.MatchRoute( routes, context.Request.CrossOriginRequest.AccessControlRequestMethod, context.Request.Path).ConfigureAwait(false); if (routeInfo == null) { routeInfo = await resolver.MatchRoute( routes, "GET", context.Request.Path).ConfigureAwait(false); if (routeInfo != null) { var enableHeadForGetRequests = routeInfo.Configuration?.EnableHeadForGetRequests ?? defaultRequestConfiguration?.EnableHeadForGetRequests ?? ApiRequestContext.GetDefaultRequestConfiguration().EnableHeadForGetRequests ?? true; if (!enableHeadForGetRequests) { routeInfo = null; } } } } else { routeInfo = await resolver.MatchRoute( routes, context.Request.CrossOriginRequest.AccessControlRequestMethod, context.Request.Path).ConfigureAwait(false); } } else { routeInfo = await resolver.MatchRoute( routes, context.Request.Method, context.Request.Path).ConfigureAwait(false); } return(routeInfo); }
/// <summary>Processes the HTTP request cross origin resource sharing preflight.</summary> /// <param name="context">The context.</param> /// <param name="routes">The routes.</param> /// <param name="resolver">The resolver.</param> /// <param name="defaultRequestConfiguration">The default request configuration.</param> /// <returns></returns> internal static async Task <bool> ProcessHttpRequestCrossOriginResourceSharingPreflight( this ApiRequestContext context, IApiRoutingTable routes, IUriRouteResolver resolver, IDeepSleepRequestConfiguration defaultRequestConfiguration) { if (!context.RequestAborted.IsCancellationRequested) { if (context.Request?.IsCorsPreflightRequest() ?? false) { var methods = (context.Routing?.Template?.Locations ?? new List <ApiEndpointLocation>()) .Where(r => !string.IsNullOrWhiteSpace(r.HttpMethod)) .Select(r => r.HttpMethod.ToUpper()) .Distinct() .ToList(); // Need to include the auto-enabled HEAD method if configured on the get endpoint (if available) var hasGet = methods.FirstOrDefault(m => m.Equals("GET", StringComparison.InvariantCultureIgnoreCase)) != null; if (hasGet) { var hasHead = methods.FirstOrDefault(m => m.Equals("HEAD", StringComparison.InvariantCultureIgnoreCase)) != null; if (!hasHead) { if (resolver != null) { var getMatch = await resolver.MatchRoute( routes, "GET", context.Request.Path).ConfigureAwait(false); if (getMatch != null) { var enableHeadForGetRequests = getMatch.Configuration?.EnableHeadForGetRequests ?? defaultRequestConfiguration?.EnableHeadForGetRequests ?? ApiRequestContext.GetDefaultRequestConfiguration().EnableHeadForGetRequests ?? true; if (enableHeadForGetRequests) { methods.Add("HEAD"); } } } } } context.Response.StatusCode = 200; context.Response.AddHeader("Access-Control-Allow-Methods", string.Join(", ", methods).Trim()); if (!string.IsNullOrWhiteSpace(context.Request?.CrossOriginRequest?.AccessControlRequestHeaders)) { var allowHeaders = (context.Configuration?.CrossOriginConfig?.AllowedHeaders ?? new string[] { }) .Distinct() .Where(i => !string.IsNullOrWhiteSpace(i)) .Select(i => i.Trim()) .ToList(); if (allowHeaders.Count > 0 && allowHeaders.Contains("*")) { context.Response.AddHeader("Access-Control-Allow-Headers", context.Request.CrossOriginRequest.AccessControlRequestHeaders); } else { context.Response.AddHeader("Access-Control-Allow-Headers", string.Join(", ", allowHeaders)); } } if (context.Configuration?.CrossOriginConfig?.MaxAgeSeconds.HasValue ?? false) { context.Response.AddHeader("Access-Control-Max-Age", $"{context.Configuration.CrossOriginConfig.MaxAgeSeconds.Value}"); } return(false); } return(true); } return(false); }