Example #1
0
        public void ParseAddressIP(string address, string ip, int port, bool isHttps)
        {
            var listenOptions = AddressBinder.ParseAddress(address, out var https);

            Assert.IsType <IPEndPoint>(listenOptions.EndPoint);
            Assert.Equal(IPAddress.Parse(ip), listenOptions.IPEndPoint.Address);
            Assert.Equal(port, listenOptions.IPEndPoint.Port);
            Assert.Equal(isHttps, https);
        }
Example #2
0
        public void ParseAddressUnixPipe()
        {
            var options       = new KestrelServerOptions();
            var listenOptions = AddressBinder.ParseAddress("http://unix:/tmp/kestrel-test.sock", out var https);

            Assert.Equal(ListenType.SocketPath, listenOptions.Type);
            Assert.Equal("/tmp/kestrel-test.sock", listenOptions.SocketPath);
            Assert.False(https);
        }
Example #3
0
        public void ParseAddressIP(string address, string ip, int port)
        {
            var options       = new KestrelServerOptions();
            var listenOptions = AddressBinder.ParseAddress(address, options, Mock.Of <IDefaultHttpsProvider>());

            Assert.Equal(ListenType.IPEndPoint, listenOptions.Type);
            Assert.Equal(IPAddress.Parse(ip), listenOptions.IPEndPoint.Address);
            Assert.Equal(port, listenOptions.IPEndPoint.Port);
        }
Example #4
0
        public void ParseAddressIP(string address, string ip, int port, bool isHttps)
        {
            var options       = new KestrelServerOptions();
            var listenOptions = AddressBinder.ParseAddress(address, out var https);

            Assert.Equal(ListenType.IPEndPoint, listenOptions.Type);
            Assert.Equal(IPAddress.Parse(ip), listenOptions.IPEndPoint.Address);
            Assert.Equal(port, listenOptions.IPEndPoint.Port);
            Assert.Equal(isHttps, https);
        }
        public void ParseAddressDefaultsToAnyIPOnInvalidIPAddress(string host)
        {
            var listenOptions = AddressBinder.ParseAddress($"http://{host}", out var https);

            Assert.IsType <AnyIPListenOptions>(listenOptions);
            Assert.IsType <IPEndPoint>(listenOptions.EndPoint);
            Assert.Equal(IPAddress.IPv6Any, listenOptions.IPEndPoint.Address);
            Assert.Equal(80, listenOptions.IPEndPoint.Port);
            Assert.False(https);
        }
        public void ParseAddressLocalhost()
        {
            var listenOptions = AddressBinder.ParseAddress("http://localhost", out var https);

            Assert.IsType <LocalhostListenOptions>(listenOptions);
            Assert.IsType <IPEndPoint>(listenOptions.EndPoint);
            Assert.Equal(IPAddress.Loopback, listenOptions.IPEndPoint.Address);
            Assert.Equal(80, listenOptions.IPEndPoint.Port);
            Assert.False(https);
        }
Example #7
0
        public void ParseAddressLocalhost()
        {
            var options       = new KestrelServerOptions();
            var listenOptions = AddressBinder.ParseAddress("http://localhost", options, Mock.Of <IDefaultHttpsProvider>());

            Assert.IsType <LocalhostListenOptions>(listenOptions);
            Assert.Equal(ListenType.IPEndPoint, listenOptions.Type);
            Assert.Equal(IPAddress.Loopback, listenOptions.IPEndPoint.Address);
            Assert.Equal(80, listenOptions.IPEndPoint.Port);
        }
Example #8
0
        public void ParseAddressDefaultsToAnyIPOnInvalidIPAddress(string host)
        {
            var options       = new KestrelServerOptions();
            var listenOptions = AddressBinder.ParseAddress($"http://{host}", options, Mock.Of <IDefaultHttpsProvider>());

            Assert.IsType <AnyIPListenOptions>(listenOptions);
            Assert.Equal(ListenType.IPEndPoint, listenOptions.Type);
            Assert.Equal(IPAddress.IPv6Any, listenOptions.IPEndPoint.Address);
            Assert.Equal(80, listenOptions.IPEndPoint.Port);
        }
        public void Load()
        {
            if (Options.ConfigurationLoader == null)
            {
                // The loader has already been run.
                return;
            }
            Options.ConfigurationLoader = null;

            var configReader = new ConfigurationReader(Configuration);

            LoadDefaultCert(configReader);

            foreach (var endpoint in configReader.Endpoints)
            {
                var listenOptions = AddressBinder.ParseAddress(endpoint.Url, out var https);
                Options.ApplyEndpointDefaults(listenOptions);

                // Compare to UseHttps(httpsOptions => { })
                var httpsOptions = new HttpsConnectionAdapterOptions();
                if (https)
                {
                    // Defaults
                    Options.ApplyHttpsDefaults(httpsOptions);

                    // Specified
                    httpsOptions.ServerCertificate = LoadCertificate(endpoint.Certificate, endpoint.Name)
                                                     ?? httpsOptions.ServerCertificate;
                }

                if (EndpointConfigurations.TryGetValue(endpoint.Name, out var configureEndpoint))
                {
                    var endpointConfig = new EndpointConfiguration(https, listenOptions, httpsOptions, endpoint.ConfigSection);
                    configureEndpoint(endpointConfig);
                }

                // EndpointDefaults or configureEndpoint may have added an https adapter.
                if (https && !listenOptions.ConnectionAdapters.Any(f => f.IsHttps))
                {
                    if (httpsOptions.ServerCertificate == null)
                    {
                        throw new InvalidOperationException(CoreStrings.NoCertSpecifiedNoDevelopmentCertificateFound);
                    }

                    listenOptions.UseHttps(httpsOptions);
                }

                Options.ListenOptions.Add(listenOptions);
            }

            foreach (var action in EndpointsToAdd)
            {
                action();
            }
        }
Example #10
0
        public void ParseAddressLocalhost()
        {
            var options       = new KestrelServerOptions();
            var listenOptions = AddressBinder.ParseAddress("http://localhost", out var https);

            Assert.IsType <LocalhostListenOptions>(listenOptions);
            Assert.Equal(ListenType.IPEndPoint, listenOptions.Type);
            Assert.Equal(IPAddress.Loopback, listenOptions.IPEndPoint.Address);
            Assert.Equal(80, listenOptions.IPEndPoint.Port);
            Assert.False(https);
        }
        public async Task WrapsAddressInUseExceptionAsIOException()
        {
            var addresses = new ServerAddressesFeature();

            addresses.Addresses.Add("http://localhost:5000");
            var options = new KestrelServerOptions();

            await Assert.ThrowsAsync <IOException>(() =>
                                                   AddressBinder.BindAsync(addresses,
                                                                           options,
                                                                           NullLogger.Instance,
                                                                           endpoint => throw new AddressInUseException("already in use")));
        }
        public async Task StartAsync <TContext>(IHttpApplication <TContext> application, CancellationToken cancellationToken)
        {
            try
            {
                if (!BitConverter.IsLittleEndian)
                {
                    throw new PlatformNotSupportedException(CoreStrings.BigEndianNotSupported);
                }

                ValidateOptions();

                if (_hasStarted)
                {
                    // The server has already started and/or has not been cleaned up yet
                    throw new InvalidOperationException(CoreStrings.ServerAlreadyStarted);
                }
                _hasStarted = true;

                ServiceContext.Heartbeat?.Start();

                async Task OnBind(ListenOptions endpoint)
                {
                    // Add the HTTP middleware as the terminal connection middleware
                    endpoint.UseHttpServer(endpoint.ConnectionAdapters, ServiceContext, application, endpoint.Protocols);

                    var connectionDelegate = endpoint.Build();

                    // Add the connection limit middleware
                    if (Options.Limits.MaxConcurrentConnections.HasValue)
                    {
                        connectionDelegate = new ConnectionLimitMiddleware(connectionDelegate, Options.Limits.MaxConcurrentConnections.Value, Trace).OnConnectionAsync;
                    }

                    var connectionDispatcher = new ConnectionDispatcher(ServiceContext, connectionDelegate);
                    var transport            = _transportFactory.Create(endpoint, connectionDispatcher);

                    _transports.Add(transport);

                    await transport.BindAsync().ConfigureAwait(false);
                }

                await AddressBinder.BindAsync(_serverAddresses, Options, Trace, OnBind).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                Trace.LogCritical(0, ex, "Unable to start Kestrel.");
                Dispose();
                throw;
            }
        }
        public void Load()
        {
            if (_loaded)
            {
                return;
            }
            _loaded = true;
            LoadDefaultCert(ConfigurationReader);
            foreach (var endpoint in ConfigurationReader.Endpoints)
            {
                var listenOptions = AddressBinder.ParseAddress(endpoint.Url, out var https);
                Options.ApplyEndpointDefaults(listenOptions);

                if (endpoint.Protocols.HasValue)
                {
                    listenOptions.Protocols = endpoint.Protocols.Value;
                }
                var httpsOptions = new HttpsConnectionAdapterOptions();
                if (https)
                {
                    Options.ApplyHttpsDefaults(httpsOptions);
                    httpsOptions.ServerCertificate = LoadCertificate(endpoint.Certificate, endpoint.Name) ?? httpsOptions.ServerCertificate;
                    Options.ApplyDefaultCert(httpsOptions);
                }

                if (EndpointConfigurations.TryGetValue(endpoint.Name, out var configureEndpoint))
                {
                    var endpointConfig = new EndpointConfiguration(https, listenOptions, httpsOptions);
                    configureEndpoint(endpointConfig);
                }

                if (https && !listenOptions.IsTls)
                {
                    if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null)
                    {
                        throw new InvalidOperationException("Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found or is out of date.\nTo generate a developer certificate run 'dotnet dev-certs https'. To trust the certificate (Windows and macOS only) run 'dotnet dev-certs https --trust'.\nFor more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054.");
                    }
                    listenOptions.UseHttps(httpsOptions);
                }

                Options.ListenOptions.Add(listenOptions);
            }

            foreach (var action in EndpointsToAdd)
            {
                action();
            }
        }
