aspnetcore/test/Microsoft.Net.Http.Server.F.../Utilities.cs

117 lines
4.3 KiB
C#

// 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.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Internal;
namespace Microsoft.Net.Http.Server
{
internal static class Utilities
{
// When tests projects are run in parallel, overlapping port ranges can cause a race condition when looking for free
// ports during dynamic port allocation. To avoid this, make sure the port range here is different from the range in
// Microsoft.AspNetCore.Server.WebListener.
private const int BasePort = 8001;
private const int MaxPort = 11000;
private static int NextPort = BasePort;
private static object PortLock = new object();
internal static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(15);
// Minimum support for Windows 7 is assumed.
internal static readonly bool IsWin8orLater;
static Utilities()
{
var win8Version = new Version(6, 2);
#if NET451
IsWin8orLater = (Environment.OSVersion.Version >= win8Version);
#else
IsWin8orLater = (new Version(RuntimeEnvironment.OperatingSystemVersion) >= win8Version);
#endif
}
internal static WebListener CreateHttpAuthServer(AuthenticationSchemes authScheme, bool allowAnonymos, out string baseAddress)
{
var listener = CreateHttpServer(out baseAddress);
listener.Settings.Authentication.Schemes = authScheme;
listener.Settings.Authentication.AllowAnonymous = allowAnonymos;
return listener;
}
internal static WebListener CreateHttpServer(out string baseAddress)
{
string root;
return CreateDynamicHttpServer(string.Empty, out root, out baseAddress);
}
internal static WebListener CreateHttpServerReturnRoot(string path, out string root)
{
string baseAddress;
return CreateDynamicHttpServer(path, out root, out baseAddress);
}
internal static WebListener CreateDynamicHttpServer(string basePath, out string root, out string baseAddress)
{
lock (PortLock)
{
while (NextPort < MaxPort)
{
var port = NextPort++;
var prefix = UrlPrefix.Create("http", "localhost", port, basePath);
root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port;
baseAddress = prefix.ToString();
var listener = new WebListener();
listener.Settings.UrlPrefixes.Add(prefix);
try
{
listener.Start();
return listener;
}
catch (WebListenerException)
{
listener.Dispose();
}
}
NextPort = BasePort;
}
throw new Exception("Failed to locate a free port.");
}
internal static WebListener CreateHttpsServer()
{
return CreateServer("https", "localhost", 9090, string.Empty);
}
internal static WebListener CreateServer(string scheme, string host, int port, string path)
{
WebListener listener = new WebListener();
listener.Settings.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path));
listener.Start();
return listener;
}
/// <summary>
/// AcceptAsync extension with timeout. This extension should be used in all tests to prevent
/// unexpected hangs when a request does not arrive.
/// </summary>
internal static async Task<RequestContext> AcceptAsync(this WebListener server, TimeSpan timeout)
{
var acceptTask = server.AcceptAsync();
var completedTask = await Task.WhenAny(acceptTask, Task.Delay(timeout));
if (completedTask == acceptTask)
{
return await acceptTask;
}
else
{
server.Dispose();
throw new TimeoutException("AcceptAsync has timed out.");
}
}
}
}