예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <summary>Uses the deep sleep services.</summary>
        /// <param name="services">The services.</param>
        /// <param name="configure">The configure.</param>
        /// <returns></returns>
        public static IServiceCollection UseDeepSleepServices(this IServiceCollection services, Action <IDeepSleepServiceConfiguration> configure = null)
        {
            var configuration = new DeepSleepServiceConfiguration
            {
                DefaultRequestConfiguration = ApiRequestContext.GetDefaultRequestConfiguration(),
                ExcludePaths = new List <string>(),
                IncludePaths = new List <string> {
                    ApiPaths.All()
                },
                WriteConsoleHeader  = true,
                DiscoveryStrategies = new List <IDeepSleepDiscoveryStrategy>()
            };

            if (configure != null)
            {
                configure(configuration);
            }

            configuration.DefaultRequestConfiguration = configuration.DefaultRequestConfiguration ?? ApiRequestContext.GetDefaultRequestConfiguration();
            configuration.ExcludePaths = configuration.ExcludePaths ?? new List <string>();
            configuration.IncludePaths = configuration.IncludePaths ?? new List <string>();

            var routingTable = new ApiRoutingTable(routePrefix: configuration.RoutePrefix);

            services
            .AddScoped <IApiRequestContextResolver, ApiRequestContextResolver>()
            .AddScoped <IFormUrlEncodedObjectSerializer, FormUrlEncodedObjectSerializer>()
            .AddScoped <IUriRouteResolver, ApiRouteResolver>()
            .AddScoped <IMultipartStreamReader, MultipartStreamReader>()
            .AddScoped <IDeepSleepMediaSerializerFactory, DeepSleepMediaSerializerWriterFactory>()
            .AddScoped <IApiValidationProvider, ApiEndpointValidationProvider>()
            .AddSingleton <IApiRequestPipeline, IApiRequestPipeline>((p) => ApiRequestPipeline.GetDefaultRequestPipeline())
            .AddSingleton <IDeepSleepRequestConfiguration, IDeepSleepRequestConfiguration>((p) => configuration.DefaultRequestConfiguration)
            .AddSingleton <IDeepSleepServiceConfiguration, IDeepSleepServiceConfiguration>((p) => configuration)
            .AddSingleton <IApiRoutingTable, IApiRoutingTable>((p) => routingTable);

            return(services);
        }
예제 #3
0
        /// <summary>Processes the HTTP response caching.</summary>
        /// <param name="context">The context.</param>
        /// <param name="defaultRequestConfiguration">The default request configuration.</param>
        /// <returns></returns>
        internal static Task <bool> ProcessHttpResponseCaching(this ApiRequestContext context, IDeepSleepRequestConfiguration defaultRequestConfiguration)
        {
            if (!context.RequestAborted.IsCancellationRequested)
            {
                var statusCode          = context.Response.StatusCode;
                var systemConfiguration = ApiRequestContext.GetDefaultRequestConfiguration();

                var expirationSeconds = context.Configuration?.CacheDirective?.ExpirationSeconds
                                        ?? defaultRequestConfiguration?.CacheDirective?.ExpirationSeconds
                                        ?? systemConfiguration.CacheDirective.ExpirationSeconds.Value;

                var cacheability = context.Configuration?.CacheDirective?.Cacheability
                                   ?? defaultRequestConfiguration?.CacheDirective?.Cacheability
                                   ?? systemConfiguration.CacheDirective.Cacheability.Value;

                var cacheLocation = context.Configuration?.CacheDirective?.CacheLocation
                                    ?? defaultRequestConfiguration?.CacheDirective?.CacheLocation
                                    ?? systemConfiguration.CacheDirective.CacheLocation.Value;

                var vary = context.Configuration?.CacheDirective?.VaryHeaderValue
                           ?? defaultRequestConfiguration?.CacheDirective?.VaryHeaderValue
                           ?? systemConfiguration.CacheDirective.VaryHeaderValue;

                if (statusCode >= 200 && statusCode <= 299 && statusCode != 204)
                {
                    // Don't add cache headers for pre-flight requests
                    // This is handled in the prflight pipeline component
                    if (context.Request.IsCorsPreflightRequest())
                    {
                        return(Task.FromResult(true));
                    }

                    if (cacheability == HttpCacheType.Cacheable)
                    {
                        var maxAgeSeconds = expirationSeconds < 0
                            ? 0
                            : expirationSeconds;

                        context.Response.AddHeader("Cache-Control", $"{cacheLocation.ToString().ToLower()}, max-age={maxAgeSeconds}");
                        context.Response.AddHeader("Expires", DateTime.UtcNow.AddSeconds(expirationSeconds).ToString("r"));

                        if (!string.IsNullOrWhiteSpace(vary))
                        {
                            // ADDING VARY HEADERS TO SPECIFY WHAT THE RESPONSE REPRESENTATION WAS GENERATED AGAINST.
                            context.Response.AddHeader(
                                name: "Vary",
                                value: vary,
                                append: true);
                        }

                        return(Task.FromResult(true));
                    }
                }

                var seconds = expirationSeconds > 0
                    ? -1
                    : expirationSeconds;

                context.Response.AddHeader("Cache-Control", $"no-store, max-age=0");

                // this gets updated when the response date is added to the headers.  THe value will
                // ultimately be the response date - expiration seconds.  Needs to be here though because the header is checked
                // for prior to updating it.
                context.Response.AddHeader("Expires", DateTime.UtcNow.AddSeconds(seconds).ToString("r"));
            }

            return(Task.FromResult(true));
        }