Example #14
0
    public async Task WrapsAddressInUseExceptionAsIOException()
    {
        var addresses = new ServerAddressesFeature();

        addresses.InternalCollection.Add("http://localhost:5000");
        var options = new KestrelServerOptions();

        var addressBindContext = TestContextFactory.CreateAddressBindContext(
            addresses,
            options,
            NullLogger.Instance,
            endpoint => throw new AddressInUseException("already in use"));

        await Assert.ThrowsAsync <IOException>(() =>
                                               AddressBinder.BindAsync(options.ListenOptions, addressBindContext, CancellationToken.None));
    }
Example #15
0
        public async Task WrapsAddressInUseExceptionAsIOException()
        {
            var addresses = new ServerAddressesFeature();

            addresses.InternalCollection.Add("http://localhost:5000");
            var options = new KestrelServerOptions();

            var addressBindContext = new AddressBindContext
            {
                ServerAddressesFeature = addresses,
                ServerOptions          = options,
                Logger        = NullLogger.Instance,
                CreateBinding = endpoint => throw new AddressInUseException("already in use"),
            };

            await Assert.ThrowsAsync <IOException>(() =>
                                                   AddressBinder.BindAsync(options.ListenOptions, addressBindContext));
        }
Example #16
0
        public async Task DefaultAddressBinderWithoutDevCertButHttpsConfiguredBindsToHttpsPorts()
        {
            var x509Certificate2 = TestResources.GetTestCertificate();
            var logger           = new MockLogger();
            var addresses        = new ServerAddressesFeature();
            var services         = new ServiceCollection();

            services.AddLogging();
            var options = new KestrelServerOptions()
            {
                // This stops the dev cert from being loaded
                IsDevCertLoaded     = true,
                ApplicationServices = services.BuildServiceProvider()
            };

            options.ConfigureEndpointDefaults(e =>
            {
                if (e.IPEndPoint.Port == 5001)
                {
                    e.UseHttps(new HttpsConnectionAdapterOptions {
                        ServerCertificate = x509Certificate2
                    });
                }
            });

            var endpoints = new List <ListenOptions>();

            var addressBindContext = new AddressBindContext
            {
                ServerAddressesFeature = addresses,
                ServerOptions          = options,
                Logger        = logger,
                CreateBinding = listenOptions =>
                {
                    endpoints.Add(listenOptions);
                    return(Task.CompletedTask);
                },
            };

            await AddressBinder.BindAsync(options.ListenOptions, addressBindContext);

            Assert.Contains(endpoints, e => e.IPEndPoint.Port == 5000 && !e.IsTls);
            Assert.Contains(endpoints, e => e.IPEndPoint.Port == 5001 && e.IsTls);
        }
Example #17
0
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            try
            {
                if (!BitConverter.IsLittleEndian)
                {
                    throw new PlatformNotSupportedException("Does not support big-endian architectures.");
                }

                if (_hasStarted)
                {
                    // The server has already started and/or has not been cleaned up yet
                    throw new InvalidOperationException("Server has already started.");
                }
                _hasStarted = true;
                _heartbeat.Start();

                async Task OnBind(ListenOptions endpoint)
                {
                    var connectionDelegate = endpoint.Build();

                    // Add the connection limit middleware
                    if (Options.Limits.MaxConcurrentConnections.HasValue)
                    {
                        connectionDelegate = new ConnectionLimitMiddleware(connectionDelegate, Options.Limits.MaxConcurrentConnections.Value, Trace).OnConnectionAsync;
                    }

                    var connectionDispatcher = new ConnectionDispatcher(ServiceContext, connectionDelegate);
                    var transport            = _transportFactory.Create(endpoint, connectionDispatcher);

                    _transports.Add(transport);

                    await transport.BindAsync().ConfigureAwait(false);
                }

                await AddressBinder.BindAsync(_serverAddresses, Options, Trace, OnBind).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                Trace.LogCritical(0, ex, "Unable to start Kestrel.");
                Dispose();
                throw;
            }
        }
Example #18
0
    public async Task FlowsCancellationTokenToCreateBinddingCallback()
    {
        var addresses = new ServerAddressesFeature();

        addresses.InternalCollection.Add("http://localhost:5000");
        var options = new KestrelServerOptions();

        var addressBindContext = TestContextFactory.CreateAddressBindContext(
            addresses,
            options,
            NullLogger.Instance,
            (endpoint, cancellationToken) =>
        {
            cancellationToken.ThrowIfCancellationRequested();
            return(Task.CompletedTask);
        });

        await Assert.ThrowsAsync <OperationCanceledException>(() =>
                                                              AddressBinder.BindAsync(options.ListenOptions, addressBindContext, new CancellationToken(true)));
    }
Example #19
0
        public async Task DefaultsToIPv6AnyOnInvalidIPAddress(string host)
        {
            var addresses = new ServerAddressesFeature();

            addresses.Addresses.Add($"http://{host}");
            var options = new List <ListenOptions>();

            var tcs = new TaskCompletionSource <ListenOptions>();
            await AddressBinder.BindAsync(addresses,
                                          options,
                                          NullLogger.Instance,
                                          endpoint =>
            {
                tcs.TrySetResult(endpoint);
                return(Task.CompletedTask);
            });

            var result = await tcs.Task;

            Assert.Equal(IPAddress.IPv6Any, result.IPEndPoint.Address);
        }
Example #20
0
        public async Task FallbackToIPv4WhenIPv6AnyBindFails(string address)
        {
            var logger    = new MockLogger();
            var addresses = new ServerAddressesFeature();

            addresses.InternalCollection.Add(address);
            var options = new KestrelServerOptions();

            var ipV6Attempt = false;
            var ipV4Attempt = false;

            var addressBindContext = new AddressBindContext
            {
                ServerAddressesFeature = addresses,
                ServerOptions          = options,
                Logger        = logger,
                CreateBinding = endpoint =>
                {
                    if (endpoint.IPEndPoint.Address == IPAddress.IPv6Any)
                    {
                        ipV6Attempt = true;
                        throw new InvalidOperationException("EAFNOSUPPORT");
                    }

                    if (endpoint.IPEndPoint.Address == IPAddress.Any)
                    {
                        ipV4Attempt = true;
                    }

                    return(Task.CompletedTask);
                },
            };

            await AddressBinder.BindAsync(options.ListenOptions, addressBindContext);

            Assert.True(ipV4Attempt, "Should have attempted to bind to IPAddress.Any");
            Assert.True(ipV6Attempt, "Should have attempted to bind to IPAddress.IPv6Any");
            Assert.Contains(logger.Messages, f => f.Equals(CoreStrings.FormatFallbackToIPv4Any(80)));
        }
