BasicMiddleware 291 B

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. commit 0a876cece7b72b11e4e9bcedd9442ac29effdd22
  2. Author: Chris Ross (ASP.NET) <[email protected]>
  3. Date: Fri Apr 13 15:55:42 2018 -0700
  4. Make https redirect no-op if no port is available #318
  5. diff --git a/samples/HttpsPolicySample/HttpsPolicySample.csproj b/samples/HttpsPolicySample/HttpsPolicySample.csproj
  6. index 3ab7f8c7cb4..fdfa7164784 100644
  7. --- a/samples/HttpsPolicySample/HttpsPolicySample.csproj
  8. +++ b/samples/HttpsPolicySample/HttpsPolicySample.csproj
  9. @@ -1,4 +1,4 @@
  10. -<Project Sdk="Microsoft.NET.Sdk.Web">
  11. +<Project Sdk="Microsoft.NET.Sdk.Web">
  12. <PropertyGroup>
  13. <TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
  14. @@ -8,6 +8,7 @@
  15. <ItemGroup>
  16. <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
  17. <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="$(MicrosoftAspNetCoreServerKestrelHttpsPackageVersion)" />
  18. + <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
  19. </ItemGroup>
  20. <ItemGroup>
  21. diff --git a/samples/HttpsPolicySample/Properties/launchSettings.json b/samples/HttpsPolicySample/Properties/launchSettings.json
  22. index fbffc1f457e..a35390177b0 100644
  23. --- a/samples/HttpsPolicySample/Properties/launchSettings.json
  24. +++ b/samples/HttpsPolicySample/Properties/launchSettings.json
  25. @@ -21,7 +21,7 @@
  26. "environmentVariables": {
  27. "ASPNETCORE_ENVIRONMENT": "Development"
  28. },
  29. - "applicationUrl": "http://localhost:31895/"
  30. + "applicationUrl": "http://localhost:5000/"
  31. }
  32. }
  33. -}
  34. +}
  35. \ No newline at end of file
  36. diff --git a/samples/HttpsPolicySample/Startup.cs b/samples/HttpsPolicySample/Startup.cs
  37. index 1c9f11fcad5..91888a01b42 100644
  38. --- a/samples/HttpsPolicySample/Startup.cs
  39. +++ b/samples/HttpsPolicySample/Startup.cs
  40. @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Hosting;
  41. using Microsoft.AspNetCore.Http;
  42. using Microsoft.AspNetCore.HttpsPolicy;
  43. using Microsoft.Extensions.DependencyInjection;
  44. +using Microsoft.Extensions.Logging;
  45. namespace HttpsSample
  46. {
  47. @@ -62,6 +63,11 @@ namespace HttpsSample
  48. });
  49. })
  50. .UseContentRoot(Directory.GetCurrentDirectory()) // for the cert file
  51. + .ConfigureLogging(factory =>
  52. + {
  53. + factory.SetMinimumLevel(LogLevel.Debug);
  54. + factory.AddConsole();
  55. + })
  56. .UseStartup<Startup>()
  57. .Build();
  58. diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs
  59. index a4a9cc034d9..192845f7dbe 100644
  60. --- a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs
  61. +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs
  62. @@ -7,7 +7,9 @@ using Microsoft.AspNetCore.Hosting.Server.Features;
  63. using Microsoft.AspNetCore.Http;
  64. using Microsoft.AspNetCore.Http.Extensions;
  65. using Microsoft.AspNetCore.Http.Internal;
  66. +using Microsoft.AspNetCore.HttpsPolicy.Internal;
  67. using Microsoft.Extensions.Configuration;
  68. +using Microsoft.Extensions.Logging;
  69. using Microsoft.Extensions.Options;
  70. using Microsoft.Net.Http.Headers;
  71. @@ -16,11 +18,13 @@ namespace Microsoft.AspNetCore.HttpsPolicy
  72. public class HttpsRedirectionMiddleware
  73. {
  74. private readonly RequestDelegate _next;
  75. + private bool _portEvaluated = false;
  76. private int? _httpsPort;
  77. private readonly int _statusCode;
  78. private readonly IServerAddressesFeature _serverAddressesFeature;
  79. private readonly IConfiguration _config;
  80. + private readonly ILogger _logger;
  81. /// <summary>
  82. /// Initializes the HttpsRedirectionMiddleware
  83. @@ -28,7 +32,8 @@ namespace Microsoft.AspNetCore.HttpsPolicy
  84. /// <param name="next"></param>
  85. /// <param name="options"></param>
  86. /// <param name="config"></param>
  87. - public HttpsRedirectionMiddleware(RequestDelegate next, IOptions<HttpsRedirectionOptions> options, IConfiguration config)
  88. + /// <param name="loggerFactory"></param>
  89. + public HttpsRedirectionMiddleware(RequestDelegate next, IOptions<HttpsRedirectionOptions> options, IConfiguration config, ILoggerFactory loggerFactory)
  90. {
  91. _next = next ?? throw new ArgumentNullException(nameof(next));
  92. @@ -40,7 +45,9 @@ namespace Microsoft.AspNetCore.HttpsPolicy
  93. }
  94. var httpsRedirectionOptions = options.Value;
  95. _httpsPort = httpsRedirectionOptions.HttpsPort;
  96. + _portEvaluated = _httpsPort.HasValue;
  97. _statusCode = httpsRedirectionOptions.RedirectStatusCode;
  98. + _logger = loggerFactory.CreateLogger<HttpsRedirectionMiddleware>();
  99. }
  100. /// <summary>
  101. @@ -49,9 +56,11 @@ namespace Microsoft.AspNetCore.HttpsPolicy
  102. /// <param name="next"></param>
  103. /// <param name="options"></param>
  104. /// <param name="config"></param>
  105. + /// <param name="loggerFactory"></param>
  106. /// <param name="serverAddressesFeature">The</param>
  107. - public HttpsRedirectionMiddleware(RequestDelegate next, IOptions<HttpsRedirectionOptions> options, IConfiguration config, IServerAddressesFeature serverAddressesFeature)
  108. - : this(next, options, config)
  109. + public HttpsRedirectionMiddleware(RequestDelegate next, IOptions<HttpsRedirectionOptions> options, IConfiguration config, ILoggerFactory loggerFactory,
  110. + IServerAddressesFeature serverAddressesFeature)
  111. + : this(next, options, config, loggerFactory)
  112. {
  113. _serverAddressesFeature = serverAddressesFeature ?? throw new ArgumentNullException(nameof(serverAddressesFeature));
  114. }
  115. @@ -63,20 +72,15 @@ namespace Microsoft.AspNetCore.HttpsPolicy
  116. /// <returns></returns>
  117. public Task Invoke(HttpContext context)
  118. {
  119. - if (context.Request.IsHttps)
  120. + if (context.Request.IsHttps || !TryGetHttpsPort(out var port))
  121. {
  122. return _next(context);
  123. }
  124. - if (!_httpsPort.HasValue)
  125. - {
  126. - CheckForHttpsPorts();
  127. - }
  128. -
  129. var host = context.Request.Host;
  130. - if (_httpsPort != 443)
  131. + if (port != 443)
  132. {
  133. - host = new HostString(host.Host, _httpsPort.Value);
  134. + host = new HostString(host.Host, port);
  135. }
  136. else
  137. {
  138. @@ -94,28 +98,41 @@ namespace Microsoft.AspNetCore.HttpsPolicy
  139. context.Response.StatusCode = _statusCode;
  140. context.Response.Headers[HeaderNames.Location] = redirectUrl;
  141. + _logger.RedirectingToHttps(redirectUrl);
  142. +
  143. return Task.CompletedTask;
  144. }
  145. - private void CheckForHttpsPorts()
  146. + private bool TryGetHttpsPort(out int port)
  147. {
  148. // The IServerAddressesFeature will not be ready until the middleware is Invoked,
  149. // Order for finding the HTTPS port:
  150. // 1. Set in the HttpsRedirectionOptions
  151. // 2. HTTPS_PORT environment variable
  152. // 3. IServerAddressesFeature
  153. - // 4. 443 (or not set)
  154. + // 4. Fail if not set
  155. +
  156. + port = -1;
  157. +
  158. + if (_portEvaluated)
  159. + {
  160. + port = _httpsPort ?? port;
  161. + return _httpsPort.HasValue;
  162. + }
  163. + _portEvaluated = true;
  164. _httpsPort = _config.GetValue<int?>("HTTPS_PORT");
  165. if (_httpsPort.HasValue)
  166. {
  167. - return;
  168. + port = _httpsPort.Value;
  169. + _logger.PortLoadedFromConfig(port);
  170. + return true;
  171. }
  172. if (_serverAddressesFeature == null)
  173. {
  174. - _httpsPort = 443;
  175. - return;
  176. + _logger.FailedToDeterminePort();
  177. + return false;
  178. }
  179. int? httpsPort = null;
  180. @@ -127,8 +144,8 @@ namespace Microsoft.AspNetCore.HttpsPolicy
  181. // If we find multiple different https ports specified, throw
  182. if (httpsPort.HasValue && httpsPort != bindingAddress.Port)
  183. {
  184. - throw new ArgumentException("Cannot determine the https port from IServerAddressesFeature, multiple values were found. " +
  185. - "Please set the desired port explicitly on HttpsRedirectionOptions.HttpsPort.");
  186. + _logger.FailedMultiplePorts();
  187. + return false;
  188. }
  189. else
  190. {
  191. @@ -136,7 +153,17 @@ namespace Microsoft.AspNetCore.HttpsPolicy
  192. }
  193. }
  194. }
  195. - _httpsPort = httpsPort ?? 443;
  196. +
  197. + if (httpsPort.HasValue)
  198. + {
  199. + _httpsPort = httpsPort;
  200. + port = _httpsPort.Value;
  201. + _logger.PortFromServer(port);
  202. + return true;
  203. + }
  204. +
  205. + _logger.FailedToDeterminePort();
  206. + return false;
  207. }
  208. }
  209. }
  210. diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/internal/HttpsLoggingExtensions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/internal/HttpsLoggingExtensions.cs
  211. new file mode 100644
  212. index 00000000000..55e65dcbddb
  213. --- /dev/null
  214. +++ b/src/Microsoft.AspNetCore.HttpsPolicy/internal/HttpsLoggingExtensions.cs
  215. @@ -0,0 +1,53 @@
  216. +// Copyright (c) .NET Foundation. All rights reserved.
  217. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  218. +
  219. +using System;
  220. +using Microsoft.Extensions.Logging;
  221. +
  222. +namespace Microsoft.AspNetCore.HttpsPolicy.Internal
  223. +{
  224. + internal static class HttpsLoggingExtensions
  225. + {
  226. + private static readonly Action<ILogger, string, Exception> _redirectingToHttps;
  227. + private static readonly Action<ILogger, int, Exception> _portLoadedFromConfig;
  228. + private static readonly Action<ILogger, Exception> _failedToDeterminePort;
  229. + private static readonly Action<ILogger, Exception> _failedMultiplePorts;
  230. + private static readonly Action<ILogger, int, Exception> _portFromServer;
  231. +
  232. + static HttpsLoggingExtensions()
  233. + {
  234. + _redirectingToHttps = LoggerMessage.Define<string>(LogLevel.Debug, 1, "Redirecting to '{redirect}'.");
  235. + _portLoadedFromConfig = LoggerMessage.Define<int>(LogLevel.Debug, 2, "Https port '{port}' loaded from configuration.");
  236. + _failedToDeterminePort = LoggerMessage.Define(LogLevel.Warning, 3, "Failed to determine the https port for redirect.");
  237. + _failedMultiplePorts = LoggerMessage.Define(LogLevel.Warning, 4,
  238. + "Cannot determine the https port from IServerAddressesFeature, multiple values were found. " +
  239. + "Please set the desired port explicitly on HttpsRedirectionOptions.HttpsPort.");
  240. + _portFromServer = LoggerMessage.Define<int>(LogLevel.Debug, 5, "Https port '{httpsPort}' discovered from server endpoints.");
  241. + }
  242. +
  243. + public static void RedirectingToHttps(this ILogger logger, string redirect)
  244. + {
  245. + _redirectingToHttps(logger, redirect, null);
  246. + }
  247. +
  248. + public static void PortLoadedFromConfig(this ILogger logger, int port)
  249. + {
  250. + _portLoadedFromConfig(logger, port, null);
  251. + }
  252. +
  253. + public static void FailedToDeterminePort(this ILogger logger)
  254. + {
  255. + _failedToDeterminePort(logger, null);
  256. + }
  257. +
  258. + public static void FailedMultiplePorts(this ILogger logger)
  259. + {
  260. + _failedMultiplePorts(logger, null);
  261. + }
  262. +
  263. + public static void PortFromServer(this ILogger logger, int port)
  264. + {
  265. + _portFromServer(logger, port, null);
  266. + }
  267. + }
  268. +}
  269. diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs
  270. index aa874fb8cd9..2b9b3d3b492 100644
  271. --- a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs
  272. +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs
  273. @@ -21,12 +21,12 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  274. public class HttpsPolicyTests
  275. {
  276. [Theory]
  277. - [InlineData(302, null, 2592000, false, false, "max-age=2592000", "https://localhost/")]
  278. + [InlineData(302, 443, 2592000, false, false, "max-age=2592000", "https://localhost/")]
  279. [InlineData(301, 5050, 2592000, false, false, "max-age=2592000", "https://localhost:5050/")]
  280. [InlineData(301, 443, 2592000, false, false, "max-age=2592000", "https://localhost/")]
  281. [InlineData(301, 443, 2592000, true, false, "max-age=2592000; includeSubDomains", "https://localhost/")]
  282. [InlineData(301, 443, 2592000, false, true, "max-age=2592000; preload", "https://localhost/")]
  283. - [InlineData(301, null, 2592000, true, true, "max-age=2592000; includeSubDomains; preload", "https://localhost/")]
  284. + [InlineData(301, 443, 2592000, true, true, "max-age=2592000; includeSubDomains; preload", "https://localhost/")]
  285. [InlineData(302, 5050, 2592000, true, true, "max-age=2592000; includeSubDomains; preload", "https://localhost:5050/")]
  286. public async Task SetsBothHstsAndHttpsRedirection_RedirectOnFirstRequest_HstsOnSecondRequest(int statusCode, int? tlsPort, int maxAge, bool includeSubDomains, bool preload, string expectedHstsHeader, string expectedUrl)
  287. {
  288. @@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  289. client = server.CreateClient();
  290. client.BaseAddress = new Uri(response.Headers.Location.ToString());
  291. - request = new HttpRequestMessage(HttpMethod.Get, "");
  292. + request = new HttpRequestMessage(HttpMethod.Get, expectedUrl);
  293. response = await client.SendAsync(request);
  294. Assert.Equal(expectedHstsHeader, response.Headers.GetValues(HeaderNames.StrictTransportSecurity).FirstOrDefault());
  295. diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs
  296. index b55c1952729..ef0b0c36859 100644
  297. --- a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs
  298. +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs
  299. @@ -2,6 +2,7 @@
  300. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  301. using System;
  302. +using System.Linq;
  303. using System.Net;
  304. using System.Net.Http;
  305. using System.Threading.Tasks;
  306. @@ -12,6 +13,8 @@ using Microsoft.AspNetCore.Http;
  307. using Microsoft.AspNetCore.Http.Features;
  308. using Microsoft.AspNetCore.TestHost;
  309. using Microsoft.Extensions.DependencyInjection;
  310. +using Microsoft.Extensions.Logging;
  311. +using Microsoft.Extensions.Logging.Testing;
  312. using Xunit;
  313. namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  314. @@ -19,9 +22,17 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  315. public class HttpsRedirectionMiddlewareTests
  316. {
  317. [Fact]
  318. - public async Task SetOptions_DefaultsSetCorrectly()
  319. + public async Task SetOptions_NotEnabledByDefault()
  320. {
  321. + var sink = new TestSink(
  322. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
  323. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
  324. + var loggerFactory = new TestLoggerFactory(sink, enabled: true);
  325. var builder = new WebHostBuilder()
  326. + .ConfigureServices(services =>
  327. + {
  328. + services.AddSingleton<ILoggerFactory>(loggerFactory);
  329. + })
  330. .Configure(app =>
  331. {
  332. app.UseHttpsRedirection();
  333. @@ -38,23 +49,32 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  334. var response = await client.SendAsync(request);
  335. - Assert.Equal(HttpStatusCode.RedirectKeepVerb, response.StatusCode);
  336. - Assert.Equal("https://localhost/", response.Headers.Location.ToString());
  337. + Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  338. +
  339. + var logMessages = sink.Writes.ToList();
  340. +
  341. + Assert.Single(logMessages);
  342. + var message = logMessages.Single();
  343. + Assert.Equal(LogLevel.Warning, message.LogLevel);
  344. + Assert.Equal("Failed to determine the https port for redirect.", message.State.ToString());
  345. }
  346. [Theory]
  347. - [InlineData(301, null, "https://localhost/")]
  348. - [InlineData(302, null, "https://localhost/")]
  349. - [InlineData(307, null, "https://localhost/")]
  350. - [InlineData(308, null, "https://localhost/")]
  351. + [InlineData(302, 5001, "https://localhost:5001/")]
  352. + [InlineData(307, 1, "https://localhost:1/")]
  353. + [InlineData(308, 3449, "https://localhost:3449/")]
  354. [InlineData(301, 5050, "https://localhost:5050/")]
  355. [InlineData(301, 443, "https://localhost/")]
  356. public async Task SetOptions_SetStatusCodeHttpsPort(int statusCode, int? httpsPort, string expected)
  357. {
  358. -
  359. + var sink = new TestSink(
  360. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
  361. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
  362. + var loggerFactory = new TestLoggerFactory(sink, enabled: true);
  363. var builder = new WebHostBuilder()
  364. .ConfigureServices(services =>
  365. {
  366. + services.AddSingleton<ILoggerFactory>(loggerFactory);
  367. services.Configure<HttpsRedirectionOptions>(options =>
  368. {
  369. options.RedirectStatusCode = statusCode;
  370. @@ -79,20 +99,31 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  371. Assert.Equal(statusCode, (int)response.StatusCode);
  372. Assert.Equal(expected, response.Headers.Location.ToString());
  373. +
  374. + var logMessages = sink.Writes.ToList();
  375. +
  376. + Assert.Single(logMessages);
  377. + var message = logMessages.Single();
  378. + Assert.Equal(LogLevel.Debug, message.LogLevel);
  379. + Assert.Equal($"Redirecting to '{expected}'.", message.State.ToString());
  380. }
  381. [Theory]
  382. - [InlineData(301, null, "https://localhost/")]
  383. - [InlineData(302, null, "https://localhost/")]
  384. - [InlineData(307, null, "https://localhost/")]
  385. - [InlineData(308, null, "https://localhost/")]
  386. + [InlineData(302, 5001, "https://localhost:5001/")]
  387. + [InlineData(307, 1, "https://localhost:1/")]
  388. + [InlineData(308, 3449, "https://localhost:3449/")]
  389. [InlineData(301, 5050, "https://localhost:5050/")]
  390. [InlineData(301, 443, "https://localhost/")]
  391. public async Task SetOptionsThroughHelperMethod_SetStatusCodeAndHttpsPort(int statusCode, int? httpsPort, string expectedUrl)
  392. {
  393. + var sink = new TestSink(
  394. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
  395. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
  396. + var loggerFactory = new TestLoggerFactory(sink, enabled: true);
  397. var builder = new WebHostBuilder()
  398. .ConfigureServices(services =>
  399. {
  400. + services.AddSingleton<ILoggerFactory>(loggerFactory);
  401. services.AddHttpsRedirection(options =>
  402. {
  403. options.RedirectStatusCode = statusCode;
  404. @@ -117,20 +148,26 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  405. Assert.Equal(statusCode, (int)response.StatusCode);
  406. Assert.Equal(expectedUrl, response.Headers.Location.ToString());
  407. +
  408. + var logMessages = sink.Writes.ToList();
  409. +
  410. + Assert.Single(logMessages);
  411. + var message = logMessages.Single();
  412. + Assert.Equal(LogLevel.Debug, message.LogLevel);
  413. + Assert.Equal($"Redirecting to '{expectedUrl}'.", message.State.ToString());
  414. }
  415. [Theory]
  416. - [InlineData(null, null, null, "https://localhost/")]
  417. [InlineData(null, null, "https://localhost:4444/", "https://localhost:4444/")]
  418. [InlineData(null, null, "https://localhost:443/", "https://localhost/")]
  419. - [InlineData(null, null, "http://localhost:5044/", "https://localhost/")]
  420. [InlineData(null, null, "https://localhost/", "https://localhost/")]
  421. [InlineData(null, "5000", "https://localhost:4444/", "https://localhost:5000/")]
  422. [InlineData(null, "443", "https://localhost:4444/", "https://localhost/")]
  423. [InlineData(443, "5000", "https://localhost:4444/", "https://localhost/")]
  424. [InlineData(4000, "5000", "https://localhost:4444/", "https://localhost:4000/")]
  425. [InlineData(5000, null, "https://localhost:4444/", "https://localhost:5000/")]
  426. - public async Task SetHttpsPortEnvironmentVariableAndServerFeature_ReturnsCorrectStatusCodeOnResponse(int? optionsHttpsPort, string configHttpsPort, string serverAddressFeatureUrl, string expectedUrl)
  427. + public async Task SetHttpsPortEnvironmentVariableAndServerFeature_ReturnsCorrectStatusCodeOnResponse(
  428. + int? optionsHttpsPort, string configHttpsPort, string serverAddressFeatureUrl, string expectedUrl)
  429. {
  430. var builder = new WebHostBuilder()
  431. .ConfigureServices(services =>
  432. @@ -172,7 +209,15 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  433. [Fact]
  434. public async Task SetServerAddressesFeature_SingleHttpsAddress_Success()
  435. {
  436. + var sink = new TestSink(
  437. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
  438. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
  439. + var loggerFactory = new TestLoggerFactory(sink, enabled: true);
  440. var builder = new WebHostBuilder()
  441. + .ConfigureServices(services =>
  442. + {
  443. + services.AddSingleton<ILoggerFactory>(loggerFactory);
  444. + })
  445. .Configure(app =>
  446. {
  447. app.UseHttpsRedirection();
  448. @@ -194,12 +239,31 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  449. var response = await client.SendAsync(request);
  450. Assert.Equal("https://localhost:5050/", response.Headers.Location.ToString());
  451. +
  452. + var logMessages = sink.Writes.ToList();
  453. +
  454. + Assert.Equal(2, logMessages.Count);
  455. + var message = logMessages.First();
  456. + Assert.Equal(LogLevel.Debug, message.LogLevel);
  457. + Assert.Equal("Https port '5050' discovered from server endpoints.", message.State.ToString());
  458. +
  459. + message = logMessages.Skip(1).First();
  460. + Assert.Equal(LogLevel.Debug, message.LogLevel);
  461. + Assert.Equal("Redirecting to 'https://localhost:5050/'.", message.State.ToString());
  462. }
  463. [Fact]
  464. - public async Task SetServerAddressesFeature_MultipleHttpsAddresses_ThrowInMiddleware()
  465. + public async Task SetServerAddressesFeature_MultipleHttpsAddresses_LogsAndFailsToRedirect()
  466. {
  467. + var sink = new TestSink(
  468. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
  469. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
  470. + var loggerFactory = new TestLoggerFactory(sink, enabled: true);
  471. var builder = new WebHostBuilder()
  472. + .ConfigureServices(services =>
  473. + {
  474. + services.AddSingleton<ILoggerFactory>(loggerFactory);
  475. + })
  476. .Configure(app =>
  477. {
  478. app.UseHttpsRedirection();
  479. @@ -220,13 +284,30 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  480. var request = new HttpRequestMessage(HttpMethod.Get, "");
  481. - await Assert.ThrowsAsync<ArgumentException>(async () => await client.SendAsync(request));
  482. + var response = await client.SendAsync(request);
  483. + Assert.Equal(200, (int)response.StatusCode);
  484. +
  485. + var logMessages = sink.Writes.ToList();
  486. +
  487. + Assert.Single(logMessages);
  488. + var message = logMessages.First();
  489. + Assert.Equal(LogLevel.Warning, message.LogLevel);
  490. + Assert.Equal("Cannot determine the https port from IServerAddressesFeature, multiple values were found. " +
  491. + "Please set the desired port explicitly on HttpsRedirectionOptions.HttpsPort.", message.State.ToString());
  492. }
  493. [Fact]
  494. public async Task SetServerAddressesFeature_MultipleHttpsAddressesWithSamePort_Success()
  495. {
  496. + var sink = new TestSink(
  497. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
  498. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
  499. + var loggerFactory = new TestLoggerFactory(sink, enabled: true);
  500. var builder = new WebHostBuilder()
  501. + .ConfigureServices(services =>
  502. + {
  503. + services.AddSingleton<ILoggerFactory>(loggerFactory);
  504. + })
  505. .Configure(app =>
  506. {
  507. app.UseHttpsRedirection();
  508. @@ -241,7 +322,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  509. var server = new TestServer(builder, featureCollection);
  510. server.Features.Get<IServerAddressesFeature>().Addresses.Add("https://localhost:5050");
  511. - server.Features.Get<IServerAddressesFeature>().Addresses.Add("https://localhost:5050");
  512. + server.Features.Get<IServerAddressesFeature>().Addresses.Add("https://example.com:5050");
  513. var client = server.CreateClient();
  514. @@ -250,17 +331,30 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  515. var response = await client.SendAsync(request);
  516. Assert.Equal("https://localhost:5050/", response.Headers.Location.ToString());
  517. +
  518. + var logMessages = sink.Writes.ToList();
  519. +
  520. + Assert.Equal(2, logMessages.Count);
  521. + var message = logMessages.First();
  522. + Assert.Equal(LogLevel.Debug, message.LogLevel);
  523. + Assert.Equal("Https port '5050' discovered from server endpoints.", message.State.ToString());
  524. +
  525. + message = logMessages.Skip(1).First();
  526. + Assert.Equal(LogLevel.Debug, message.LogLevel);
  527. + Assert.Equal("Redirecting to 'https://localhost:5050/'.", message.State.ToString());
  528. }
  529. [Fact]
  530. - public async Task NoServerAddressFeature_DoesNotThrow_DefaultsTo443()
  531. + public async Task NoServerAddressFeature_DoesNotThrow_DoesNotRedirect()
  532. {
  533. + var sink = new TestSink(
  534. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
  535. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
  536. + var loggerFactory = new TestLoggerFactory(sink, enabled: true);
  537. var builder = new WebHostBuilder()
  538. .ConfigureServices(services =>
  539. {
  540. - services.AddHttpsRedirection(options =>
  541. - {
  542. - });
  543. + services.AddSingleton<ILoggerFactory>(loggerFactory);
  544. })
  545. .Configure(app =>
  546. {
  547. @@ -275,19 +369,27 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  548. var client = server.CreateClient();
  549. var request = new HttpRequestMessage(HttpMethod.Get, "");
  550. var response = await client.SendAsync(request);
  551. + Assert.Equal(200, (int)response.StatusCode);
  552. +
  553. + var logMessages = sink.Writes.ToList();
  554. - Assert.Equal("https://localhost/", response.Headers.Location.ToString());
  555. + Assert.Single(logMessages);
  556. + var message = logMessages.First();
  557. + Assert.Equal(LogLevel.Warning, message.LogLevel);
  558. + Assert.Equal("Failed to determine the https port for redirect.", message.State.ToString());
  559. }
  560. [Fact]
  561. public async Task SetNullAddressFeature_DoesNotThrow()
  562. {
  563. + var sink = new TestSink(
  564. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>,
  565. + TestSink.EnableWithTypeName<HttpsRedirectionMiddleware>);
  566. + var loggerFactory = new TestLoggerFactory(sink, enabled: true);
  567. var builder = new WebHostBuilder()
  568. .ConfigureServices(services =>
  569. {
  570. - services.AddHttpsRedirection(options =>
  571. - {
  572. - });
  573. + services.AddSingleton<ILoggerFactory>(loggerFactory);
  574. })
  575. .Configure(app =>
  576. {
  577. @@ -305,8 +407,14 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests
  578. var client = server.CreateClient();
  579. var request = new HttpRequestMessage(HttpMethod.Get, "");
  580. var response = await client.SendAsync(request);
  581. + Assert.Equal(200, (int)response.StatusCode);
  582. +
  583. + var logMessages = sink.Writes.ToList();
  584. - Assert.Equal("https://localhost/", response.Headers.Location.ToString());
  585. + Assert.Single(logMessages);
  586. + var message = logMessages.First();
  587. + Assert.Equal(LogLevel.Warning, message.LogLevel);
  588. + Assert.Equal("Failed to determine the https port for redirect.", message.State.ToString());
  589. }
  590. }
  591. }
  592. diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj
  593. index af610a24a8e..e51e3a6640d 100644
  594. --- a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj
  595. +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj
  596. @@ -1,4 +1,4 @@
  597. -<Project Sdk="Microsoft.NET.Sdk">
  598. +<Project Sdk="Microsoft.NET.Sdk">
  599. <PropertyGroup>
  600. <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
  601. @@ -8,4 +8,8 @@
  602. <ItemGroup>
  603. <ProjectReference Include="..\..\src\Microsoft.AspNetCore.HttpsPolicy\Microsoft.AspNetCore.HttpsPolicy.csproj" />
  604. </ItemGroup>
  605. +
  606. + <ItemGroup>
  607. + <PackageReference Include="Microsoft.Extensions.Logging.Testing" Version="$(MicrosoftExtensionsLoggingTestingPackageVersion)" />
  608. + </ItemGroup>
  609. </Project>