예제 #4
0
        /// <summary>Writes the deepsleep to console.</summary>
        /// <param name="routingTable">The routing table.</param>
        /// <param name="defaultConfiguration">The default configuration.</param>
        internal static void WriteDeepSleepToConsole(IApiRoutingTable routingTable, IDeepSleepRequestConfiguration defaultConfiguration)
        {
            var systemConfiguration = ApiRequestContext.GetDefaultRequestConfiguration();
            var existingColor       = Console.ForegroundColor;

            var deepSleepAssemblyInfo        = GetAssemplyInfo(typeof(ApiRequestContext));
            var deepSleepWebAssemblyInfo     = GetAssemplyInfo(typeof(ApiCoreHttpExtensionMethods));
            var deepSleepOpenApiAssemblyInfo = GetAssemplyInfo(Type.GetType("DeepSleep.OpenApi.DeepSleepOasGenerator, deepsleep.openapi", false, false));

            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine($@"");
            Console.WriteLine($@" ____                  _             ");
            Console.WriteLine($@"|    \ ___ ___ ___ ___| |___ ___ ___ ");
            Console.WriteLine($@"|  |  | -_| -_| . |_ -| | -_| -_| . |");
            Console.WriteLine($@"|____/|___|___|  _|___|_|___|___|  _|");
            Console.Write($@"              |_|               |_|  ");
            Console.ForegroundColor = existingColor;

            Console.WriteLine($"   v{deepSleepAssemblyInfo.version}");
            Console.WriteLine($"");

            if (!string.IsNullOrWhiteSpace(deepSleepWebAssemblyInfo.framework))
            {
                Console.WriteLine($"");
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine($"Target(s): ");
                Console.ForegroundColor = existingColor;
                Console.WriteLine($"------------------------------------------------");
                Console.ForegroundColor = existingColor;
                Console.WriteLine($"           {deepSleepAssemblyInfo.name}, {deepSleepAssemblyInfo.version}, {deepSleepAssemblyInfo.framework}");

                if (!string.IsNullOrWhiteSpace(deepSleepOpenApiAssemblyInfo.name))
                {
                    Console.WriteLine($"           {deepSleepOpenApiAssemblyInfo.name}, {deepSleepOpenApiAssemblyInfo.version}, {deepSleepOpenApiAssemblyInfo.framework}");
                }

                Console.WriteLine($"           {deepSleepWebAssemblyInfo.name}, {deepSleepWebAssemblyInfo.version}, {deepSleepWebAssemblyInfo.framework}");
                Console.WriteLine($"");
            }


            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.Write($"Endpoints: ");
            Console.ForegroundColor = existingColor;
            Console.WriteLine($"{routingTable?.GetRoutes()?.Count ?? 0}");
            Console.WriteLine($"------------------------------------------------");
            Console.WriteLine($"");

            var routes = (routingTable?.GetRoutes() ?? new List <ApiRoutingItem>())
                         .OrderBy(r => r.Template)
                         .ToList();

            Action <string, string, bool> writeRoute = (string method, string template, bool isAutoHead) =>
            {
                existingColor = Console.ForegroundColor;

                Console.ForegroundColor = isAutoHead ? ConsoleColor.Gray : ConsoleColor.Yellow;
                Console.Write($"  {method.ToUpper(),-9}");
                Console.ForegroundColor = existingColor;

                WriteEndpointTemplate(template, isAutoHead);
            };

            routes.ForEach(r =>
            {
                writeRoute(r.HttpMethod, r.Template, false);

                if (string.Compare(r.HttpMethod, "GET", true) == 0)
                {
                    var enableGet = r.Configuration?.EnableHeadForGetRequests
                                    ?? defaultConfiguration?.EnableHeadForGetRequests
                                    ?? systemConfiguration?.EnableHeadForGetRequests
                                    ?? true;

                    if (enableGet)
                    {
                        var matchingHead = routes
                                           .Where(m => m.HttpMethod.ToLowerInvariant() == "head")
                                           .Where(m => m.Template.ToLowerInvariant() == r.Template.ToLowerInvariant())
                                           .FirstOrDefault();

                        if (matchingHead == null)
                        {
                            writeRoute("HEAD", r.Template, true);
                        }
                    }
                }
            });

            Console.WriteLine("");

            var now = DateTime.Now;

            if (now.Month == 5 && now.Day == 4)
            {
                MayTheFourth();
            }

            Console.WriteLine();
        }