Example #21
0
        public async Task StartAsync <TContext>(IHttpApplication <TContext> application, CancellationToken cancellationToken)
        {
            try
            {
                if (!BitConverter.IsLittleEndian)
                {
                    throw new PlatformNotSupportedException(CoreStrings.BigEndianNotSupported);
                }

                ValidateOptions();

                if (_hasStarted)
                {
                    // The server has already started and/or has not been cleaned up yet
                    throw new InvalidOperationException(CoreStrings.ServerAlreadyStarted);
                }
                _hasStarted = true;
                _heartbeat.Start();

                async Task OnBind(ListenOptions endpoint)
                {
                    var connectionHandler = new ConnectionHandler <TContext>(endpoint, ServiceContext, application);
                    var transport         = _transportFactory.Create(endpoint, connectionHandler);

                    _transports.Add(transport);

                    await transport.BindAsync().ConfigureAwait(false);
                }

                await AddressBinder.BindAsync(_serverAddresses, Options.ListenOptions, Trace, OnBind).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                Trace.LogCritical(0, ex, "Unable to start Kestrel.");
                Dispose();
                throw;
            }
        }
Example #22
0
        internal virtual async Task BindAsync(AddressBindContext context)
        {
            await AddressBinder.BindEndpointAsync(this, context).ConfigureAwait(false);

            context.Addresses.Add(GetDisplayName());
        }
 public void DoesNotCreateIPEndPointOnInvalidIPAddress(string address)
 {
     Assert.False(AddressBinder.TryCreateIPEndPoint(
                      BindingAddress.Parse(address), out var endpoint));
 }
        public void Load()
        {
            if (_loaded)
            {
                // The loader has already been run.
                return;
            }
            _loaded = true;

            Options.Latin1RequestHeaders = ConfigurationReader.Latin1RequestHeaders;

            LoadDefaultCert(ConfigurationReader);

            foreach (var endpoint in ConfigurationReader.Endpoints)
            {
                var listenOptions = AddressBinder.ParseAddress(endpoint.Url, out var https);
                Options.ApplyEndpointDefaults(listenOptions);

                if (endpoint.Protocols.HasValue)
                {
                    listenOptions.Protocols = endpoint.Protocols.Value;
                }

                // Compare to UseHttps(httpsOptions => { })
                var httpsOptions = new HttpsConnectionAdapterOptions();
                if (https)
                {
                    // Defaults
                    Options.ApplyHttpsDefaults(httpsOptions);

                    // Specified
                    httpsOptions.ServerCertificate = LoadCertificate(endpoint.Certificate, endpoint.Name)
                                                     ?? httpsOptions.ServerCertificate;

                    // Fallback
                    Options.ApplyDefaultCert(httpsOptions);
                }

                if (EndpointConfigurations.TryGetValue(endpoint.Name, out var configureEndpoint))
                {
                    var endpointConfig = new EndpointConfiguration(https, listenOptions, httpsOptions, endpoint.ConfigSection);
                    configureEndpoint(endpointConfig);
                }

                // EndpointDefaults or configureEndpoint may have added an https adapter.
                if (https && !listenOptions.IsTls)
                {
                    if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null)
                    {
                        throw new InvalidOperationException(CoreStrings.NoCertSpecifiedNoDevelopmentCertificateFound);
                    }

                    listenOptions.UseHttps(httpsOptions);
                }

                Options.ListenOptions.Add(listenOptions);
            }

            foreach (var action in EndpointsToAdd)
            {
                action();
            }
        }
Example #25
0
 public void DoesNotCreateIPEndPointOnInvalidIPAddress(string address)
 {
     Assert.False(AddressBinder.TryCreateIPEndPoint(
                      ServerAddress.FromUrl(address), out var endpoint));
 }
