// 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.Net; using System.Security.Cryptography.X509Certificates; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.Kestrel.Https; using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal; using Microsoft.Extensions.Configuration; namespace Microsoft.AspNetCore.Server.Kestrel.Core { /// /// Provides programmatic configuration of Kestrel-specific features. /// public class KestrelServerOptions { /// /// Configures the endpoints that Kestrel should listen to. /// /// /// If this list is empty, the server.urls setting (e.g. UseUrls) is used. /// internal List ListenOptions { get; } = new List(); /// /// Gets or sets whether the Server header should be included in each response. /// /// /// Defaults to true. /// public bool AddServerHeader { get; set; } = true; /// /// Gets or sets a value that determines how Kestrel should schedule user callbacks. /// /// The default mode is public SchedulingMode ApplicationSchedulingMode { get; set; } = SchedulingMode.Default; /// /// Gets or sets a value that controls whether synchronous IO is allowed for the and /// /// /// Defaults to true. /// public bool AllowSynchronousIO { get; set; } = true; /// /// Enables the Listen options callback to resolve and use services registered by the application during startup. /// Typically initialized by UseKestrel()"/>. /// public IServiceProvider ApplicationServices { get; set; } /// /// Provides access to request limit options. /// public KestrelServerLimits Limits { get; } = new KestrelServerLimits(); /// /// Provides a configuration source where endpoints will be loaded from on server start. /// The default is null. /// public KestrelConfigurationLoader ConfigurationLoader { get; set; } /// /// A default configuration action for all endpoints. Use for Listen, configuration, the default url, and URLs. /// private Action EndpointDefaults { get; set; } = _ => { }; /// /// A default configuration action for all https endpoints. /// private Action HttpsDefaults { get; set; } = _ => { }; /// /// The default server certificate for https endpoints. This is applied before HttpsDefaults. /// internal X509Certificate2 DefaultCertificate { get; set; } /// /// Specifies a configuration Action to run for each newly created endpoint. Calling this again will replace /// the prior action. /// public void ConfigureEndpointDefaults(Action configureOptions) { EndpointDefaults = configureOptions ?? throw new ArgumentNullException(nameof(configureOptions)); } internal void ApplyEndpointDefaults(ListenOptions listenOptions) { listenOptions.KestrelServerOptions = this; EndpointDefaults(listenOptions); } /// /// Specifies a configuration Action to run for each newly created https endpoint. Calling this again will replace /// the prior action. /// public void ConfigureHttpsDefaults(Action configureOptions) { HttpsDefaults = configureOptions ?? throw new ArgumentNullException(nameof(configureOptions)); } internal void ApplyHttpsDefaults(HttpsConnectionAdapterOptions httpsOptions) { httpsOptions.ServerCertificate = DefaultCertificate; HttpsDefaults(httpsOptions); } /// /// Creates a configuration loader for setting up Kestrel. /// public KestrelConfigurationLoader Configure() { var loader = new KestrelConfigurationLoader(this, new ConfigurationBuilder().Build()); ConfigurationLoader = loader; return loader; } /// /// Creates a configuration loader for setting up Kestrel that takes an IConfiguration as input. /// This configuration must be scoped to the configuration section for Kestrel. /// public KestrelConfigurationLoader Configure(IConfiguration config) { var loader = new KestrelConfigurationLoader(this, config); ConfigurationLoader = loader; return loader; } /// /// Bind to given IP address and port. /// public void Listen(IPAddress address, int port) { Listen(address, port, _ => { }); } /// /// Bind to given IP address and port. /// The callback configures endpoint-specific settings. /// public void Listen(IPAddress address, int port, Action configure) { if (address == null) { throw new ArgumentNullException(nameof(address)); } Listen(new IPEndPoint(address, port), configure); } /// /// Bind to given IP endpoint. /// public void Listen(IPEndPoint endPoint) { Listen(endPoint, _ => { }); } /// /// Bind to given IP address and port. /// The callback configures endpoint-specific settings. /// public void Listen(IPEndPoint endPoint, Action configure) { if (endPoint == null) { throw new ArgumentNullException(nameof(endPoint)); } if (configure == null) { throw new ArgumentNullException(nameof(configure)); } var listenOptions = new ListenOptions(endPoint); ApplyEndpointDefaults(listenOptions); configure(listenOptions); ListenOptions.Add(listenOptions); } /// /// Listens on ::1 and 127.0.0.1 with the given port. Requesting a dynamic port by specifying 0 is not supported /// for this type of endpoint. /// public void ListenLocalhost(int port) => ListenLocalhost(port, options => { }); /// /// Listens on ::1 and 127.0.0.1 with the given port. Requesting a dynamic port by specifying 0 is not supported /// for this type of endpoint. /// public void ListenLocalhost(int port, Action configure) { if (configure == null) { throw new ArgumentNullException(nameof(configure)); } var listenOptions = new LocalhostListenOptions(port); ApplyEndpointDefaults(listenOptions); configure(listenOptions); ListenOptions.Add(listenOptions); } /// /// Listens on all IPs using IPv6 [::], or IPv4 0.0.0.0 if IPv6 is not supported. /// public void ListenAnyIP(int port) => ListenAnyIP(port, options => { }); /// /// Listens on all IPs using IPv6 [::], or IPv4 0.0.0.0 if IPv6 is not supported. /// public void ListenAnyIP(int port, Action configure) { if (configure == null) { throw new ArgumentNullException(nameof(configure)); } var listenOptions = new AnyIPListenOptions(port); ApplyEndpointDefaults(listenOptions); configure(listenOptions); ListenOptions.Add(listenOptions); } /// /// Bind to given Unix domain socket path. /// public void ListenUnixSocket(string socketPath) { ListenUnixSocket(socketPath, _ => { }); } /// /// Bind to given Unix domain socket path. /// Specify callback to configure endpoint-specific settings. /// public void ListenUnixSocket(string socketPath, Action configure) { if (socketPath == null) { throw new ArgumentNullException(nameof(socketPath)); } if (socketPath.Length == 0 || socketPath[0] != '/') { throw new ArgumentException(CoreStrings.UnixSocketPathMustBeAbsolute, nameof(socketPath)); } if (configure == null) { throw new ArgumentNullException(nameof(configure)); } var listenOptions = new ListenOptions(socketPath); ApplyEndpointDefaults(listenOptions); configure(listenOptions); ListenOptions.Add(listenOptions); } /// /// Open a socket file descriptor. /// public void ListenHandle(ulong handle) { ListenHandle(handle, _ => { }); } /// /// Open a socket file descriptor. /// The callback configures endpoint-specific settings. /// public void ListenHandle(ulong handle, Action configure) { if (configure == null) { throw new ArgumentNullException(nameof(configure)); } var listenOptions = new ListenOptions(handle); ApplyEndpointDefaults(listenOptions); configure(listenOptions); ListenOptions.Add(listenOptions); } } }