예제 #5
0
        /// <summary>Processes the API request.</summary>
        /// <param name="context">The context.</param>
        /// <param name="httpcontext">The httpcontext.</param>
        /// <param name="contextResolver">The context resolver.</param>
        /// <param name="requestPipeline">The request pipeline.</param>
        /// <param name="defaultRequestConfiguration">The default request configuration.</param>
        /// <returns></returns>
        internal static async Task <bool> ProcessApiRequest(
            this ApiRequestContext context,
            HttpContext httpcontext,
            IApiRequestContextResolver contextResolver,
            IApiRequestPipeline requestPipeline,
            IDeepSleepRequestConfiguration defaultRequestConfiguration)
        {
            if (!context.RequestAborted.IsCancellationRequested)
            {
                await requestPipeline.Run(contextResolver);

                context.SetThreadCulure();

                var responseDate = DateTimeOffset.UtcNow;
                context.Response.Date = responseDate;

                context.Response.AddHeader(
                    name: "Date",
                    value: responseDate.ToString("r"),
                    append: false,
                    allowMultiple: false);

                httpcontext.Response.Headers.Add("Date", responseDate.ToString("r"));

                // Sync up the expire header for nocache requests with the date header being used
                var contextExpiresHeader = context.Response.Headers.FirstOrDefault(h => h.Name == "Expires");

                var expirationSeconds = context.Configuration?.CacheDirective?.ExpirationSeconds
                                        ?? defaultRequestConfiguration?.CacheDirective?.ExpirationSeconds
                                        ?? ApiRequestContext.GetDefaultRequestConfiguration().CacheDirective.ExpirationSeconds.Value;

                var cacheability = context.Configuration?.CacheDirective?.Cacheability
                                   ?? defaultRequestConfiguration?.CacheDirective?.Cacheability
                                   ?? ApiRequestContext.GetDefaultRequestConfiguration().CacheDirective.Cacheability.Value;

                if (contextExpiresHeader != null)
                {
                    if (cacheability == HttpCacheType.NoCache && expirationSeconds > 0)
                    {
                        contextExpiresHeader.Value = responseDate.AddSeconds(-1).ToString("r");
                    }
                    else
                    {
                        contextExpiresHeader.Value = responseDate.AddSeconds(expirationSeconds).ToString("r");
                    }
                }

                // Merge status code to the http response
                httpcontext.Response.StatusCode = context.Response.StatusCode;

                if (context.Response.ResponseWriter != null && context.Response.ResponseWriterOptions != null)
                {
                    context.Response.AddHeader(
                        name: "Content-Type",
                        value: context.Response.ContentType.ToString(),
                        append: false,
                        allowMultiple: false);

                    if (!string.IsNullOrWhiteSpace(context.Response.ContentLanguage))
                    {
                        context.Response.AddHeader(
                            name: "Content-Language",
                            value: context.Response.ContentLanguage,
                            append: false,
                            allowMultiple: false);
                    }


                    if (!context.Request.IsHeadRequest())
                    {
                        var contentLength = await context.Response.ResponseWriter.WriteType(
                            stream : httpcontext.Response.Body,
                            obj : context.Response.ResponseObject,
                            context.Response.ResponseWriterOptions,
                            (l) =>
                        {
                            context.Response.ContentLength = l;

                            context.Response.AddHeader(
                                name: "Content-Length",
                                value: l.ToString(CultureInfo.InvariantCulture),
                                append: false,
                                allowMultiple: false);

                            AddHeadersToResponse(httpcontext, context);
                        }).ConfigureAwait(false);

                        context.Response.ContentLength = contentLength;
                    }
                    else
                    {
                        using (var ms = new MemoryStream())
                        {
                            await context.Response.ResponseWriter.WriteType(
                                ms,
                                context.Response.ResponseObject,
                                context.Response.ResponseWriterOptions).ConfigureAwait(false);

                            context.Response.ResponseObject = null;
                            context.Response.ContentLength  = ms.Length;

                            context.Response.AddHeader(
                                name: "Content-Length",
                                value: ms.Length.ToString(CultureInfo.InvariantCulture),
                                append: false,
                                allowMultiple: false);

                            AddHeadersToResponse(httpcontext, context);
                        }
                    }
                }
                else
                {
                    context.Response.ContentLength = 0;
                    context.Response.AddHeader("Content-Length", "0");
                    AddHeadersToResponse(httpcontext, context);
                }

                context.Runtime.Duration.UtcEnd = DateTime.UtcNow;
            }

            return(true);
        }