Example #26
0
        // Adds endpoints from config to KestrelServerOptions.ConfigurationBackedListenOptions and configures some other options.
        // Any endpoints that were removed from the last time endpoints were loaded are returned.
        internal (List <ListenOptions>, List <ListenOptions>) Reload()
        {
            var endpointsToStop  = Options.ConfigurationBackedListenOptions.ToList();
            var endpointsToStart = new List <ListenOptions>();

            Options.ConfigurationBackedListenOptions.Clear();
            DefaultCertificateConfig = null;

            ConfigurationReader = new ConfigurationReader(Configuration);

            Options.Latin1RequestHeaders = ConfigurationReader.Latin1RequestHeaders;

            LoadDefaultCert(ConfigurationReader);

            foreach (var endpoint in ConfigurationReader.Endpoints)
            {
                var listenOptions = AddressBinder.ParseAddress(endpoint.Url, out var https);

                Options.ApplyEndpointDefaults(listenOptions);

                if (endpoint.Protocols.HasValue)
                {
                    listenOptions.Protocols = endpoint.Protocols.Value;
                }
                else
                {
                    // Ensure endpoint is reloaded if it used the default protocol and the protocol changed.
                    // listenOptions.Protocols should already be set to this by ApplyEndpointDefaults.
                    endpoint.Protocols = ConfigurationReader.EndpointDefaults.Protocols;
                }

                // Compare to UseHttps(httpsOptions => { })
                var httpsOptions = new HttpsConnectionAdapterOptions();
                if (https)
                {
                    // Defaults
                    Options.ApplyHttpsDefaults(httpsOptions);

                    // Specified
                    httpsOptions.ServerCertificate = LoadCertificate(endpoint.Certificate, endpoint.Name)
                                                     ?? httpsOptions.ServerCertificate;

                    if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null)
                    {
                        // Fallback
                        Options.ApplyDefaultCert(httpsOptions);

                        // Ensure endpoint is reloaded if it used the default certificate and the certificate changed.
                        endpoint.Certificate = DefaultCertificateConfig;
                    }
                }

                // Now that defaults have been loaded, we can compare to the currently bound endpoints to see if the config changed.
                // There's no reason to rerun an EndpointConfigurations callback if nothing changed.
                var matchingBoundEndpoints = endpointsToStop.Where(o => o.EndpointConfig == endpoint).ToList();

                if (matchingBoundEndpoints.Count > 0)
                {
                    endpointsToStop.RemoveAll(o => o.EndpointConfig == endpoint);
                    Options.ConfigurationBackedListenOptions.AddRange(matchingBoundEndpoints);
                    continue;
                }

                if (EndpointConfigurations.TryGetValue(endpoint.Name, out var configureEndpoint))
                {
                    var endpointConfig = new EndpointConfiguration(https, listenOptions, httpsOptions, endpoint.ConfigSection);
                    configureEndpoint(endpointConfig);
                }

                // EndpointDefaults or configureEndpoint may have added an https adapter.
                if (https && !listenOptions.IsTls)
                {
                    if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null)
                    {
                        throw new InvalidOperationException(CoreStrings.NoCertSpecifiedNoDevelopmentCertificateFound);
                    }

                    listenOptions.UseHttps(httpsOptions);
                }

                listenOptions.EndpointConfig = endpoint;

                endpointsToStart.Add(listenOptions);
                Options.ConfigurationBackedListenOptions.Add(listenOptions);
            }

            return(endpointsToStop, endpointsToStart);
        }
