Bind to both IPv4 and IPv6 when localhost is specified (#231).

This commit is contained in:
Cesar Blum Silveira 2016-05-23 17:22:08 -07:00
parent 3f4e2323f4
commit a3d0bd0ec4
18 changed files with 264 additions and 110 deletions

View File

@ -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;
}
}
}
}

View File

@ -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);

View File

@ -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
{

View File

@ -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; }
}
}

View File

@ -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
};
}
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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 =>

View File

@ -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 =>

View File

@ -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 =>

View File

@ -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 =>

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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) =>

View File

@ -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) =>

View File

@ -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);
}
}
}

View File

@ -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/")
{
}