예제 #6
0
        /// <summary>Merges the configurations.</summary>
        /// <param name="serviceProvider">The service provider.</param>
        /// <param name="defaultConfig">The default configuration.</param>
        /// <param name="endpointConfig">The endpoint configuration.</param>
        /// <returns></returns>
        public static IDeepSleepRequestConfiguration MergeConfigurations(
            IServiceProvider serviceProvider,
            IDeepSleepRequestConfiguration defaultConfig,
            IDeepSleepRequestConfiguration endpointConfig)
        {
            IDeepSleepRequestConfiguration systemConfig = ApiRequestContext.GetDefaultRequestConfiguration();

            IDeepSleepRequestConfiguration requestConfig = (endpointConfig != null)
                ? GetNewConfiguration(serviceProvider, endpointConfig)
                : GetNewConfiguration(serviceProvider, defaultConfig);

            if (requestConfig == null)
            {
                return(systemConfig);
            }


            requestConfig.ApiErrorResponseProvider = endpointConfig?.ApiErrorResponseProvider
                                                     ?? defaultConfig?.ApiErrorResponseProvider
                                                     ?? systemConfig.ApiErrorResponseProvider;

            requestConfig.AllowAnonymous = endpointConfig?.AllowAnonymous
                                           ?? defaultConfig?.AllowAnonymous
                                           ?? systemConfig.AllowAnonymous;

            requestConfig.EnableHeadForGetRequests = endpointConfig?.EnableHeadForGetRequests
                                                     ?? defaultConfig?.EnableHeadForGetRequests
                                                     ?? systemConfig.EnableHeadForGetRequests;


            // ----------------------------
            // Authorization Components
            // ----------------------------
            if (endpointConfig?.AuthorizationProviders != null || defaultConfig?.AuthorizationProviders != null)
            {
                if (endpointConfig?.AuthorizationProviders != null)
                {
                    requestConfig.AuthorizationProviders = new List <IAuthorizationComponent>(endpointConfig.AuthorizationProviders);
                }
                else if (defaultConfig?.AuthorizationProviders != null)
                {
                    requestConfig.AuthorizationProviders = new List <IAuthorizationComponent>(defaultConfig.AuthorizationProviders);
                }
                else
                {
                    requestConfig.AuthorizationProviders = systemConfig.AuthorizationProviders;
                }
            }
            else
            {
                requestConfig.AuthorizationProviders = systemConfig.AuthorizationProviders;
            }


            // ----------------------------
            // Authentication Components
            // ----------------------------
            if (endpointConfig?.AuthenticationProviders != null || defaultConfig?.AuthenticationProviders != null)
            {
                if (endpointConfig?.AuthenticationProviders != null)
                {
                    requestConfig.AuthenticationProviders = new List <IAuthenticationComponent>(endpointConfig.AuthenticationProviders);
                }
                else if (defaultConfig?.AuthenticationProviders != null)
                {
                    requestConfig.AuthenticationProviders = new List <IAuthenticationComponent>(defaultConfig.AuthenticationProviders);
                }
                else
                {
                    requestConfig.AuthenticationProviders = systemConfig.AuthenticationProviders;
                }
            }
            else
            {
                requestConfig.AuthenticationProviders = systemConfig.AuthenticationProviders;
            }


            // ----------------------------
            // Validator Components
            // ----------------------------
            if (endpointConfig?.Validators != null || defaultConfig?.Validators != null)
            {
                if (endpointConfig?.Validators != null)
                {
                    requestConfig.Validators = new List <IEndpointValidatorComponent>(endpointConfig.Validators);
                }
                else if (defaultConfig?.Validators != null)
                {
                    requestConfig.Validators = new List <IEndpointValidatorComponent>(defaultConfig.Validators);
                }
                else
                {
                    requestConfig.Validators = systemConfig.Validators;
                }
            }
            else
            {
                requestConfig.Validators = systemConfig.Validators;
            }

            // ----------------------------
            // Pipeline Components
            // ----------------------------
            if (endpointConfig?.PipelineComponents != null || defaultConfig?.PipelineComponents != null)
            {
                if (endpointConfig?.PipelineComponents != null)
                {
                    requestConfig.PipelineComponents = new List <IRequestPipelineComponent>(endpointConfig.PipelineComponents);
                }
                else if (defaultConfig?.PipelineComponents != null)
                {
                    requestConfig.PipelineComponents = new List <IRequestPipelineComponent>(defaultConfig.PipelineComponents);
                }
                else
                {
                    requestConfig.PipelineComponents = systemConfig.PipelineComponents;
                }
            }
            else
            {
                requestConfig.PipelineComponents = systemConfig.PipelineComponents;
            }

            // ----------------------------
            // Language Support Validation
            // ----------------------------
            if (endpointConfig?.LanguageSupport != null || defaultConfig?.LanguageSupport != null)
            {
                requestConfig.LanguageSupport = new ApiLanguageSupportConfiguration
                {
                    FallBackLanguage = endpointConfig?.LanguageSupport?.FallBackLanguage
                                       ?? defaultConfig?.LanguageSupport?.FallBackLanguage
                                       ?? systemConfig.LanguageSupport?.FallBackLanguage,

                    SupportedLanguages = new List <string>(endpointConfig?.LanguageSupport?.SupportedLanguages
                                                           ?? defaultConfig?.LanguageSupport?.SupportedLanguages
                                                           ?? systemConfig.LanguageSupport?.SupportedLanguages),

                    UseAcceptedLanguageAsThreadCulture = endpointConfig?.LanguageSupport?.UseAcceptedLanguageAsThreadCulture
                                                         ?? defaultConfig?.LanguageSupport?.UseAcceptedLanguageAsThreadCulture
                                                         ?? systemConfig.LanguageSupport?.UseAcceptedLanguageAsThreadCulture,

                    UseAcceptedLanguageAsThreadUICulture = endpointConfig?.LanguageSupport?.UseAcceptedLanguageAsThreadUICulture
                                                           ?? defaultConfig?.LanguageSupport?.UseAcceptedLanguageAsThreadUICulture
                                                           ?? systemConfig.LanguageSupport?.UseAcceptedLanguageAsThreadUICulture
                };

                var endpointSupportedLanguages = endpointConfig?.LanguageSupport?.SupportedLanguages != null
                    ? new List <string>(endpointConfig.LanguageSupport.SupportedLanguages)
                    : null;

                var defaultSupportedLanguages = defaultConfig?.LanguageSupport?.SupportedLanguages != null
                    ? new List <string>(defaultConfig.LanguageSupport.SupportedLanguages)
                    : null;

                requestConfig.LanguageSupport.SupportedLanguages = endpointSupportedLanguages ?? defaultSupportedLanguages ?? systemConfig.LanguageSupport?.SupportedLanguages;
            }
            else
            {
                requestConfig.LanguageSupport = systemConfig.LanguageSupport;
            }

            // ----------------------------
            // Merge Request Validation
            // ----------------------------
            if (endpointConfig?.RequestValidation != null || defaultConfig?.RequestValidation != null)
            {
                requestConfig.RequestValidation = new ApiRequestValidationConfiguration
                {
                    MaxHeaderLength = endpointConfig?.RequestValidation?.MaxHeaderLength
                                      ?? defaultConfig?.RequestValidation?.MaxHeaderLength
                                      ?? systemConfig.RequestValidation?.MaxHeaderLength,
                    MaxRequestUriLength = endpointConfig?.RequestValidation?.MaxRequestUriLength
                                          ?? defaultConfig?.RequestValidation?.MaxRequestUriLength
                                          ?? systemConfig.RequestValidation?.MaxRequestUriLength,
                    MaxRequestLength = endpointConfig?.RequestValidation?.MaxRequestLength
                                       ?? defaultConfig?.RequestValidation?.MaxRequestLength
                                       ?? systemConfig.RequestValidation?.MaxRequestLength,
                    AllowRequestBodyWhenNoModelDefined = endpointConfig?.RequestValidation?.AllowRequestBodyWhenNoModelDefined
                                                         ?? defaultConfig?.RequestValidation?.AllowRequestBodyWhenNoModelDefined
                                                         ?? systemConfig.RequestValidation?.AllowRequestBodyWhenNoModelDefined,
                    RequireContentLengthOnRequestBodyRequests = endpointConfig?.RequestValidation?.RequireContentLengthOnRequestBodyRequests
                                                                ?? defaultConfig?.RequestValidation?.RequireContentLengthOnRequestBodyRequests
                                                                ?? systemConfig.RequestValidation?.RequireContentLengthOnRequestBodyRequests
                };
            }
            else
            {
                requestConfig.RequestValidation = systemConfig.RequestValidation;
            }

            // ----------------------------
            // Merge Cache Directive
            // ----------------------------
            if (endpointConfig?.CacheDirective != null || defaultConfig?.CacheDirective != null)
            {
                requestConfig.CacheDirective = new ApiCacheDirectiveConfiguration
                {
                    Cacheability = endpointConfig?.CacheDirective?.Cacheability
                                   ?? defaultConfig?.CacheDirective?.Cacheability
                                   ?? systemConfig.CacheDirective?.Cacheability,

                    CacheLocation = endpointConfig?.CacheDirective?.CacheLocation
                                    ?? defaultConfig?.CacheDirective?.CacheLocation
                                    ?? systemConfig.CacheDirective?.CacheLocation,

                    ExpirationSeconds = endpointConfig?.CacheDirective?.ExpirationSeconds
                                        ?? defaultConfig?.CacheDirective?.ExpirationSeconds
                                        ?? systemConfig.CacheDirective?.ExpirationSeconds,

                    VaryHeaderValue = endpointConfig?.CacheDirective?.VaryHeaderValue
                                      ?? defaultConfig?.CacheDirective?.VaryHeaderValue
                                      ?? systemConfig.CacheDirective?.VaryHeaderValue
                };
            }
            else
            {
                requestConfig.CacheDirective = systemConfig.CacheDirective;
            }


            // ----------------------------
            // Merge Cross Origin Configuration
            // ----------------------------
            if (endpointConfig?.CrossOriginConfig != null || defaultConfig?.CrossOriginConfig != null)
            {
                requestConfig.CrossOriginConfig = new ApiCrossOriginConfiguration
                {
                    AllowCredentials = endpointConfig?.CrossOriginConfig?.AllowCredentials
                                       ?? defaultConfig?.CrossOriginConfig?.AllowCredentials
                                       ?? systemConfig?.CrossOriginConfig?.AllowCredentials,
                    MaxAgeSeconds = endpointConfig?.CrossOriginConfig?.MaxAgeSeconds
                                    ?? defaultConfig?.CrossOriginConfig?.MaxAgeSeconds
                                    ?? systemConfig?.CrossOriginConfig?.MaxAgeSeconds
                };

                var endpointAllowedOrigins = endpointConfig?.CrossOriginConfig?.AllowedOrigins != null
                    ? new List <string>(endpointConfig.CrossOriginConfig.AllowedOrigins)
                    : null;

                var defaultAllowedOrigins = defaultConfig?.CrossOriginConfig?.AllowedOrigins != null
                    ? new List <string>(defaultConfig.CrossOriginConfig.AllowedOrigins)
                    : null;

                requestConfig.CrossOriginConfig.AllowedOrigins = endpointAllowedOrigins ?? defaultAllowedOrigins ?? systemConfig.CrossOriginConfig?.AllowedOrigins;

                var endpointExposeHeaders = endpointConfig?.CrossOriginConfig?.ExposeHeaders != null
                    ? new List <string>(endpointConfig.CrossOriginConfig.ExposeHeaders)
                    : null;

                var defaultExposeHeaders = defaultConfig?.CrossOriginConfig?.ExposeHeaders != null
                    ? new List <string>(defaultConfig.CrossOriginConfig.ExposeHeaders)
                    : null;

                requestConfig.CrossOriginConfig.ExposeHeaders = endpointExposeHeaders ?? defaultExposeHeaders ?? systemConfig.CrossOriginConfig?.ExposeHeaders;

                var endpointAllowedHeaders = endpointConfig?.CrossOriginConfig?.AllowedHeaders != null
                    ? new List <string>(endpointConfig.CrossOriginConfig.AllowedHeaders)
                    : null;

                var defaultAllowedHeaders = defaultConfig?.CrossOriginConfig?.AllowedHeaders != null
                    ? new List <string>(defaultConfig.CrossOriginConfig.AllowedHeaders)
                    : null;

                requestConfig.CrossOriginConfig.AllowedHeaders = endpointAllowedHeaders ?? defaultAllowedHeaders ?? systemConfig.CrossOriginConfig?.AllowedHeaders;
            }
            else
            {
                requestConfig.CrossOriginConfig = systemConfig.CrossOriginConfig;
            }


            // ----------------------------
            // Merge Read Write Configuration
            // ----------------------------
            if (endpointConfig?.ReadWriteConfiguration != null || defaultConfig?.ReadWriteConfiguration != null)
            {
                requestConfig.ReadWriteConfiguration = new ApiMediaSerializerConfiguration
                {
                    ReaderResolver = endpointConfig?.ReadWriteConfiguration?.ReaderResolver
                                     ?? defaultConfig?.ReadWriteConfiguration?.ReaderResolver
                                     ?? systemConfig.ReadWriteConfiguration?.ReaderResolver,

                    WriterResolver = endpointConfig?.ReadWriteConfiguration?.WriterResolver
                                     ?? defaultConfig?.ReadWriteConfiguration?.WriterResolver
                                     ?? systemConfig.ReadWriteConfiguration?.WriterResolver,

                    AcceptHeaderOverride = endpointConfig?.ReadWriteConfiguration?.AcceptHeaderOverride
                                           ?? defaultConfig?.ReadWriteConfiguration?.AcceptHeaderOverride
                                           ?? systemConfig.ReadWriteConfiguration?.AcceptHeaderOverride,
                };

                var endpointReadableMediaTypes = endpointConfig?.ReadWriteConfiguration?.ReadableMediaTypes != null
                    ? new List <string>(endpointConfig.ReadWriteConfiguration.ReadableMediaTypes)
                    : null;

                var defaultReadableMediaTypes = defaultConfig?.ReadWriteConfiguration?.ReadableMediaTypes != null
                    ? new List <string>(defaultConfig.ReadWriteConfiguration.ReadableMediaTypes)
                    : null;

                var endpointWriteableMediaTypes = endpointConfig?.ReadWriteConfiguration?.WriteableMediaTypes != null
                    ? new List <string>(endpointConfig.ReadWriteConfiguration.WriteableMediaTypes)
                    : null;

                var defaultWriteableMediaTypes = defaultConfig?.ReadWriteConfiguration?.WriteableMediaTypes != null
                    ? new List <string>(defaultConfig.ReadWriteConfiguration.WriteableMediaTypes)
                    : null;

                requestConfig.ReadWriteConfiguration.ReadableMediaTypes = endpointReadableMediaTypes
                                                                          ?? defaultReadableMediaTypes
                                                                          ?? systemConfig.ReadWriteConfiguration?.ReadableMediaTypes;

                requestConfig.ReadWriteConfiguration.WriteableMediaTypes = endpointWriteableMediaTypes
                                                                           ?? defaultWriteableMediaTypes
                                                                           ?? systemConfig.ReadWriteConfiguration?.WriteableMediaTypes;
            }
            else
            {
                requestConfig.ReadWriteConfiguration = systemConfig.ReadWriteConfiguration;
            }


            // ------------------------------------
            // Merge Validation Error Configuration
            // ------------------------------------
            if (endpointConfig?.ValidationErrorConfiguration != null || defaultConfig?.ValidationErrorConfiguration != null)
            {
                requestConfig.ValidationErrorConfiguration = new ApiValidationErrorConfiguration
                {
                    UriBindingError = endpointConfig?.ValidationErrorConfiguration?.UriBindingError
                                      ?? defaultConfig?.ValidationErrorConfiguration?.UriBindingError
                                      ?? systemConfig.ValidationErrorConfiguration?.UriBindingError,

                    UriBindingValueError = endpointConfig?.ValidationErrorConfiguration?.UriBindingValueError
                                           ?? defaultConfig?.ValidationErrorConfiguration?.UriBindingValueError
                                           ?? systemConfig.ValidationErrorConfiguration?.UriBindingValueError,

                    RequestDeserializationError = endpointConfig?.ValidationErrorConfiguration?.RequestDeserializationError
                                                  ?? defaultConfig?.ValidationErrorConfiguration?.RequestDeserializationError
                                                  ?? systemConfig.ValidationErrorConfiguration?.RequestDeserializationError,

                    HttpStatusMode = endpointConfig?.ValidationErrorConfiguration?.HttpStatusMode
                                     ?? defaultConfig?.ValidationErrorConfiguration?.HttpStatusMode
                                     ?? systemConfig.ValidationErrorConfiguration.HttpStatusMode
                };
            }
            else
            {
                requestConfig.ValidationErrorConfiguration = systemConfig.ValidationErrorConfiguration;
            }


            return(requestConfig);
        }
예제 #7
0
        /// <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);
        }
예제 #8
0
        /// <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);
        }