Bind to both IPv4 and IPv6 when localhost is specified (#231).
This commit is contained in:
parent
3f4e2323f4
commit
a3d0bd0ec4
|
|
@ -11,6 +11,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
|
|||
|
||||
public const int EOF = -4095;
|
||||
public static readonly int? ECONNRESET = GetECONNRESET();
|
||||
public static readonly int? EADDRINUSE = GetEADDRINUSE();
|
||||
|
||||
/// <summary>
|
||||
/// Prefix of host name used to specify Unix sockets in the configuration.
|
||||
|
|
@ -39,5 +40,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static int? GetEADDRINUSE()
|
||||
{
|
||||
switch (PlatformServices.Default.Runtime.OperatingSystemPlatform)
|
||||
{
|
||||
case Platform.Windows:
|
||||
return -4091;
|
||||
case Platform.Linux:
|
||||
return -98;
|
||||
case Platform.Darwin:
|
||||
return -48;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
|
|
@ -11,6 +12,7 @@ using Microsoft.AspNetCore.Hosting.Server.Features;
|
|||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Http;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Infrastructure;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Networking;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
|
@ -94,6 +96,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
{
|
||||
_logger.LogWarning("Unable to determine ECONNRESET value on this platform.");
|
||||
}
|
||||
if (!Constants.EADDRINUSE.HasValue)
|
||||
{
|
||||
_logger.LogWarning("Unable to determine EADDRINUSE value on this platform.");
|
||||
}
|
||||
|
||||
engine.Start(threadCount);
|
||||
var atLeastOneListener = false;
|
||||
|
|
@ -108,8 +114,69 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
else
|
||||
{
|
||||
atLeastOneListener = true;
|
||||
_disposables.Push(engine.CreateServer(
|
||||
parsedAddress));
|
||||
|
||||
if (!parsedAddress.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_disposables.Push(engine.CreateServer(
|
||||
parsedAddress));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parsedAddress.Port == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Dynamic port binding is not supported when binding to localhost. You must either bind to 127.0.0.1:0 or [::1]:0, or both.");
|
||||
}
|
||||
|
||||
var ipv4Address = parsedAddress.WithHost("127.0.0.1");
|
||||
var exceptions = new List<UvException>();
|
||||
|
||||
try
|
||||
{
|
||||
_disposables.Push(engine.CreateServer(ipv4Address));
|
||||
}
|
||||
catch (AggregateException ex)
|
||||
{
|
||||
var uvException = ex.InnerException as UvException;
|
||||
|
||||
if (uvException != null && uvException.StatusCode != Constants.EADDRINUSE)
|
||||
{
|
||||
_logger.LogWarning(0, ex, $"Unable to bind to {parsedAddress.ToString()} on the IPv4 loopback interface.");
|
||||
exceptions.Add(uvException);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
var ipv6Address = parsedAddress.WithHost("[::1]");
|
||||
|
||||
try
|
||||
{
|
||||
_disposables.Push(engine.CreateServer(ipv6Address));
|
||||
}
|
||||
catch (AggregateException ex)
|
||||
{
|
||||
var uvException = ex.InnerException as UvException;
|
||||
|
||||
if (uvException != null && uvException.StatusCode != Constants.EADDRINUSE)
|
||||
{
|
||||
_logger.LogWarning(0, ex, $"Unable to bind to {parsedAddress.ToString()} on the IPv6 loopback interface.");
|
||||
exceptions.Add(uvException);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (exceptions.Count == 2)
|
||||
{
|
||||
var ex = new AggregateException(exceptions);
|
||||
_logger.LogError(0, ex, $"Unable to bind to {parsedAddress.ToString()} on any loopback interface.");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
// If requested port was "0", replace with assigned dynamic port.
|
||||
_serverAddresses.Addresses.Remove(address);
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
{
|
||||
var errorName = err_name(statusCode);
|
||||
var errorDescription = strerror(statusCode);
|
||||
error = new UvException("Error " + statusCode + " " + errorName + " " + errorDescription);
|
||||
error = new UvException("Error " + statusCode + " " + errorName + " " + errorDescription, statusCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
{
|
||||
public class UvException : Exception
|
||||
{
|
||||
public UvException(string message) : base(message) { }
|
||||
public UvException(string message, int statusCode) : base(message)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
}
|
||||
|
||||
public int StatusCode { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,5 +155,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
|
||||
return serverAddress;
|
||||
}
|
||||
|
||||
internal ServerAddress WithHost(string host)
|
||||
{
|
||||
return new ServerAddress
|
||||
{
|
||||
Scheme = Scheme,
|
||||
Host = host,
|
||||
Port = Port,
|
||||
PathBase = PathBase
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
|
@ -13,8 +12,8 @@ using Microsoft.AspNetCore.Hosting;
|
|||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Networking;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||
|
|
@ -42,7 +41,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
await RegisterAddresses_Success(addressInput, testUrls);
|
||||
}
|
||||
|
||||
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv6Port80))]
|
||||
[IPv6SupportedCondition]
|
||||
[Port80SupportedCondition]
|
||||
public async Task RegisterAddresses_IPv6Port80_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
||||
{
|
||||
await RegisterAddresses_Success(addressInput, testUrls);
|
||||
}
|
||||
|
||||
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv6ScopeId))]
|
||||
[IPv6SupportedCondition]
|
||||
[OSSkipCondition(OperatingSystems.Linux, SkipReason = "HttpClient does not support IPv6 with scope ID on Linux (https://github.com/dotnet/corefx/issues/8235).")]
|
||||
[OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "HttpClient does not support IPv6 with scope ID on Mac (https://github.com/dotnet/corefx/issues/8235).")]
|
||||
public async Task RegisterAddresses_IPv6ScopeId_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
||||
|
|
@ -50,18 +58,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
await RegisterAddresses_Success(addressInput, testUrls);
|
||||
}
|
||||
|
||||
public async Task RegisterAddresses_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
||||
private async Task RegisterAddresses_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string>
|
||||
{
|
||||
{ "server.urls", addressInput }
|
||||
})
|
||||
.Build();
|
||||
|
||||
var hostBuilder = new WebHostBuilder()
|
||||
.UseConfiguration(config)
|
||||
.UseKestrel()
|
||||
.UseUrls(addressInput)
|
||||
.Configure(ConfigureEchoAddress);
|
||||
|
||||
using (var host = hostBuilder.Build())
|
||||
|
|
@ -84,6 +85,53 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ThrowsWhenBindingLocalhostToIPv4AddressInUse()
|
||||
{
|
||||
ThrowsWhenBindingLocalhostToAddressInUse(AddressFamily.InterNetwork, IPAddress.Loopback);
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[IPv6SupportedCondition]
|
||||
public void ThrowsWhenBindingLocalhostToIPv6AddressInUse()
|
||||
{
|
||||
ThrowsWhenBindingLocalhostToAddressInUse(AddressFamily.InterNetworkV6, IPAddress.IPv6Loopback);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ThrowsWhenBindingLocalhostToDynamicPort()
|
||||
{
|
||||
var hostBuilder = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseUrls("http://localhost:0")
|
||||
.Configure(ConfigureEchoAddress);
|
||||
|
||||
using (var host = hostBuilder.Build())
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => host.Start());
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowsWhenBindingLocalhostToAddressInUse(AddressFamily addressFamily, IPAddress address)
|
||||
{
|
||||
using (var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
var port = GetNextPort();
|
||||
socket.Bind(new IPEndPoint(address, port));
|
||||
|
||||
var hostBuilder = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseUrls($"http://localhost:{port}")
|
||||
.Configure(ConfigureEchoAddress);
|
||||
|
||||
using (var host = hostBuilder.Build())
|
||||
{
|
||||
var exception = Assert.Throws<AggregateException>(() => host.Start());
|
||||
Assert.Contains(exception.InnerExceptions, ex => ex is UvException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv4
|
||||
{
|
||||
get
|
||||
|
|
@ -91,26 +139,31 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
var dataset = new TheoryData<string, Func<IServerAddressesFeature, string[]>>();
|
||||
|
||||
// Default host and port
|
||||
dataset.Add(null, _ => new[] { "http://localhost:5000/" });
|
||||
dataset.Add(string.Empty, _ => new[] { "http://localhost:5000/" });
|
||||
dataset.Add(null, _ => new[] { "http://127.0.0.1:5000/" });
|
||||
dataset.Add(string.Empty, _ => new[] { "http://127.0.0.1:5000/" });
|
||||
|
||||
// Static port
|
||||
// Static ports
|
||||
var port1 = GetNextPort();
|
||||
var port2 = GetNextPort();
|
||||
|
||||
// Ensure multiple addresses can be separated by semicolon
|
||||
dataset.Add($"http://localhost:{port1};http://localhost:{port2}",
|
||||
_ => new[] { $"http://localhost:{port1}/", $"http://localhost:{port2}/" });
|
||||
// Loopback
|
||||
dataset.Add($"http://127.0.0.1:{port1}", _ => new[] { $"http://127.0.0.1:{port1}/" });
|
||||
|
||||
// Ensure "localhost" and "127.0.0.1" are equivalent
|
||||
// Localhost
|
||||
dataset.Add($"http://localhost:{port1}", _ => new[] { $"http://localhost:{port1}/", $"http://127.0.0.1:{port1}/" });
|
||||
dataset.Add($"http://127.0.0.1:{port1}", _ => new[] { $"http://localhost:{port1}/", $"http://127.0.0.1:{port1}/" });
|
||||
|
||||
// Any
|
||||
dataset.Add($"http://*:{port1}/", _ => new[] { $"http://127.0.0.1:{port1}/" });
|
||||
dataset.Add($"http://+:{port1}/", _ => new[] { $"http://127.0.0.1:{port1}/" });
|
||||
|
||||
// Multiple addresses
|
||||
dataset.Add($"http://127.0.0.1:{port1};http://127.0.0.1:{port2}", _ => new[] { $"http://127.0.0.1:{port1}/", $"http://127.0.0.1:{port2}/" });
|
||||
|
||||
// Path after port
|
||||
dataset.Add($"http://localhost:{port1}/base/path", _ => new[] { $"http://localhost:{port1}/base/path" });
|
||||
dataset.Add($"http://127.0.0.1:{port1}/base/path", _ => new[] { $"http://127.0.0.1:{port1}/base/path" });
|
||||
|
||||
// Dynamic port
|
||||
dataset.Add("http://localhost:0/", GetTestUrls);
|
||||
// Dynamic port and non-loopback addresses
|
||||
dataset.Add("http://127.0.0.1:0/", GetTestUrls);
|
||||
dataset.Add($"http://{Dns.GetHostName()}:0/", GetTestUrls);
|
||||
|
||||
var ipv4Addresses = Dns.GetHostAddressesAsync(Dns.GetHostName()).Result
|
||||
|
|
@ -131,8 +184,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
var dataset = new TheoryData<string, Func<IServerAddressesFeature, string[]>>();
|
||||
|
||||
// Default port for HTTP (80)
|
||||
dataset.Add("http://*", _ => new[] { "http://localhost/" });
|
||||
dataset.Add("http://localhost", _ => new[] { "http://localhost/" });
|
||||
dataset.Add("http://127.0.0.1", _ => new[] { "http://127.0.0.1/" });
|
||||
dataset.Add("http://localhost", _ => new[] { "http://127.0.0.1/" });
|
||||
dataset.Add("http://*", _ => new[] { "http://127.0.0.1/" });
|
||||
|
||||
return dataset;
|
||||
}
|
||||
|
|
@ -144,17 +198,32 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
{
|
||||
var dataset = new TheoryData<string, Func<IServerAddressesFeature, string[]>>();
|
||||
|
||||
// Static port
|
||||
var port = GetNextPort();
|
||||
dataset.Add($"http://*:{port}/", _ => new[] { $"http://localhost:{port}/", $"http://127.0.0.1:{port}/", $"http://[::1]:{port}/" });
|
||||
dataset.Add($"http://localhost:{port}/", _ => new[] { $"http://localhost:{port}/", $"http://127.0.0.1:{port}/",
|
||||
/* // https://github.com/aspnet/KestrelHttpServer/issues/231
|
||||
$"http://[::1]:{port}/"
|
||||
*/ });
|
||||
dataset.Add($"http://[::1]:{port}/", _ => new[] { $"http://[::1]:{port}/", });
|
||||
dataset.Add($"http://127.0.0.1:{port}/;http://[::1]:{port}/", _ => new[] { $"http://127.0.0.1:{port}/", $"http://[::1]:{port}/" });
|
||||
// Default host and port
|
||||
dataset.Add(null, _ => new[] { "http://127.0.0.1:5000/", "http://[::1]:5000/" });
|
||||
dataset.Add(string.Empty, _ => new[] { "http://127.0.0.1:5000/", "http://[::1]:5000/" });
|
||||
|
||||
// Dynamic port
|
||||
// Static ports
|
||||
var port1 = GetNextPort();
|
||||
var port2 = GetNextPort();
|
||||
|
||||
// Loopback
|
||||
dataset.Add($"http://[::1]:{port1}/", _ => new[] { $"http://[::1]:{port1}/" });
|
||||
|
||||
// Localhost
|
||||
dataset.Add($"http://localhost:{port1}", _ => new[] { $"http://localhost:{port1}/", $"http://127.0.0.1:{port1}/", $"http://[::1]:{port1}/" });
|
||||
|
||||
// Any
|
||||
dataset.Add($"http://*:{port1}/", _ => new[] { $"http://127.0.0.1:{port1}/", $"http://[::1]:{port1}/" });
|
||||
dataset.Add($"http://+:{port1}/", _ => new[] { $"http://127.0.0.1:{port1}/", $"http://[::1]:{port1}/" });
|
||||
|
||||
// Multiple addresses
|
||||
dataset.Add($"http://127.0.0.1:{port1}/;http://[::1]:{port1}/", _ => new[] { $"http://127.0.0.1:{port1}/", $"http://[::1]:{port1}/" });
|
||||
dataset.Add($"http://[::1]:{port1};http://[::1]:{port2}", _ => new[] { $"http://[::1]:{port1}/", $"http://[::1]:{port2}/" });
|
||||
|
||||
// Path after port
|
||||
dataset.Add($"http://[::1]:{port1}/base/path", _ => new[] { $"http://[::1]:{port1}/base/path" });
|
||||
|
||||
// Dynamic port and non-loopback addresses
|
||||
var ipv6Addresses = Dns.GetHostAddressesAsync(Dns.GetHostName()).Result
|
||||
.Where(ip => ip.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
.Where(ip => ip.ScopeId == 0);
|
||||
|
|
@ -167,6 +236,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv6Port80
|
||||
{
|
||||
get
|
||||
{
|
||||
var dataset = new TheoryData<string, Func<IServerAddressesFeature, string[]>>();
|
||||
|
||||
// Default port for HTTP (80)
|
||||
dataset.Add("http://[::1]", _ => new[] { "http://[::1]/" });
|
||||
dataset.Add("http://localhost", _ => new[] { "http://127.0.0.1/", "http://[::1]/" });
|
||||
dataset.Add("http://*", _ => new[] { "http://[::1]/" });
|
||||
|
||||
return dataset;
|
||||
}
|
||||
}
|
||||
|
||||
public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv6ScopeId
|
||||
{
|
||||
get
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
{
|
||||
using (var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 8787));
|
||||
socket.Bind(new IPEndPoint(IPAddress.IPv6Any, 0));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Xunit;
|
||||
|
|
@ -68,14 +66,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
|
||||
private async Task TestPathBase(string registerPathBase, string requestPath, string expectedPathBase, string expectedPath)
|
||||
{
|
||||
var config = new ConfigurationBuilder().AddInMemoryCollection(
|
||||
new Dictionary<string, string> {
|
||||
{ "server.urls", $"http://localhost:0{registerPathBase}" }
|
||||
}).Build();
|
||||
|
||||
var builder = new WebHostBuilder()
|
||||
.UseConfiguration(config)
|
||||
.UseKestrel()
|
||||
.UseUrls($"http://127.0.0.1:0{registerPathBase}")
|
||||
.Configure(app =>
|
||||
{
|
||||
app.Run(async context =>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseUrls($"http://localhost:0/")
|
||||
.UseUrls("http://127.0.0.1:0/")
|
||||
.Configure(app =>
|
||||
{
|
||||
app.Run(async context =>
|
||||
|
|
@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseUrls($"http://localhost:0/")
|
||||
.UseUrls("http://127.0.0.1:0/")
|
||||
.Configure(app =>
|
||||
{
|
||||
app.Run(async context =>
|
||||
|
|
@ -117,12 +117,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("127.0.0.1", "127.0.0.1")]
|
||||
[InlineData("localhost", "127.0.0.1")]
|
||||
public Task RemoteIPv4Address(string requestAddress, string expectAddress)
|
||||
[Fact]
|
||||
public Task RemoteIPv4Address()
|
||||
{
|
||||
return TestRemoteIPAddress("localhost", requestAddress, expectAddress);
|
||||
return TestRemoteIPAddress("127.0.0.1", "127.0.0.1", "127.0.0.1");
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
|
|
@ -137,7 +135,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseUrls($"http://localhost:0")
|
||||
.UseUrls($"http://127.0.0.1:0")
|
||||
.Configure(app =>
|
||||
{
|
||||
app.Run(async context =>
|
||||
|
|
@ -165,7 +163,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseUrls($"http://localhost:0/\u0041\u030A")
|
||||
.UseUrls($"http://127.0.0.1:0/\u0041\u030A")
|
||||
.Configure(app =>
|
||||
{
|
||||
app.Run(async context =>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
|
@ -10,7 +9,6 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -21,16 +19,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
[Fact]
|
||||
public async Task LargeDownload()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string>
|
||||
{
|
||||
{ "server.urls", $"http://localhost:0/" }
|
||||
})
|
||||
.Build();
|
||||
|
||||
var hostBuilder = new WebHostBuilder()
|
||||
.UseConfiguration(config)
|
||||
.UseKestrel()
|
||||
.UseUrls("http://127.0.0.1:0/")
|
||||
.Configure(app =>
|
||||
{
|
||||
app.Run(async context =>
|
||||
|
|
@ -80,16 +71,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
[Theory, MemberData(nameof(NullHeaderData))]
|
||||
public async Task IgnoreNullHeaderValues(string headerName, StringValues headerValue, string expectedValue)
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string>
|
||||
{
|
||||
{ "server.urls", $"http://localhost:0/" }
|
||||
})
|
||||
.Build();
|
||||
|
||||
var hostBuilder = new WebHostBuilder()
|
||||
.UseConfiguration(config)
|
||||
.UseKestrel()
|
||||
.UseUrls("http://127.0.0.1:0/")
|
||||
.Configure(app =>
|
||||
{
|
||||
app.Run(async context =>
|
||||
|
|
@ -127,19 +111,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
[Fact]
|
||||
public async Task OnCompleteCalledEvenWhenOnStartingNotCalled()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string>
|
||||
{
|
||||
{ "server.urls", $"http://localhost:0/" }
|
||||
})
|
||||
.Build();
|
||||
|
||||
var onStartingCalled = false;
|
||||
var onCompletedCalled = false;
|
||||
|
||||
var hostBuilder = new WebHostBuilder()
|
||||
.UseConfiguration(config)
|
||||
.UseKestrel()
|
||||
.UseUrls("http://127.0.0.1:0/")
|
||||
.Configure(app =>
|
||||
{
|
||||
app.Run(context =>
|
||||
|
|
|
|||
|
|
@ -7,28 +7,22 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||
{
|
||||
public class ThreadCountTests
|
||||
{
|
||||
public async Task ZeroToTenThreads(int threadCount)
|
||||
[Theory]
|
||||
[MemberData(nameof(OneToTen))]
|
||||
public async Task OneToTenThreads(int threadCount)
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string>
|
||||
{
|
||||
{ "server.urls", $"http://localhost:0/" }
|
||||
})
|
||||
.Build();
|
||||
|
||||
var hostBuilder = new WebHostBuilder()
|
||||
.UseConfiguration(config)
|
||||
.UseKestrel(options =>
|
||||
{
|
||||
options.ThreadCount = threadCount;
|
||||
})
|
||||
.UseUrls("http://127.0.0.1:0/")
|
||||
.Configure(app =>
|
||||
{
|
||||
app.Run(context =>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
FrameFactory = connectionContext => new Frame<HttpContext>(
|
||||
new DummyApplication(httpContext => TaskUtilities.CompletedTask), connectionContext),
|
||||
Memory = memory,
|
||||
ServerAddress = ServerAddress.FromUrl($"http://localhost:0"),
|
||||
ServerAddress = ServerAddress.FromUrl("http://127.0.0.1:0"),
|
||||
Thread = engine.Threads[0]
|
||||
};
|
||||
var socket = new MockSocket(mockLibuv, Thread.CurrentThread.ManagedThreadId, trace);
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
testContext.App = App;
|
||||
var engine = new KestrelEngine(testContext);
|
||||
engine.Start(1);
|
||||
var address = ServerAddress.FromUrl($"http://localhost:0/");
|
||||
var address = ServerAddress.FromUrl("http://127.0.0.1:0/");
|
||||
var started = engine.CreateServer(address);
|
||||
started.Dispose();
|
||||
engine.Dispose();
|
||||
|
|
@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
testContext.App = App;
|
||||
var engine = new KestrelEngine(testContext);
|
||||
engine.Start(1);
|
||||
var address = ServerAddress.FromUrl($"http://localhost:0/");
|
||||
var address = ServerAddress.FromUrl("http://127.0.0.1:0/");
|
||||
var started = engine.CreateServer(address);
|
||||
|
||||
var socket = TestConnection.CreateConnectedLoopbackSocket(address.Port);
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
new NoOpConnectionFilter())
|
||||
);
|
||||
|
||||
using (var server = new TestServer(App, serviceContext, "https://localhost:0/"))
|
||||
using (var server = new TestServer(App, serviceContext, "https://127.0.0.1:0/"))
|
||||
{
|
||||
using (var client = new HttpClient(handler))
|
||||
{
|
||||
|
|
@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
new NoOpConnectionFilter())
|
||||
);
|
||||
|
||||
using (var server = new TestServer(App, serviceContext, "https://localhost:0/"))
|
||||
using (var server = new TestServer(App, serviceContext, "https://127.0.0.1:0/"))
|
||||
{
|
||||
using (var client = new HttpClient(handler))
|
||||
{
|
||||
|
|
@ -172,7 +172,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
return context.Response.WriteAsync("hello world");
|
||||
};
|
||||
|
||||
using (var server = new TestServer(app, serviceContext, "https://localhost:0/"))
|
||||
using (var server = new TestServer(app, serviceContext, "https://127.0.0.1:0/"))
|
||||
{
|
||||
using (var client = new HttpClient(handler))
|
||||
{
|
||||
|
|
@ -222,7 +222,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
return context.Response.WriteAsync("hello world");
|
||||
};
|
||||
|
||||
using (var server = new TestServer(app, serviceContext, "https://localhost:0/"))
|
||||
using (var server = new TestServer(app, serviceContext, "https://127.0.0.1:0/"))
|
||||
{
|
||||
// SslStream is used to ensure the certificate is actually passed to the server
|
||||
// HttpClient might not send the certificate because it is invalid or it doesn't match any
|
||||
|
|
@ -281,7 +281,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
|
||||
RequestDelegate app = context => context.Response.WriteAsync(context.Request.Scheme);
|
||||
|
||||
using (var server = new TestServer(app, serviceContext, "https://localhost:0/"))
|
||||
using (var server = new TestServer(app, serviceContext, "https://127.0.0.1:0/"))
|
||||
{
|
||||
using (var client = new HttpClient(handler))
|
||||
{
|
||||
|
|
@ -327,7 +327,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
return context.Response.WriteAsync("hello world");
|
||||
};
|
||||
|
||||
using (var server = new TestServer(app, serviceContext, "https://localhost:0/"))
|
||||
using (var server = new TestServer(app, serviceContext, "https://127.0.0.1:0/"))
|
||||
{
|
||||
// SslStream is used to ensure the certificate is actually passed to the server
|
||||
// HttpClient might not send the certificate because it is invalid or it doesn't match any
|
||||
|
|
@ -384,7 +384,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
return context.Response.WriteAsync("hello world");
|
||||
};
|
||||
|
||||
using (var server = new TestServer(app, serviceContext, "https://localhost:0/"))
|
||||
using (var server = new TestServer(app, serviceContext, "https://127.0.0.1:0/"))
|
||||
{
|
||||
// SslStream is used to ensure the certificate is actually passed to the server
|
||||
// HttpClient might not send the certificate because it is invalid or it doesn't match any
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
|
||||
var serverListenTcp = new UvTcpHandle(_logger);
|
||||
serverListenTcp.Init(loop, (a, b) => { });
|
||||
var address = ServerAddress.FromUrl($"http://localhost:0/");
|
||||
var address = ServerAddress.FromUrl($"http://127.0.0.1:0/");
|
||||
serverListenTcp.Bind(address);
|
||||
var port = serverListenTcp.GetSockIPEndPoint().Port;
|
||||
serverListenTcp.Listen(128, (_1, status, error, _2) =>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
loop.Init(_uv);
|
||||
var tcp = new UvTcpHandle(_logger);
|
||||
tcp.Init(loop, (a, b) => { });
|
||||
var address = ServerAddress.FromUrl("http://localhost:0/");
|
||||
var address = ServerAddress.FromUrl("http://127.0.0.1:0/");
|
||||
tcp.Bind(address);
|
||||
tcp.Dispose();
|
||||
loop.Run();
|
||||
|
|
@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
loop.Init(_uv);
|
||||
var tcp = new UvTcpHandle(_logger);
|
||||
tcp.Init(loop, (a, b) => { });
|
||||
var address = ServerAddress.FromUrl($"http://localhost:0/");
|
||||
var address = ServerAddress.FromUrl($"http://127.0.0.1:0/");
|
||||
tcp.Bind(address);
|
||||
var port = tcp.GetSockIPEndPoint().Port;
|
||||
tcp.Listen(10, (stream, status, error, state) =>
|
||||
|
|
@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
loop.Init(_uv);
|
||||
var tcp = new UvTcpHandle(_logger);
|
||||
tcp.Init(loop, (a, b) => { });
|
||||
var address = ServerAddress.FromUrl($"http://localhost:0/");
|
||||
var address = ServerAddress.FromUrl($"http://127.0.0.1:0/");
|
||||
tcp.Bind(address);
|
||||
var port = tcp.GetSockIPEndPoint().Port;
|
||||
tcp.Listen(10, (_, status, error, state) =>
|
||||
|
|
@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
loop.Init(_uv);
|
||||
var tcp = new UvTcpHandle(_logger);
|
||||
tcp.Init(loop, (a, b) => { });
|
||||
var address = ServerAddress.FromUrl($"http://localhost:0/");
|
||||
var address = ServerAddress.FromUrl($"http://127.0.0.1:0/");
|
||||
tcp.Bind(address);
|
||||
var port = tcp.GetSockIPEndPoint().Port;
|
||||
tcp.Listen(10, (_, status, error, state) =>
|
||||
|
|
|
|||
|
|
@ -60,5 +60,15 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
Assert.True(serverAddres.PathBase.IsNormalized(NormalizationForm.FormC));
|
||||
Assert.Equal("/p\u00C5thbase", serverAddres.PathBase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WithHostReturnsNewInstanceWithDifferentHost()
|
||||
{
|
||||
var serverAddress = ServerAddress.FromUrl("http://localhost:8080");
|
||||
var newAddress = serverAddress.WithHost("otherhost");
|
||||
Assert.NotSame(serverAddress, newAddress);
|
||||
Assert.Equal("otherhost", newAddress.Host);
|
||||
Assert.Equal("localhost", serverAddress.Host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Server.Kestrel;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Http;
|
||||
|
|
@ -16,7 +15,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
{
|
||||
private KestrelEngine _engine;
|
||||
private IDisposable _server;
|
||||
ServerAddress _address;
|
||||
private ServerAddress _address;
|
||||
|
||||
public TestServer(RequestDelegate app)
|
||||
: this(app, new TestServiceContext())
|
||||
|
|
@ -24,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
}
|
||||
|
||||
public TestServer(RequestDelegate app, ServiceContext context)
|
||||
: this(app, context, "http://localhost:0/")
|
||||
: this(app, context, "http://127.0.0.1:0/")
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue