Update addresses in IServerAddressesFeature with assigned dynamic ports (#758)

- Change most tests to use dynamic ports, rather than a fixed port obtained from GetNextPort().
- Add several new cases to `AddressRegistrationTests` and `ServerAddressFacts`.
- Remove project `test\Microsoft.AspNetCore.Server.Kestrel.TestCommon`.  It's not longer needed, since only `AddressRegistrationTests` uses `GetNextPort()`.
This commit is contained in:
Mike Harder 2016-05-04 11:27:23 -07:00
parent f8c2c2470f
commit 14bbba0641
24 changed files with 316 additions and 211 deletions

View File

@ -34,8 +34,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server
EndProject EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.Kestrel.FunctionalTests", "test\Microsoft.AspNetCore.Server.Kestrel.FunctionalTests\Microsoft.AspNetCore.Server.Kestrel.FunctionalTests.xproj", "{9559A5F1-080C-4909-B6CF-7E4B3DC55748}" Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.Kestrel.FunctionalTests", "test\Microsoft.AspNetCore.Server.Kestrel.FunctionalTests\Microsoft.AspNetCore.Server.Kestrel.FunctionalTests.xproj", "{9559A5F1-080C-4909-B6CF-7E4B3DC55748}"
EndProject EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.Kestrel.TestCommon", "test\Microsoft.AspNetCore.Server.Kestrel.TestCommon\Microsoft.AspNetCore.Server.Kestrel.TestCommon.xproj", "{A485B4F9-0392-478C-B19A-F4DE6B17F491}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -74,10 +72,6 @@ Global
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Debug|Any CPU.Build.0 = Debug|Any CPU {9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Release|Any CPU.ActiveCfg = Release|Any CPU {9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Release|Any CPU.Build.0 = Release|Any CPU {9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Release|Any CPU.Build.0 = Release|Any CPU
{A485B4F9-0392-478C-B19A-F4DE6B17F491}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A485B4F9-0392-478C-B19A-F4DE6B17F491}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A485B4F9-0392-478C-B19A-F4DE6B17F491}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A485B4F9-0392-478C-B19A-F4DE6B17F491}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -91,6 +85,5 @@ Global
{8CBA6FE3-3CC9-4420-8AA3-123E983734C2} = {327F7880-D9AF-46BD-B45C-3B7E34A01DFD} {8CBA6FE3-3CC9-4420-8AA3-123E983734C2} = {327F7880-D9AF-46BD-B45C-3B7E34A01DFD}
{5F64B3C3-0C2E-431A-B820-A81BBFC863DA} = {2D5D5227-4DBD-499A-96B1-76A36B03B750} {5F64B3C3-0C2E-431A-B820-A81BBFC863DA} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
{9559A5F1-080C-4909-B6CF-7E4B3DC55748} = {D3273454-EA07-41D2-BF0B-FCC3675C2483} {9559A5F1-080C-4909-B6CF-7E4B3DC55748} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
{A485B4F9-0392-478C-B19A-F4DE6B17F491} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@ -25,6 +25,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
socket.Init(Thread.Loop, Thread.QueueCloseHandle); socket.Init(Thread.Loop, Thread.QueueCloseHandle);
socket.NoDelay(ServerOptions.NoDelay); socket.NoDelay(ServerOptions.NoDelay);
socket.Bind(ServerAddress); socket.Bind(ServerAddress);
// If requested port was "0", replace with assigned dynamic port.
ServerAddress.Port = socket.GetSockIPEndPoint().Port;
socket.Listen(Constants.ListenBacklog, (stream, status, error, state) => ConnectionCallback(stream, status, error, state), this); socket.Listen(Constants.ListenBacklog, (stream, status, error, state) => ConnectionCallback(stream, status, error, state), this);
return socket; return socket;
} }

View File