Example #27
0
    // Adds endpoints from config to KestrelServerOptions.ConfigurationBackedListenOptions and configures some other options.
    // Any endpoints that were removed from the last time endpoints were loaded are returned.
    internal (List <ListenOptions>, List <ListenOptions>) Reload()
    {
        var endpointsToStop  = Options.ConfigurationBackedListenOptions.ToList();
        var endpointsToStart = new List <ListenOptions>();

        Options.ConfigurationBackedListenOptions.Clear();
        DefaultCertificateConfig = null;

        ConfigurationReader = new ConfigurationReader(Configuration);

        LoadDefaultCert();

        foreach (var endpoint in ConfigurationReader.Endpoints)
        {
            var listenOptions = AddressBinder.ParseAddress(endpoint.Url, out var https);

            if (!https)
            {
                ConfigurationReader.ThrowIfContainsHttpsOnlyConfiguration(endpoint);
            }

            Options.ApplyEndpointDefaults(listenOptions);

            if (endpoint.Protocols.HasValue)
            {
                listenOptions.Protocols = endpoint.Protocols.Value;
            }
            else
            {
                // Ensure endpoint is reloaded if it used the default protocol and the protocol changed.
                // listenOptions.Protocols should already be set to this by ApplyEndpointDefaults.
                endpoint.Protocols = ConfigurationReader.EndpointDefaults.Protocols;
            }

            // Compare to UseHttps(httpsOptions => { })
            var httpsOptions = new HttpsConnectionAdapterOptions();

            if (https)
            {
                // Defaults
                Options.ApplyHttpsDefaults(httpsOptions);

                if (endpoint.SslProtocols.HasValue)
                {
                    httpsOptions.SslProtocols = endpoint.SslProtocols.Value;
                }
                else
                {
                    // Ensure endpoint is reloaded if it used the default protocol and the SslProtocols changed.
                    endpoint.SslProtocols = ConfigurationReader.EndpointDefaults.SslProtocols;
                }

                if (endpoint.ClientCertificateMode.HasValue)
                {
                    httpsOptions.ClientCertificateMode = endpoint.ClientCertificateMode.Value;
                }
                else
                {
                    // Ensure endpoint is reloaded if it used the default mode and the ClientCertificateMode changed.
                    endpoint.ClientCertificateMode = ConfigurationReader.EndpointDefaults.ClientCertificateMode;
                }

                // A cert specified directly on the endpoint overrides any defaults.
                httpsOptions.ServerCertificate = CertificateConfigLoader.LoadCertificate(endpoint.Certificate, endpoint.Name)
                                                 ?? httpsOptions.ServerCertificate;

                if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null)
                {
                    // Fallback
                    Options.ApplyDefaultCert(httpsOptions);

                    // Ensure endpoint is reloaded if it used the default certificate and the certificate changed.
                    endpoint.Certificate = DefaultCertificateConfig;
                }
            }

            // Now that defaults have been loaded, we can compare to the currently bound endpoints to see if the config changed.
            // There's no reason to rerun an EndpointConfigurations callback if nothing changed.
            var matchingBoundEndpoints = endpointsToStop.Where(o => o.EndpointConfig == endpoint).ToList();

            if (matchingBoundEndpoints.Count > 0)
            {
                endpointsToStop.RemoveAll(o => o.EndpointConfig == endpoint);
                Options.ConfigurationBackedListenOptions.AddRange(matchingBoundEndpoints);
                continue;
            }

            if (EndpointConfigurations.TryGetValue(endpoint.Name, out var configureEndpoint))
            {
                var endpointConfig = new EndpointConfiguration(https, listenOptions, httpsOptions, endpoint.ConfigSection);
                configureEndpoint(endpointConfig);
            }

            // EndpointDefaults or configureEndpoint may have added an https adapter.
            if (https && !listenOptions.IsTls)
            {
                if (endpoint.Sni.Count == 0)
                {
                    if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null)
                    {
                        throw new InvalidOperationException(CoreStrings.NoCertSpecifiedNoDevelopmentCertificateFound);
                    }

                    listenOptions.UseHttps(httpsOptions);
                }
                else
                {
                    var sniOptionsSelector = new SniOptionsSelector(endpoint.Name, endpoint.Sni, CertificateConfigLoader,
                                                                    httpsOptions, listenOptions.Protocols, HttpsLogger);
                    var tlsCallbackOptions = new TlsHandshakeCallbackOptions()
                    {
                        OnConnection      = SniOptionsSelector.OptionsCallback,
                        HandshakeTimeout  = httpsOptions.HandshakeTimeout,
                        OnConnectionState = sniOptionsSelector,
                    };

                    listenOptions.UseHttps(tlsCallbackOptions);
                }
            }

            listenOptions.EndpointConfig = endpoint;

            endpointsToStart.Add(listenOptions);
            Options.ConfigurationBackedListenOptions.Add(listenOptions);
        }

        return(endpointsToStop, endpointsToStart);
    }