Make https redirect no-op if no port is available #318

This commit is contained in:
Chris Ross (ASP.NET) 2018-04-13 15:55:42 -07:00
parent 0c31fcdf30
commit 0a876cece7
8 changed files with 252 additions and 53 deletions

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
@ -8,6 +8,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="$(MicrosoftAspNetCoreServerKestrelHttpsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
</ItemGroup>
<ItemGroup>

View File

@ -21,7 +21,7 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:31895/"
"applicationUrl": "http://localhost:5000/"
}
}
}
}

View File

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace HttpsSample
{
@ -62,6 +63,11 @@ namespace HttpsSample
});
})
.UseContentRoot(Directory.GetCurrentDirectory()) // for the cert file
.ConfigureLogging(factory =>
{
factory.SetMinimumLevel(LogLevel.Debug);
factory.AddConsole();
})
.UseStartup<Startup>()
.Build();

View File

@ -7,7 +7,9 @@ using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.HttpsPolicy.Internal;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
@ -16,11 +18,13 @@ namespace Microsoft.AspNetCore.HttpsPolicy
public class HttpsRedirectionMiddleware
{
private readonly RequestDelegate _next;
private bool _portEvaluated = false;
private int? _httpsPort;
private readonly int _statusCode;
private readonly IServerAddressesFeature _serverAddressesFeature;
private readonly IConfiguration _config;
private readonly ILogger _logger;
/// <summary>
/// Initializes the HttpsRedirectionMiddleware
@ -28,7 +32,8 @@ namespace Microsoft.AspNetCore.HttpsPolicy
/// <param name="next"></param>
/// <param name="options"></param>
/// <param name="config"></param>
public HttpsRedirectionMiddleware(RequestDelegate next, IOptions<HttpsRedirectionOptions> options, IConfiguration config)
/// <param name="loggerFactory"></param>
public HttpsRedirectionMiddleware(RequestDelegate next, IOptions<HttpsRedirectionOptions> options, IConfiguration config, ILoggerFactory loggerFactory)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
@ -40,7 +45,9 @@ namespace Microsoft.AspNetCore.HttpsPolicy
}
var httpsRedirectionOptions = options.Value;
_httpsPort = httpsRedirectionOptions.HttpsPort;
_portEvaluated = _httpsPort.HasValue;
_statusCode = httpsRedirectionOptions.RedirectStatusCode;
_logger = loggerFactory.CreateLogger<HttpsRedirectionMiddleware>();
}
/// <summary>
@ -49,9 +56,11 @@ namespace Microsoft.AspNetCore.HttpsPolicy
/// <param name="next"></param>
/// <param name="options"></param>
/// <param name="config"></param>
/// <param name="loggerFactory"></param>
/// <param name="serverAddressesFeature">The</param>
public HttpsRedirectionMiddleware(RequestDelegate next, IOptions<HttpsRedirectionOptions> options, IConfiguration config, IServerAddressesFeature serverAddressesFeature)
: this(next, options, config)
public HttpsRedirectionMiddleware(RequestDelegate next, IOptions<HttpsRedirectionOptions> options, IConfiguration config, ILoggerFactory loggerFactory,
IServerAddressesFeature serverAddressesFeature)
: this(next, options, config, loggerFactory)
{
_serverAddressesFeature = serverAddressesFeature ?? throw new ArgumentNullException(nameof(serverAddressesFeature));
}
@ -63,20 +72,15 @@ namespace Microsoft.AspNetCore.HttpsPolicy
/// <returns></returns>
public Task Invoke(HttpContext context)
{
if (context.Request.IsHttps)
if (context.Request.IsHttps || !TryGetHttpsPort(out var port))
{
return _next(context);
}
if (!_httpsPort.HasValue)
{
CheckForHttpsPorts();
}
var host = context.Request.Host;
if (_httpsPort != 443)
if (port != 443)
{
host = new HostString(host.Host, _httpsPort.Value);
host = new HostString(host.Host, port);
}
else
{
@ -94,28 +98,41 @@ namespace Microsoft.AspNetCore.HttpsPolicy
context.Response.StatusCode = _statusCode;
context.Response.Headers[HeaderNames.Location] = redirectUrl;
_logger.RedirectingToHttps(redirectUrl);
return Task.CompletedTask;
}
private void CheckForHttpsPorts()
private bool TryGetHttpsPort(out int port)
{
// The IServerAddressesFeature will not be ready until the middleware is Invoked,
// Order for finding the HTTPS port:
// 1. Set in the HttpsRedirectionOptions
// 2. HTTPS_PORT environment variable
// 3. IServerAddressesFeature
// 4. 443 (or not set)
// 4. Fail if not set
port = -1;
if (_portEvaluated)
{
port = _httpsPort ?? port;
return _httpsPort.HasValue;
}
_portEvaluated = true;
_httpsPort = _config.GetValue<int?>("HTTPS_PORT");
if (_httpsPort.HasValue)
{
return;
port = _httpsPort.Value;
_logger.PortLoadedFromConfig(port);
return true;
}
if (_serverAddressesFeature == null)
{
_httpsPort = 443;
return;
_logger.FailedToDeterminePort();
return false;
}
int? httpsPort = null;
@ -127,8 +144,8 @@ namespace Microsoft.AspNetCore.HttpsPolicy
// If we find multiple different https ports specified, throw
if (httpsPort.HasValue && httpsPort != bindingAddress.Port)
{
throw new ArgumentException("Cannot determine the https port from IServerAddressesFeature, multiple values were found. " +
"Please set the desired port explicitly on HttpsRedirectionOptions.HttpsPort.");
_logger.FailedMultiplePorts();
return false;
}
else
{
@ -136,7 +153,17 @@ namespace Microsoft.AspNetCore.HttpsPolicy
}
}
}
_httpsPort = httpsPort ?? 443;
if (httpsPort.HasValue)
{
_httpsPort = httpsPort;
port = _httpsPort.Value;
_logger.PortFromServer(port);
return true;
}
_logger.FailedToDeterminePort();
return false;
}
}
}

View File

@ -0,0 +1,53 @@
// 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 Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.HttpsPolicy.Internal
{
internal static class HttpsLoggingExtensions
{
private static readonly Action<ILogger, string, Exception> _redirectingToHttps;
private static readonly Action<ILogger, int, Exception> _portLoadedFromConfig;
private static readonly Action<ILogger, Exception> _failedToDeterminePort;
private static readonly Action<ILogger, Exception> _failedMultiplePorts;
private static readonly Action<ILogger, int, Exception> _portFromServer;
static HttpsLoggingExtensions()
{
_redirectingToHttps = LoggerMessage.Define<string>(LogLevel.Debug, 1, "Redirecting to '{redirect}'.");
_portLoadedFromConfig = LoggerMessage.Define<int>(LogLevel.Debug, 2, "Https port '{port}' loaded from configuration.");
_failedToDeterminePort = LoggerMessage.Define(LogLevel.Warning, 3, "Failed to determine the https port for redirect.");
_failedMultiplePorts = LoggerMessage.Define(LogLevel.Warning, 4,
"Cannot determine the https port from IServerAddressesFeature, multiple values were found. " +
"Please set the desired port explicitly on HttpsRedirectionOptions.HttpsPort.");
_portFromServer = LoggerMessage.Define<int>(LogLevel.Debug, 5, "Https port '{httpsPort}' discovered from server endpoints.");
}
public static void RedirectingToHttps(this ILogger logger, string redirect)
{
_redirectingToHttps(logger, redirect, null);
}
public static void PortLoadedFromConfig(this ILogger logger, int port)
{
_portLoadedFromConfig(logger, port, null);
}
public static void FailedToDeterminePort(this ILogger logger)
{
_failedToDeterminePort(logger, null);
}
public static void FailedMultiplePorts(this ILogger logger)
{
_failedMultiplePorts(logger, null);
}
public static void PortFromServer(this ILogger logger, int port)
{
_portFromServer(logger, port, null);
}
}
}