@ -27,6 +27,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
socket.Init(Thread.Loop, Thread.QueueCloseHandle); socket.Init(Thread.Loop, Thread.QueueCloseHandle);
socket.NoDelay(ServerOptions.NoDelay); socket.NoDelay(ServerOptions.NoDelay);
socket.Bind(ServerAddress); socket.Bind(ServerAddress);
// If requested port was "0", replace with assigned dynamic port.
ServerAddress.Port = socket.GetSockIPEndPoint().Port;
socket.Listen(Constants.ListenBacklog, (stream, status, error, state) => ConnectionCallback(stream, status, error, state), this); socket.Listen(Constants.ListenBacklog, (stream, status, error, state) => ConnectionCallback(stream, status, error, state), this);
return socket; return socket;
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server;
@ -96,7 +97,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
engine.Start(threadCount); engine.Start(threadCount);
var atLeastOneListener = false; var atLeastOneListener = false;
foreach (var address in _serverAddresses.Addresses) foreach (var address in _serverAddresses.Addresses.ToArray())
{ {
var parsedAddress = ServerAddress.FromUrl(address); var parsedAddress = ServerAddress.FromUrl(address);
if (parsedAddress == null) if (parsedAddress == null)
@ -108,6 +109,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel
atLeastOneListener = true; atLeastOneListener = true;
_disposables.Push(engine.CreateServer( _disposables.Push(engine.CreateServer(
parsedAddress)); parsedAddress));
// If requested port was "0", replace with assigned dynamic port.
_serverAddresses.Addresses.Remove(address);
_serverAddresses.Addresses.Add(parsedAddress.ToString());
} }
} }

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
{ {
public string Host { get; private set; } public string Host { get; private set; }
public string PathBase { get; private set; } public string PathBase { get; private set; }
public int Port { get; private set; } public int Port { get; internal set; }
public string Scheme { get; private set; } public string Scheme { get; private set; }
public bool IsUnixPipe public bool IsUnixPipe
@ -36,7 +36,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel
public override string ToString() public override string ToString()
{ {
return Scheme.ToLowerInvariant() + "://" + Host.ToLowerInvariant() + ":" + Port.ToString(CultureInfo.InvariantCulture) + PathBase.ToLowerInvariant(); if (IsUnixPipe)
{
if (String.IsNullOrEmpty(PathBase))
{
return Scheme.ToLowerInvariant() + "://" + Host.ToLowerInvariant();
}
else
{
return Scheme.ToLowerInvariant() + "://" + Host.ToLowerInvariant() + ":" + PathBase.ToLowerInvariant();
}
}
else
{
return Scheme.ToLowerInvariant() + "://" + Host.ToLowerInvariant() + ":" + Port.ToString(CultureInfo.InvariantCulture) + PathBase.ToLowerInvariant();
}
} }
public override int GetHashCode() public override int GetHashCode()

View File

@ -1,11 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Sockets;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
@ -16,20 +21,36 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
public class AddressRegistrationTests public class AddressRegistrationTests
{ {
[Theory, MemberData(nameof(AddressRegistrationDataIPv4))] [Theory, MemberData(nameof(AddressRegistrationDataIPv4))]
public async Task RegisterAddresses_IPv4_Success(string addressInput, string[] testUrls) public async Task RegisterAddresses_IPv4_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
{
await RegisterAddresses_Success(addressInput, testUrls);
}
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv4Port80))]
[Port80SupportedCondition]
public async Task RegisterAddresses_IPv4Port80_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
{ {
await RegisterAddresses_Success(addressInput, testUrls); await RegisterAddresses_Success(addressInput, testUrls);
} }
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv6))] [ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv6))]
[IPv6SupportedCondition] [IPv6SupportedCondition]
public async Task RegisterAddresses_IPv6_Success(string addressInput, string[] testUrls) public async Task RegisterAddresses_IPv6_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
{ {
await RegisterAddresses_Success(addressInput, testUrls); await RegisterAddresses_Success(addressInput, testUrls);
} }
public async Task RegisterAddresses_Success(string addressInput, string[] testUrls) [ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv6ScopeId))]
[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)
{
await RegisterAddresses_Success(addressInput, testUrls);
}
public async Task RegisterAddresses_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
{ {
var config = new ConfigurationBuilder() var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string> .AddInMemoryCollection(new Dictionary<string, string>
@ -49,49 +70,129 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
using (var client = new HttpClient()) using (var client = new HttpClient())
{ {
foreach (var testUrl in testUrls) foreach (var testUrl in testUrls(host.ServerFeatures.Get<IServerAddressesFeature>()))
{ {
var responseText = await client.GetStringAsync(testUrl); var response = await client.GetAsync(testUrl);
Assert.Equal(testUrl, responseText);
// Compare the response with the RequestMessage.RequestUri, rather than testUrl directly.
// Required to handle IPv6 addresses with zone index, like "fe80::3%1"
Assert.Equal(
response.RequestMessage.RequestUri.ToString(),
await response.Content.ReadAsStringAsync());
} }
} }
} }
} }
public static TheoryData<string, string[]> AddressRegistrationDataIPv4 public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv4
{ {
get get
{ {
var port1 = PortManager.GetPort(); var dataset = new TheoryData<string, Func<IServerAddressesFeature, string[]>>();
var port2 = PortManager.GetPort();
var dataset = new TheoryData<string, string[]>(); // Default host and port
dataset.Add($"{port1}", new[] { $"http://localhost:{port1}/" }); dataset.Add(null, _ => new[] { "http://localhost:5000/" });
dataset.Add($"{port1};{port2}", new[] { $"http://localhost:{port1}/", $"http://localhost:{port2}/" }); dataset.Add(string.Empty, _ => new[] { "http://localhost:5000/" });
dataset.Add($"http://127.0.0.1:{port1}/", new[] { $"http://127.0.0.1:{port1}/", });
dataset.Add($"http://localhost:{port1}/base/path", new[] { $"http://localhost:{port1}/base/path" }); // Static port
var port1 = GetNextPort();
var port2 = GetNextPort();
dataset.Add($"{port1}", _ => new[] { $"http://localhost:{port1}/" });
dataset.Add($"{port1};{port2}", _ => new[] { $"http://localhost:{port1}/", $"http://localhost:{port2}/" });
// Ensure "localhost" and "127.0.0.1" are equivalent
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}/" });
// Path after port
dataset.Add($"http://localhost:{port1}/base/path", _ => new[] { $"http://localhost:{port1}/base/path" });
// Dynamic port
dataset.Add("0", GetTestUrls);
dataset.Add("http://localhost:0/", GetTestUrls);
dataset.Add($"http://{Dns.GetHostName()}:0/", GetTestUrls);
var ipv4Addresses = Dns.GetHostAddressesAsync(Dns.GetHostName()).Result
.Where(ip => ip.AddressFamily == AddressFamily.InterNetwork);
foreach (var ip in ipv4Addresses)
{
dataset.Add($"http://{ip}:0/", GetTestUrls);
}
return dataset; return dataset;
} }
} }
public static TheoryData<string, string[]> AddressRegistrationDataIPv6 public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv4Port80
{ {
get get
{ {
var port = PortManager.GetPort(); var dataset = new TheoryData<string, Func<IServerAddressesFeature, string[]>>();
var dataset = new TheoryData<string, string[]>();
dataset.Add($"http://*:{port}/", new[] { $"http://localhost:{port}/", $"http://127.0.0.1:{port}/", $"http://[::1]:{port}/" }); // Default port for HTTP (80)
dataset.Add($"http://localhost:{port}/", new[] { $"http://localhost:{port}/", $"http://127.0.0.1:{port}/", dataset.Add("http://*", _ => new[] { "http://localhost/" });
/* // https://github.com/aspnet/KestrelHttpServer/issues/231 dataset.Add("http://localhost", _ => new[] { "http://localhost/" });
$"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}/" });
return dataset; return dataset;
} }
} }
public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv6
{
get
{
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}/" });
// Dynamic port
var ipv6Addresses = Dns.GetHostAddressesAsync(Dns.GetHostName()).Result
.Where(ip => ip.AddressFamily == AddressFamily.InterNetworkV6)
.Where(ip => ip.ScopeId == 0);
foreach (var ip in ipv6Addresses)
{
dataset.Add($"http://[{ip}]:0/", GetTestUrls);
}
return dataset;
}
}
public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv6ScopeId
{
get
{
var dataset = new TheoryData<string, Func<IServerAddressesFeature, string[]>>();
// Dynamic port
var ipv6Addresses = Dns.GetHostAddressesAsync(Dns.GetHostName()).Result
.Where(ip => ip.AddressFamily == AddressFamily.InterNetworkV6)
.Where(ip => ip.ScopeId != 0);
foreach (var ip in ipv6Addresses)
{
dataset.Add($"http://[{ip}]:0/", GetTestUrls);
}
return dataset;
}
}
private static string[] GetTestUrls(IServerAddressesFeature addressesFeature)
{
return addressesFeature.Addresses
.Select(a => a.Replace("://+", "://localhost"))
.Select(a => a.EndsWith("/") ? a : a + "/")
.ToArray();
}
private void ConfigureEchoAddress(IApplicationBuilder app) private void ConfigureEchoAddress(IApplicationBuilder app)
{ {
app.Run(context => app.Run(context =>
@ -99,5 +200,72 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
return context.Response.WriteAsync(context.Request.GetDisplayUrl()); return context.Response.WriteAsync(context.Request.GetDisplayUrl());
}); });
} }
private static int _nextPort = 8001;
private static object _portLock = new object();
private static int GetNextPort()
{
lock (_portLock)
{
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
while (true)
{
try
{
var port = _nextPort++;
socket.Bind(new IPEndPoint(IPAddress.Loopback, port));
return port;
}
catch (SocketException)
{
// Retry unless exhausted
if (_nextPort == 65536)
{
throw;
}
}
}
}
}
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
private class Port80SupportedConditionAttribute : Attribute, ITestCondition
{
private static readonly Lazy<bool> _port80Supported = new Lazy<bool>(CanBindToPort80);
public bool IsMet
{
get
{
return _port80Supported.Value;
}
}
public string SkipReason
{
get
{
return "Cannot bind to port 80 on the host.";
}
}
private static bool CanBindToPort80()
{
try
{
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
socket.Bind(new IPEndPoint(IPAddress.Loopback, 80));
return true;
}
}
catch (SocketException)
{
return false;
}
}
}
} }
} }

View File

@ -0,0 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Hosting.Server.Features;
namespace Microsoft.AspNetCore.Hosting
{
public static class IWebHostPortExtensions
{
public static int GetPort(this IWebHost host)
{
return host.GetPorts().First();
}
public static IEnumerable<int> GetPorts(this IWebHost host)
{
return host.ServerFeatures.Get<IServerAddressesFeature>().Addresses
.Select(a => a.Replace("://+", "://localhost"))
.Select(a => (new Uri(a)).Port);
}
}
}

View File

@ -68,10 +68,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
private async Task TestPathBase(string registerPathBase, string requestPath, string expectedPathBase, string expectedPath) private async Task TestPathBase(string registerPathBase, string requestPath, string expectedPathBase, string expectedPath)
{ {
var port = PortManager.GetPort();
var config = new ConfigurationBuilder().AddInMemoryCollection( var config = new ConfigurationBuilder().AddInMemoryCollection(
new Dictionary<string, string> { new Dictionary<string, string> {
{ "server.urls", $"http://localhost:{port}{registerPathBase}" } { "server.urls", $"http://localhost:0{registerPathBase}" }
}).Build(); }).Build();
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
@ -95,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
using (var client = new HttpClient()) using (var client = new HttpClient())
{ {
var response = await client.GetAsync($"http://localhost:{port}{requestPath}"); var response = await client.GetAsync($"http://localhost:{host.GetPort()}{requestPath}");
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
var responseText = await response.Content.ReadAsStringAsync(); var responseText = await response.Content.ReadAsStringAsync();

View File

@ -1,15 +0,0 @@
// 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.Threading;
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
public static class PortManager
{
public static int GetPort()
{
return TestCommon.PortManager.GetNextPort();
}
}
}

View File

@ -22,10 +22,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact] [Fact]
public async Task LargeUpload() public async Task LargeUpload()
{ {
var port = PortManager.GetPort();
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls($"http://localhost:{port}/") .UseUrls($"http://localhost:0/")
.Configure(app => .Configure(app =>
{ {
app.Run(async context => app.Run(async context =>
@ -60,7 +59,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
bytes[i] = (byte)i; bytes[i] = (byte)i;
} }
var response = await client.PostAsync($"http://localhost:{port}/", new ByteArrayContent(bytes)); var response = await client.PostAsync($"http://localhost:{host.GetPort()}/", new ByteArrayContent(bytes));
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
var sizeString = await response.Content.ReadAsStringAsync(); var sizeString = await response.Content.ReadAsStringAsync();
Assert.Equal(sizeString, bytes.Length.ToString(CultureInfo.InvariantCulture)); Assert.Equal(sizeString, bytes.Length.ToString(CultureInfo.InvariantCulture));
@ -72,10 +71,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Fails on Mono on Mac because it is not 64-bit.")] [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Fails on Mono on Mac because it is not 64-bit.")]
public async Task LargeMultipartUpload() public async Task LargeMultipartUpload()
{ {
var port = PortManager.GetPort();
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls($"http://localhost:{port}/") .UseUrls($"http://localhost:0/")
.Configure(app => .Configure(app =>
{ {
app.Run(async context => app.Run(async context =>
@ -111,7 +109,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
} }
var length = form.Headers.ContentLength.Value; var length = form.Headers.ContentLength.Value;
var response = await client.PostAsync($"http://localhost:{port}/", form); var response = await client.PostAsync($"http://localhost:{host.GetPort()}/", form);
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
Assert.Equal(length.ToString(CultureInfo.InvariantCulture), await response.Content.ReadAsStringAsync()); Assert.Equal(length.ToString(CultureInfo.InvariantCulture), await response.Content.ReadAsStringAsync());
} }
@ -137,10 +135,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact] [Fact]
public async Task DoesNotHangOnConnectionCloseRequest() public async Task DoesNotHangOnConnectionCloseRequest()
{ {
var port = PortManager.GetPort();
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls($"http://localhost:{port}") .UseUrls($"http://localhost:0")
.Configure(app => .Configure(app =>
{ {
app.Run(async context => app.Run(async context =>
@ -158,7 +155,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
client.DefaultRequestHeaders.Connection.Clear(); client.DefaultRequestHeaders.Connection.Clear();
client.DefaultRequestHeaders.Connection.Add("close"); client.DefaultRequestHeaders.Connection.Add("close");
var response = await client.GetAsync($"http://localhost:{port}/"); var response = await client.GetAsync($"http://localhost:{host.GetPort()}/");
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
} }
} }
@ -166,10 +163,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact] [Fact]
public void RequestPathIsNormalized() public void RequestPathIsNormalized()
{ {
var port = PortManager.GetPort();
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls($"http://localhost:{port}/\u0041\u030A") .UseUrls($"http://localhost:0/\u0041\u030A")
.Configure(app => .Configure(app =>
{ {
app.Run(async context => app.Run(async context =>
@ -185,7 +181,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
host.Start(); host.Start();
using (var socket = TestConnection.CreateConnectedLoopbackSocket(port)) using (var socket = TestConnection.CreateConnectedLoopbackSocket(host.GetPort()))
{ {
socket.Send(Encoding.ASCII.GetBytes("GET /%41%CC%8A/A/../B/%41%CC%8A HTTP/1.1\r\n\r\n")); socket.Send(Encoding.ASCII.GetBytes("GET /%41%CC%8A/A/../B/%41%CC%8A HTTP/1.1\r\n\r\n"));
socket.Shutdown(SocketShutdown.Send); socket.Shutdown(SocketShutdown.Send);
@ -210,10 +206,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
private async Task TestRemoteIPAddress(string registerAddress, string requestAddress, string expectAddress) private async Task TestRemoteIPAddress(string registerAddress, string requestAddress, string expectAddress)
{ {
var port = PortManager.GetPort();
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls($"http://{registerAddress}:{port}") .UseUrls($"http://{registerAddress}:0")
.Configure(app => .Configure(app =>
{ {
app.Run(async context => app.Run(async context =>
@ -234,7 +229,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
host.Start(); host.Start();
var response = await client.GetAsync($"http://{requestAddress}:{port}/"); var response = await client.GetAsync($"http://{requestAddress}:{host.GetPort()}/");
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
var connectionFacts = await response.Content.ReadAsStringAsync(); var connectionFacts = await response.Content.ReadAsStringAsync();

View File

@ -21,11 +21,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact] [Fact]
public async Task LargeDownload() public async Task LargeDownload()
{ {
var port = PortManager.GetPort();
var config = new ConfigurationBuilder() var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string> .AddInMemoryCollection(new Dictionary<string, string>
{ {
{ "server.urls", $"http://localhost:{port}/" } { "server.urls", $"http://localhost:0/" }
}) })
.Build(); .Build();
@ -57,7 +56,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
using (var client = new HttpClient()) using (var client = new HttpClient())
{ {
var response = await client.GetAsync($"http://localhost:{port}/"); var response = await client.GetAsync($"http://localhost:{host.GetPort()}/");
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStreamAsync(); var responseBody = await response.Content.ReadAsStreamAsync();
@ -81,11 +80,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Theory, MemberData(nameof(NullHeaderData))] [Theory, MemberData(nameof(NullHeaderData))]
public async Task IgnoreNullHeaderValues(string headerName, StringValues headerValue, string expectedValue) public async Task IgnoreNullHeaderValues(string headerName, StringValues headerValue, string expectedValue)
{ {
var port = PortManager.GetPort();
var config = new ConfigurationBuilder() var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string> .AddInMemoryCollection(new Dictionary<string, string>
{ {
{ "server.urls", $"http://localhost:{port}/" } { "server.urls", $"http://localhost:0/" }
}) })
.Build(); .Build();
@ -108,7 +106,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
using (var client = new HttpClient()) using (var client = new HttpClient())
{ {
var response = await client.GetAsync($"http://localhost:{port}/"); var response = await client.GetAsync($"http://localhost:{host.GetPort()}/");
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
var headers = response.Headers; var headers = response.Headers;
@ -129,11 +127,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact] [Fact]
public async Task OnCompleteCalledEvenWhenOnStartingNotCalled() public async Task OnCompleteCalledEvenWhenOnStartingNotCalled()
{ {
var port = PortManager.GetPort();
var config = new ConfigurationBuilder() var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string> .AddInMemoryCollection(new Dictionary<string, string>
{ {
{ "server.urls", $"http://localhost:{port}/" } { "server.urls", $"http://localhost:0/" }
}) })
.Build(); .Build();
@ -161,7 +158,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
using (var client = new HttpClient()) using (var client = new HttpClient())
{ {
var response = await client.GetAsync($"http://localhost:{port}/"); var response = await client.GetAsync($"http://localhost:{host.GetPort()}/");
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
Assert.False(onStartingCalled); Assert.False(onStartingCalled);

View File

@ -16,11 +16,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
public async Task ZeroToTenThreads(int threadCount) public async Task ZeroToTenThreads(int threadCount)
{ {
var port = PortManager.GetPort();
var config = new ConfigurationBuilder() var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string> .AddInMemoryCollection(new Dictionary<string, string>
{ {
{ "server.urls", $"http://localhost:{port}/" } { "server.urls", $"http://localhost:0/" }
}) })
.Build(); .Build();
@ -48,7 +47,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
var requestTasks = new List<Task<string>>(); var requestTasks = new List<Task<string>>();
for (int i = 0; i < 20; i++) for (int i = 0; i < 20; i++)
{ {
var requestTask = client.GetStringAsync($"http://localhost:{port}/"); var requestTask = client.GetStringAsync($"http://localhost:{host.GetPort()}/");
requestTasks.Add(requestTask); requestTasks.Add(requestTask);
} }

View File

@ -5,7 +5,7 @@
"Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.NETCore.Platforms": "1.0.1-*",
"Microsoft.AspNetCore.Http.Abstractions": "1.0.0-*", "Microsoft.AspNetCore.Http.Abstractions": "1.0.0-*",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*",
"Microsoft.AspNetCore.Server.Kestrel.TestCommon": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.0-*",
"Microsoft.AspNetCore.Testing": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*",
"Newtonsoft.Json": "8.0.3", "Newtonsoft.Json": "8.0.3",
"xunit": "2.1.0" "xunit": "2.1.0"
@ -18,6 +18,7 @@
"type": "platform" "type": "platform"
}, },
"System.Net.Http": "4.0.1-*", "System.Net.Http": "4.0.1-*",
"System.Net.Http.WinHttpHandler": "4.0.0-*",
"System.Runtime.Serialization.Primitives": "4.1.1-*" "System.Runtime.Serialization.Primitives": "4.1.1-*"
}, },
"imports": [ "imports": [

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>a485b4f9-0392-478c-b19a-f4de6b17f491</ProjectGuid>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -1,38 +0,0 @@
using System.Net;
using System.Net.Sockets;
namespace Microsoft.AspNetCore.Server.Kestrel.TestCommon
{
public static class PortManager
{
public static int _nextPort = 8001;
public static object _portLock = new object();
public static int GetNextPort()
{
lock (_portLock)
{
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
while (true)
{
try
{
var port = _nextPort++;
socket.Bind(new IPEndPoint(IPAddress.Loopback, port));
return port;
}
catch (SocketException)
{
// Retry unless exhausted
if (_nextPort == 65536)
{
throw;
}
}
}
}
}
}
}
}

View File

@ -1,18 +0,0 @@
{
"version": "1.0.0-*",
"frameworks": {
"net451": {},
"netstandard1.3": {
"dependencies": {
"System.Threading": "4.0.11-*",
"System.Net.Sockets": "4.1.0-*"
},
"imports": [
"portable-net45+win8"
]
}
},
"buildOptions": {
"keyFile": "../../tools/Key.snk"
}
}

View File

@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
FrameFactory = connectionContext => new Frame<HttpContext>( FrameFactory = connectionContext => new Frame<HttpContext>(
new DummyApplication(httpContext => TaskUtilities.CompletedTask), connectionContext), new DummyApplication(httpContext => TaskUtilities.CompletedTask), connectionContext),
Memory = memory, Memory = memory,
ServerAddress = ServerAddress.FromUrl($"http://localhost:{TestServer.GetNextPort()}"), ServerAddress = ServerAddress.FromUrl($"http://localhost:0"),
Thread = engine.Threads[0] Thread = engine.Threads[0]
}; };
var socket = new MockSocket(mockLibuv, Thread.CurrentThread.ManagedThreadId, trace); var socket = new MockSocket(mockLibuv, Thread.CurrentThread.ManagedThreadId, trace);

View File

@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
testContext.App = App; testContext.App = App;
var engine = new KestrelEngine(testContext); var engine = new KestrelEngine(testContext);
engine.Start(1); engine.Start(1);
var address = ServerAddress.FromUrl($"http://localhost:{TestServer.GetNextPort()}/"); var address = ServerAddress.FromUrl($"http://localhost:0/");
var started = engine.CreateServer(address); var started = engine.CreateServer(address);
started.Dispose(); started.Dispose();
engine.Dispose(); engine.Dispose();
@ -98,14 +98,13 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
[MemberData(nameof(ConnectionFilterData))] [MemberData(nameof(ConnectionFilterData))]
public void ConnectionCanReadAndWrite(TestServiceContext testContext) public void ConnectionCanReadAndWrite(TestServiceContext testContext)
{ {
var port = TestServer.GetNextPort();
testContext.App = App; testContext.App = App;
var engine = new KestrelEngine(testContext); var engine = new KestrelEngine(testContext);
engine.Start(1); engine.Start(1);
var address = ServerAddress.FromUrl($"http://localhost:{port}/"); var address = ServerAddress.FromUrl($"http://localhost:0/");
var started = engine.CreateServer(address); var started = engine.CreateServer(address);
var socket = TestConnection.CreateConnectedLoopbackSocket(port); var socket = TestConnection.CreateConnectedLoopbackSocket(address.Port);
socket.Send(Encoding.ASCII.GetBytes("POST / HTTP/1.0\r\n\r\nHello World")); socket.Send(Encoding.ASCII.GetBytes("POST / HTTP/1.0\r\n\r\nHello World"));
socket.Shutdown(SocketShutdown.Send); socket.Shutdown(SocketShutdown.Send);
var buffer = new byte[8192]; var buffer = new byte[8192];

View File

@ -69,18 +69,17 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
var handler = new WinHttpHandler(); var handler = new WinHttpHandler();
handler.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; handler.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
#endif #endif
var serverAddress = $"https://localhost:{TestServer.GetNextPort()}/";
var serviceContext = new TestServiceContext(new HttpsConnectionFilter( var serviceContext = new TestServiceContext(new HttpsConnectionFilter(
new HttpsConnectionFilterOptions new HttpsConnectionFilterOptions
{ ServerCertificate = new X509Certificate2(@"TestResources/testCert.pfx", "testPassword") }, { ServerCertificate = new X509Certificate2(@"TestResources/testCert.pfx", "testPassword") },
new NoOpConnectionFilter()) new NoOpConnectionFilter())
); );
using (var server = new TestServer(App, serviceContext, serverAddress)) using (var server = new TestServer(App, serviceContext, "https://localhost:0/"))
{ {
using (var client = new HttpClient(handler)) using (var client = new HttpClient(handler))
{ {
var result = await client.PostAsync(serverAddress, new FormUrlEncodedContent(new[] { var result = await client.PostAsync($"https://localhost:{server.Port}/", new FormUrlEncodedContent(new[] {
new KeyValuePair<string, string>("content", "Hello World?") new KeyValuePair<string, string>("content", "Hello World?")
})); }));
@ -114,7 +113,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
handler.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; handler.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
#endif #endif
var serverAddress = $"https://localhost:{TestServer.GetNextPort()}/";
var serviceContext = new TestServiceContext(new HttpsConnectionFilter( var serviceContext = new TestServiceContext(new HttpsConnectionFilter(
new HttpsConnectionFilterOptions new HttpsConnectionFilterOptions
{ {
@ -124,12 +122,12 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
new NoOpConnectionFilter()) new NoOpConnectionFilter())
); );
using (var server = new TestServer(App, serviceContext, serverAddress)) using (var server = new TestServer(App, serviceContext, "https://localhost:0/"))
{ {
using (var client = new HttpClient(handler)) using (var client = new HttpClient(handler))
{ {
await Assert.ThrowsAnyAsync<Exception>( await Assert.ThrowsAnyAsync<Exception>(
() => client.GetAsync(serverAddress)); () => client.GetAsync($"https://localhost:{server.Port}/"));
} }
} }
} }
@ -159,7 +157,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
handler.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; handler.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
#endif #endif
var serverAddress = $"https://localhost:{TestServer.GetNextPort()}/";
var serviceContext = new TestServiceContext(new HttpsConnectionFilter( var serviceContext = new TestServiceContext(new HttpsConnectionFilter(
new HttpsConnectionFilterOptions new HttpsConnectionFilterOptions
{ {
@ -175,11 +172,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
return context.Response.WriteAsync("hello world"); return context.Response.WriteAsync("hello world");
}; };
using (var server = new TestServer(app, serviceContext, serverAddress)) using (var server = new TestServer(app, serviceContext, "https://localhost:0/"))
{ {
using (var client = new HttpClient(handler)) using (var client = new HttpClient(handler))
{ {
var result = await client.GetAsync(serverAddress); var result = await client.GetAsync($"https://localhost:{server.Port}/");
Assert.Equal("hello world", await result.Content.ReadAsStringAsync()); Assert.Equal("hello world", await result.Content.ReadAsStringAsync());
} }
@ -206,7 +203,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
ServicePointManager.ServerCertificateValidationCallback += validationCallback; ServicePointManager.ServerCertificateValidationCallback += validationCallback;
#endif #endif
var serverAddress = $"https://localhost:{TestServer.GetNextPort()}/";
var serviceContext = new TestServiceContext(new HttpsConnectionFilter( var serviceContext = new TestServiceContext(new HttpsConnectionFilter(
new HttpsConnectionFilterOptions new HttpsConnectionFilterOptions
{ {
@ -226,7 +222,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
return context.Response.WriteAsync("hello world"); return context.Response.WriteAsync("hello world");
}; };
using (var server = new TestServer(app, serviceContext, serverAddress)) using (var server = new TestServer(app, serviceContext, "https://localhost:0/"))
{ {
// SslStream is used to ensure the certificate is actually passed to the server // 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 // HttpClient might not send the certificate because it is invalid or it doesn't match any
@ -274,7 +270,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
handler.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; handler.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
#endif #endif
var serverAddress = $"https://localhost:{TestServer.GetNextPort()}/";
var serviceContext = new TestServiceContext( var serviceContext = new TestServiceContext(
new HttpsConnectionFilter( new HttpsConnectionFilter(
new HttpsConnectionFilterOptions new HttpsConnectionFilterOptions
@ -286,11 +281,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
RequestDelegate app = context => context.Response.WriteAsync(context.Request.Scheme); RequestDelegate app = context => context.Response.WriteAsync(context.Request.Scheme);
using (var server = new TestServer(app, serviceContext, serverAddress)) using (var server = new TestServer(app, serviceContext, "https://localhost:0/"))
{ {
using (var client = new HttpClient(handler)) using (var client = new HttpClient(handler))
{ {
var result = await client.GetAsync(serverAddress); var result = await client.GetAsync($"https://localhost:{server.Port}/");
Assert.Equal("https", await result.Content.ReadAsStringAsync()); Assert.Equal("https", await result.Content.ReadAsStringAsync());
} }
@ -317,7 +312,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
ServicePointManager.ServerCertificateValidationCallback += validationCallback; ServicePointManager.ServerCertificateValidationCallback += validationCallback;
#endif #endif
var serverAddress = $"https://localhost:{TestServer.GetNextPort()}/";
var serviceContext = new TestServiceContext(new HttpsConnectionFilter( var serviceContext = new TestServiceContext(new HttpsConnectionFilter(
new HttpsConnectionFilterOptions new HttpsConnectionFilterOptions
{ {
@ -333,7 +327,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
return context.Response.WriteAsync("hello world"); return context.Response.WriteAsync("hello world");
}; };
using (var server = new TestServer(app, serviceContext, serverAddress)) using (var server = new TestServer(app, serviceContext, "https://localhost:0/"))
{ {
// SslStream is used to ensure the certificate is actually passed to the server // 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 // HttpClient might not send the certificate because it is invalid or it doesn't match any

View File

@ -128,7 +128,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
{ {
var pipeName = @"\\.\pipe\ServerPipeDispatchConnections" + Guid.NewGuid().ToString("n"); var pipeName = @"\\.\pipe\ServerPipeDispatchConnections" + Guid.NewGuid().ToString("n");
var port = TestServer.GetNextPort();
var loop = new UvLoopHandle(_logger); var loop = new UvLoopHandle(_logger);
loop.Init(_uv); loop.Init(_uv);
@ -158,8 +157,9 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
var serverListenTcp = new UvTcpHandle(_logger); var serverListenTcp = new UvTcpHandle(_logger);
serverListenTcp.Init(loop, (a, b) => { }); serverListenTcp.Init(loop, (a, b) => { });
var address = ServerAddress.FromUrl($"http://localhost:{port}/"); var address = ServerAddress.FromUrl($"http://localhost:0/");
serverListenTcp.Bind(address); serverListenTcp.Bind(address);
var port = serverListenTcp.GetSockIPEndPoint().Port;
serverListenTcp.Listen(128, (_1, status, error, _2) => serverListenTcp.Listen(128, (_1, status, error, _2) =>
{ {
var serverConnectionTcp = new UvTcpHandle(_logger); var serverConnectionTcp = new UvTcpHandle(_logger);

View File

@ -76,9 +76,9 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
loop.Init(_uv); loop.Init(_uv);
var tcp = new UvTcpHandle(_logger); var tcp = new UvTcpHandle(_logger);
tcp.Init(loop, (a, b) => { }); tcp.Init(loop, (a, b) => { });
var port = TestServer.GetNextPort(); var address = ServerAddress.FromUrl($"http://localhost:0/");
var address = ServerAddress.FromUrl($"http://localhost:{port}/");
tcp.Bind(address); tcp.Bind(address);
var port = tcp.GetSockIPEndPoint().Port;
tcp.Listen(10, (stream, status, error, state) => tcp.Listen(10, (stream, status, error, state) =>
{ {
var tcp2 = new UvTcpHandle(_logger); var tcp2 = new UvTcpHandle(_logger);
@ -105,9 +105,9 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
loop.Init(_uv); loop.Init(_uv);
var tcp = new UvTcpHandle(_logger); var tcp = new UvTcpHandle(_logger);
tcp.Init(loop, (a, b) => { }); tcp.Init(loop, (a, b) => { });
var port = TestServer.GetNextPort(); var address = ServerAddress.FromUrl($"http://localhost:0/");
var address = ServerAddress.FromUrl($"http://localhost:{port}/");
tcp.Bind(address); tcp.Bind(address);
var port = tcp.GetSockIPEndPoint().Port;
tcp.Listen(10, (_, status, error, state) => tcp.Listen(10, (_, status, error, state) =>
{ {
var tcp2 = new UvTcpHandle(_logger); var tcp2 = new UvTcpHandle(_logger);
@ -155,9 +155,9 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
loop.Init(_uv); loop.Init(_uv);
var tcp = new UvTcpHandle(_logger); var tcp = new UvTcpHandle(_logger);
tcp.Init(loop, (a, b) => { }); tcp.Init(loop, (a, b) => { });
var port = TestServer.GetNextPort(); var address = ServerAddress.FromUrl($"http://localhost:0/");
var address = ServerAddress.FromUrl($"http://localhost:{port}/");
tcp.Bind(address); tcp.Bind(address);
var port = tcp.GetSockIPEndPoint().Port;
tcp.Listen(10, (_, status, error, state) => tcp.Listen(10, (_, status, error, state) =>
{ {
var tcp2 = new UvTcpHandle(_logger); var tcp2 = new UvTcpHandle(_logger);

View File

@ -19,27 +19,28 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
} }
[Theory] [Theory]
[InlineData("://emptyscheme", "", "emptyscheme", 0, "")] [InlineData("5000", "http", "+", 5000, "/", "http://+:5000/")]
[InlineData("http://localhost", "http", "localhost", 80, "")] [InlineData("://emptyscheme", "", "emptyscheme", 0, "", "://emptyscheme:0")]
[InlineData("http://www.example.com", "http", "www.example.com", 80, "")] [InlineData("http://localhost", "http", "localhost", 80, "", "http://localhost:80")]
[InlineData("https://www.example.com", "https", "www.example.com", 443, "")] [InlineData("http://www.example.com", "http", "www.example.com", 80, "", "http://www.example.com:80")]
[InlineData("http://www.example.com/", "http", "www.example.com", 80, "")] [InlineData("https://www.example.com", "https", "www.example.com", 443, "", "https://www.example.com:443")]
[InlineData("http://www.example.com/foo?bar=baz", "http", "www.example.com", 80, "/foo?bar=baz")] [InlineData("http://www.example.com/", "http", "www.example.com", 80, "", "http://www.example.com:80")]
[InlineData("http://www.example.com:5000", "http", "www.example.com", 5000, "")] [InlineData("http://www.example.com/foo?bar=baz", "http", "www.example.com", 80, "/foo?bar=baz", "http://www.example.com:80/foo?bar=baz")]
[InlineData("https://www.example.com:5000", "https", "www.example.com", 5000, "")] [InlineData("http://www.example.com:5000", "http", "www.example.com", 5000, "", null)]
[InlineData("http://www.example.com:5000/", "http", "www.example.com", 5000, "")] [InlineData("https://www.example.com:5000", "https", "www.example.com", 5000, "", null)]
[InlineData("http://www.example.com:NOTAPORT", "http", "www.example.com:NOTAPORT", 80, "")] [InlineData("http://www.example.com:5000/", "http", "www.example.com", 5000, "", "http://www.example.com:5000")]
[InlineData("https://www.example.com:NOTAPORT", "https", "www.example.com:NOTAPORT", 443, "")] [InlineData("http://www.example.com:NOTAPORT", "http", "www.example.com:NOTAPORT", 80, "", "http://www.example.com:notaport:80")]
[InlineData("http://www.example.com:NOTAPORT/", "http", "www.example.com:NOTAPORT", 80, "")] [InlineData("https://www.example.com:NOTAPORT", "https", "www.example.com:NOTAPORT", 443, "", "https://www.example.com:notaport:443")]
[InlineData("http://foo:/tmp/kestrel-test.sock:5000/doesn't/matter", "http", "foo:", 80, "/tmp/kestrel-test.sock:5000/doesn't/matter")] [InlineData("http://www.example.com:NOTAPORT/", "http", "www.example.com:NOTAPORT", 80, "", "http://www.example.com:notaport:80")]
[InlineData("http://unix:foo/tmp/kestrel-test.sock", "http", "unix:foo", 80, "/tmp/kestrel-test.sock")] [InlineData("http://foo:/tmp/kestrel-test.sock:5000/doesn't/matter", "http", "foo:", 80, "/tmp/kestrel-test.sock:5000/doesn't/matter", "http://foo::80/tmp/kestrel-test.sock:5000/doesn't/matter")]
[InlineData("http://unix:5000/tmp/kestrel-test.sock", "http", "unix", 5000, "/tmp/kestrel-test.sock")] [InlineData("http://unix:foo/tmp/kestrel-test.sock", "http", "unix:foo", 80, "/tmp/kestrel-test.sock", "http://unix:foo:80/tmp/kestrel-test.sock")]
[InlineData("http://unix:/tmp/kestrel-test.sock", "http", "unix:/tmp/kestrel-test.sock", 0, "")] [InlineData("http://unix:5000/tmp/kestrel-test.sock", "http", "unix", 5000, "/tmp/kestrel-test.sock", null)]
[InlineData("https://unix:/tmp/kestrel-test.sock", "https", "unix:/tmp/kestrel-test.sock", 0, "")] [InlineData("http://unix:/tmp/kestrel-test.sock", "http", "unix:/tmp/kestrel-test.sock", 0, "", null)]
[InlineData("http://unix:/tmp/kestrel-test.sock:", "http", "unix:/tmp/kestrel-test.sock", 0, "")] [InlineData("https://unix:/tmp/kestrel-test.sock", "https", "unix:/tmp/kestrel-test.sock", 0, "", null)]
[InlineData("http://unix:/tmp/kestrel-test.sock:/", "http", "unix:/tmp/kestrel-test.sock", 0, "")] [InlineData("http://unix:/tmp/kestrel-test.sock:", "http", "unix:/tmp/kestrel-test.sock", 0, "", "http://unix:/tmp/kestrel-test.sock")]
[InlineData("http://unix:/tmp/kestrel-test.sock:5000/doesn't/matter", "http", "unix:/tmp/kestrel-test.sock", 0, "5000/doesn't/matter")] [InlineData("http://unix:/tmp/kestrel-test.sock:/", "http", "unix:/tmp/kestrel-test.sock", 0, "", "http://unix:/tmp/kestrel-test.sock")]
public void UrlsAreParsedCorrectly(string url, string scheme, string host, int port, string pathBase) [InlineData("http://unix:/tmp/kestrel-test.sock:5000/doesn't/matter", "http", "unix:/tmp/kestrel-test.sock", 0, "5000/doesn't/matter", null)]
public void UrlsAreParsedCorrectly(string url, string scheme, string host, int port, string pathBase, string toString)
{ {
var serverAddress = ServerAddress.FromUrl(url); var serverAddress = ServerAddress.FromUrl(url);
@ -47,6 +48,8 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
Assert.Equal(host, serverAddress.Host); Assert.Equal(host, serverAddress.Host);
Assert.Equal(port, serverAddress.Port); Assert.Equal(port, serverAddress.Port);
Assert.Equal(pathBase, serverAddress.PathBase); Assert.Equal(pathBase, serverAddress.PathBase);
Assert.Equal(toString ?? url, serverAddress.ToString());
} }
[Fact] [Fact]

View File

@ -6,7 +6,6 @@ using System.Threading;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel; using Microsoft.AspNetCore.Server.Kestrel;
using Microsoft.AspNetCore.Server.Kestrel.Http; using Microsoft.AspNetCore.Server.Kestrel.Http;
using Microsoft.AspNetCore.Server.Kestrel.TestCommon;
namespace Microsoft.AspNetCore.Server.KestrelTests namespace Microsoft.AspNetCore.Server.KestrelTests
{ {
@ -25,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
} }
public TestServer(RequestDelegate app, ServiceContext context) public TestServer(RequestDelegate app, ServiceContext context)
: this(app, context, $"http://localhost:{GetNextPort()}/") : this(app, context, "http://localhost:0/")
{ {
} }
@ -58,10 +57,5 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
_server.Dispose(); _server.Dispose();
_engine.Dispose(); _engine.Dispose();
} }
public static int GetNextPort()
{
return PortManager.GetNextPort();
}
} }
} }

View File

@ -5,7 +5,6 @@
"Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.NETCore.Platforms": "1.0.1-*",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*",
"Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.0-*",
"Microsoft.AspNetCore.Server.Kestrel.TestCommon": "1.0.0-*",
"Microsoft.AspNetCore.Testing": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*",
"xunit": "2.1.0" "xunit": "2.1.0"
}, },