View File

@ -21,12 +21,12 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
public class HttpsPolicyTests
{
[Theory]
[InlineData(302, null, 2592000, false, false, "max-age=2592000", "https://localhost/")]
[InlineData(302, 443, 2592000, false, false, "max-age=2592000", "https://localhost/")]
[InlineData(301, 5050, 2592000, false, false, "max-age=2592000", "https://localhost:5050/")]
[InlineData(301, 443, 2592000, false, false, "max-age=2592000", "https://localhost/")]
[InlineData(301, 443, 2592000, true, false, "max-age=2592000; includeSubDomains", "https://localhost/")]
[InlineData(301, 443, 2592000, false, true, "max-age=2592000; preload", "https://localhost/")]
[InlineData(301, null, 2592000, true, true, "max-age=2592000; includeSubDomains; preload", "https://localhost/")]
[InlineData(301, 443, 2592000, true, true, "max-age=2592000; includeSubDomains; preload", "https://localhost/")]
[InlineData(302, 5050, 2592000, true, true, "max-age=2592000; includeSubDomains; preload", "https://localhost:5050/")]
public async Task SetsBothHstsAndHttpsRedirection_RedirectOnFirstRequest_HstsOnSecondRequest(int statusCode, int? tlsPort, int maxAge, bool includeSubDomains, bool preload, string expectedHstsHeader, string expectedUrl)
{
@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
client = server.CreateClient();
client.BaseAddress = new Uri(response.Headers.Location.ToString());
request = new HttpRequestMessage(HttpMethod.Get, "");
request = new HttpRequestMessage(HttpMethod.Get, expectedUrl);
response = await client.SendAsync(request);
Assert.Equal(expectedHstsHeader, response.Headers.GetValues(HeaderNames.StrictTransportSecurity).FirstOrDefault());

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
@ -12,6 +13,8 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Xunit;
namespace Microsoft.AspNetCore.HttpsPolicy.Tests
@ -19,9 +22,17 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
public class HttpsRedirectionMiddlewareTests
{
[Fact]
public async Task SetOptions_DefaultsSetCorrectly()
public async Task SetOptions_NotEnabledByDefault()
{
var sink = new TestSink(
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
var builder = new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddSingleton<ILoggerFactory>(loggerFactory);
})
.Configure(app =>
{
app.UseHttpsRedirection();
@ -38,23 +49,32 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
var response = await client.SendAsync(request);
Assert.Equal(HttpStatusCode.RedirectKeepVerb, response.StatusCode);
Assert.Equal("https://localhost/", response.Headers.Location.ToString());
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var logMessages = sink.Writes.ToList();
Assert.Single(logMessages);
var message = logMessages.Single();
Assert.Equal(LogLevel.Warning, message.LogLevel);
Assert.Equal("Failed to determine the https port for redirect.", message.State.ToString());
}
[Theory]
[InlineData(301, null, "https://localhost/")]
[InlineData(302, null, "https://localhost/")]
[InlineData(307, null, "https://localhost/")]
[InlineData(308, null, "https://localhost/")]
[InlineData(302, 5001, "https://localhost:5001/")]
[InlineData(307, 1, "https://localhost:1/")]
[InlineData(308, 3449, "https://localhost:3449/")]
[InlineData(301, 5050, "https://localhost:5050/")]
[InlineData(301, 443, "https://localhost/")]
public async Task SetOptions_SetStatusCodeHttpsPort(int statusCode, int? httpsPort, string expected)
{
var sink = new TestSink(
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
var builder = new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddSingleton<ILoggerFactory>(loggerFactory);
services.Configure<HttpsRedirectionOptions>(options =>
{
options.RedirectStatusCode = statusCode;
@ -79,20 +99,31 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
Assert.Equal(statusCode, (int)response.StatusCode);
Assert.Equal(expected, response.Headers.Location.ToString());
var logMessages = sink.Writes.ToList();
Assert.Single(logMessages);
var message = logMessages.Single();
Assert.Equal(LogLevel.Debug, message.LogLevel);
Assert.Equal($"Redirecting to '{expected}'.", message.State.ToString());
}
[Theory]
[InlineData(301, null, "https://localhost/")]
[InlineData(302, null, "https://localhost/")]
[InlineData(307, null, "https://localhost/")]
[InlineData(308, null, "https://localhost/")]
[InlineData(302, 5001, "https://localhost:5001/")]
[InlineData(307, 1, "https://localhost:1/")]
[InlineData(308, 3449, "https://localhost:3449/")]
[InlineData(301, 5050, "https://localhost:5050/")]
[InlineData(301, 443, "https://localhost/")]
public async Task SetOptionsThroughHelperMethod_SetStatusCodeAndHttpsPort(int statusCode, int? httpsPort, string expectedUrl)
{
var sink = new TestSink(
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
var builder = new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddSingleton<ILoggerFactory>(loggerFactory);
services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = statusCode;
@ -117,20 +148,26 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
Assert.Equal(statusCode, (int)response.StatusCode);
Assert.Equal(expectedUrl, response.Headers.Location.ToString());
var logMessages = sink.Writes.ToList();
Assert.Single(logMessages);
var message = logMessages.Single();
Assert.Equal(LogLevel.Debug, message.LogLevel);
Assert.Equal($"Redirecting to '{expectedUrl}'.", message.State.ToString());
}
[Theory]
[InlineData(null, null, null, "https://localhost/")]
[InlineData(null, null, "https://localhost:4444/", "https://localhost:4444/")]
[InlineData(null, null, "https://localhost:443/", "https://localhost/")]
[InlineData(null, null, "http://localhost:5044/", "https://localhost/")]
[InlineData(null, null, "https://localhost/", "https://localhost/")]
[InlineData(null, "5000", "https://localhost:4444/", "https://localhost:5000/")]
[InlineData(null, "443", "https://localhost:4444/", "https://localhost/")]
[InlineData(443, "5000", "https://localhost:4444/", "https://localhost/")]
[InlineData(4000, "5000", "https://localhost:4444/", "https://localhost:4000/")]
[InlineData(5000, null, "https://localhost:4444/", "https://localhost:5000/")]
public async Task SetHttpsPortEnvironmentVariableAndServerFeature_ReturnsCorrectStatusCodeOnResponse(int? optionsHttpsPort, string configHttpsPort, string serverAddressFeatureUrl, string expectedUrl)
public async Task SetHttpsPortEnvironmentVariableAndServerFeature_ReturnsCorrectStatusCodeOnResponse(
int? optionsHttpsPort, string configHttpsPort, string serverAddressFeatureUrl, string expectedUrl)
{
var builder = new WebHostBuilder()
.ConfigureServices(services =>
@ -172,7 +209,15 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
[Fact]
public async Task SetServerAddressesFeature_SingleHttpsAddress_Success()
{
var sink = new TestSink(
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
var builder = new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddSingleton<ILoggerFactory>(loggerFactory);
})
.Configure(app =>
{
app.UseHttpsRedirection();
@ -194,12 +239,31 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
var response = await client.SendAsync(request);
Assert.Equal("https://localhost:5050/", response.Headers.Location.ToString());
var logMessages = sink.Writes.ToList();
Assert.Equal(2, logMessages.Count);
var message = logMessages.First();
Assert.Equal(LogLevel.Debug, message.LogLevel);
Assert.Equal("Https port '5050' discovered from server endpoints.", message.State.ToString());
message = logMessages.Skip(1).First();
Assert.Equal(LogLevel.Debug, message.LogLevel);
Assert.Equal("Redirecting to 'https://localhost:5050/'.", message.State.ToString());
}
[Fact]
public async Task SetServerAddressesFeature_MultipleHttpsAddresses_ThrowInMiddleware()
public async Task SetServerAddressesFeature_MultipleHttpsAddresses_LogsAndFailsToRedirect()
{
var sink = new TestSink(
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
var builder = new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddSingleton<ILoggerFactory>(loggerFactory);
})
.Configure(app =>
{
app.UseHttpsRedirection();
@ -220,13 +284,30 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
var request = new HttpRequestMessage(HttpMethod.Get, "");
await Assert.ThrowsAsync<ArgumentException>(async () => await client.SendAsync(request));
var response = await client.SendAsync(request);
Assert.Equal(200, (int)response.StatusCode);
var logMessages = sink.Writes.ToList();
Assert.Single(logMessages);
var message = logMessages.First();
Assert.Equal(LogLevel.Warning, message.LogLevel);
Assert.Equal("Cannot determine the https port from IServerAddressesFeature, multiple values were found. " +
"Please set the desired port explicitly on HttpsRedirectionOptions.HttpsPort.", message.State.ToString());
}
[Fact]
public async Task SetServerAddressesFeature_MultipleHttpsAddressesWithSamePort_Success()
{
var sink = new TestSink(
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
var builder = new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddSingleton<ILoggerFactory>(loggerFactory);
})
.Configure(app =>
{
app.UseHttpsRedirection();
@ -241,7 +322,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
var server = new TestServer(builder, featureCollection);
server.Features.Get<IServerAddressesFeature>().Addresses.Add("https://localhost:5050");
server.Features.Get<IServerAddressesFeature>().Addresses.Add("https://localhost:5050");
server.Features.Get<IServerAddressesFeature>().Addresses.Add("https://example.com:5050");
var client = server.CreateClient();
@ -250,17 +331,30 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
var response = await client.SendAsync(request);
Assert.Equal("https://localhost:5050/", response.Headers.Location.ToString());
var logMessages = sink.Writes.ToList();
Assert.Equal(2, logMessages.Count);
var message = logMessages.First();
Assert.Equal(LogLevel.Debug, message.LogLevel);
Assert.Equal("Https port '5050' discovered from server endpoints.", message.State.ToString());
message = logMessages.Skip(1).First();
Assert.Equal(LogLevel.Debug, message.LogLevel);
Assert.Equal("Redirecting to 'https://localhost:5050/'.", message.State.ToString());
}
[Fact]
public async Task NoServerAddressFeature_DoesNotThrow_DefaultsTo443()
public async Task NoServerAddressFeature_DoesNotThrow_DoesNotRedirect()
{
var sink = new TestSink(
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
var builder = new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddHttpsRedirection(options =>
{
});
services.AddSingleton<ILoggerFactory>(loggerFactory);
})
.Configure(app =>
{
@ -275,19 +369,27 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
var client = server.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Get, "");
var response = await client.SendAsync(request);
Assert.Equal(200, (int)response.StatusCode);
Assert.Equal("https://localhost/", response.Headers.Location.ToString());
var logMessages = sink.Writes.ToList();
Assert.Single(logMessages);
var message = logMessages.First();
Assert.Equal(LogLevel.Warning, message.LogLevel);
Assert.Equal("Failed to determine the https port for redirect.", message.State.ToString());
}
[Fact]
public async Task SetNullAddressFeature_DoesNotThrow()
{
var sink = new TestSink(
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
var builder = new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddHttpsRedirection(options =>
{
});
services.AddSingleton<ILoggerFactory>(loggerFactory);
})
.Configure(app =>
{
@ -305,8 +407,14 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
var client = server.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Get, "");
var response = await client.SendAsync(request);
Assert.Equal(200, (int)response.StatusCode);
Assert.Equal("https://localhost/", response.Headers.Location.ToString());
var logMessages = sink.Writes.ToList();
Assert.Single(logMessages);
var message = logMessages.First();
Assert.Equal(LogLevel.Warning, message.LogLevel);
Assert.Equal("Failed to determine the https port for redirect.", message.State.ToString());
}
}
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.1</TargetFrameworks>
@ -8,4 +8,8 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.HttpsPolicy\Microsoft.AspNetCore.HttpsPolicy.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Testing" Version="$(MicrosoftExtensionsLoggingTestingPackageVersion)" />
</ItemGroup>
</Project>