From 8c9c445f0f82ff7bb2635b70b981042043ddef0c Mon Sep 17 00:00:00 2001 From: AvremelM <1865736+AvremelM@users.noreply.github.com> Date: Wed, 24 Jan 2024 12:58:43 -0500 Subject: [PATCH 1/4] : : Add Redirect/RedirectPermanent to HttpResponseBase --- .../HttpResponseBase.cs | 13 +++++++++++++ .../HttpResponseWrapper.cs | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/Microsoft.AspNetCore.SystemWebAdapters/HttpResponseBase.cs b/src/Microsoft.AspNetCore.SystemWebAdapters/HttpResponseBase.cs index c0e56891d..9df8df8c3 100644 --- a/src/Microsoft.AspNetCore.SystemWebAdapters/HttpResponseBase.cs +++ b/src/Microsoft.AspNetCore.SystemWebAdapters/HttpResponseBase.cs @@ -129,6 +129,19 @@ public virtual Stream Filter public virtual void TransmitFile(string filename, long offset, long length) => throw new NotImplementedException(); + + [SuppressMessage("Design", "CA1054:URI parameters should not be strings", Justification = Constants.ApiFromAspNet)] + public virtual void Redirect(string url) => throw new NotImplementedException(); + + [SuppressMessage("Design", "CA1054:URI parameters should not be strings", Justification = Constants.ApiFromAspNet)] + public virtual void Redirect(string url, bool endResponse) => throw new NotImplementedException(); + + [SuppressMessage("Design", "CA1054:URI parameters should not be strings", Justification = Constants.ApiFromAspNet)] + public virtual void RedirectPermanent(string url) => throw new NotImplementedException(); + + [SuppressMessage("Design", "CA1054:URI parameters should not be strings", Justification = Constants.ApiFromAspNet)] + public virtual void RedirectPermanent(string url, bool endResponse) => throw new NotImplementedException(); + [return: NotNullIfNotNull(nameof(response))] public static implicit operator HttpResponseBase?(HttpResponseCore? response) => response?.HttpContext.AsSystemWebBase().Response; } diff --git a/src/Microsoft.AspNetCore.SystemWebAdapters/HttpResponseWrapper.cs b/src/Microsoft.AspNetCore.SystemWebAdapters/HttpResponseWrapper.cs index 19603596c..ff2569be7 100644 --- a/src/Microsoft.AspNetCore.SystemWebAdapters/HttpResponseWrapper.cs +++ b/src/Microsoft.AspNetCore.SystemWebAdapters/HttpResponseWrapper.cs @@ -129,5 +129,19 @@ public override Stream Filter public override void TransmitFile(string filename, long offset, long length) => _response.TransmitFile(filename, offset, length); public override void WriteFile(string filename) => _response.WriteFile(filename); + + + [SuppressMessage("Design", "CA1054:URI parameters should not be strings", Justification = Constants.ApiFromAspNet)] + public override void Redirect(string url) => _response.Redirect(url); + + [SuppressMessage("Design", "CA1054:URI parameters should not be strings", Justification = Constants.ApiFromAspNet)] + public override void Redirect(string url, bool endResponse) => _response.Redirect(url, endResponse); + + [SuppressMessage("Design", "CA1054:URI parameters should not be strings", Justification = Constants.ApiFromAspNet)] + public override void RedirectPermanent(string url) => _response.RedirectPermanent(url); + + [SuppressMessage("Design", "CA1054:URI parameters should not be strings", Justification = Constants.ApiFromAspNet)] + public override void RedirectPermanent(string url, bool endResponse) => _response.RedirectPermanent(url, endResponse); + } } From 48c2cd677caa849bd5516ff60b61e8125f7b2ec4 Mon Sep 17 00:00:00 2001 From: AvremelM <1865736+AvremelM@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:31:22 -0500 Subject: [PATCH 2/4] : Regenerate Ref.Standard.cs --- .../Generated/Ref.Standard.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Microsoft.AspNetCore.SystemWebAdapters/Generated/Ref.Standard.cs b/src/Microsoft.AspNetCore.SystemWebAdapters/Generated/Ref.Standard.cs index 84ec1ff5a..dde05feed 100644 --- a/src/Microsoft.AspNetCore.SystemWebAdapters/Generated/Ref.Standard.cs +++ b/src/Microsoft.AspNetCore.SystemWebAdapters/Generated/Ref.Standard.cs @@ -529,6 +529,10 @@ public partial class HttpResponseBase public virtual void ClearContent() { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} public virtual void ClearHeaders() { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} public virtual void End() { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} + public virtual void Redirect(string url) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} + public virtual void Redirect(string url, bool endResponse) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} + public virtual void RedirectPermanent(string url) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} + public virtual void RedirectPermanent(string url, bool endResponse) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} public virtual void SetCookie(System.Web.HttpCookie cookie) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} public virtual void TransmitFile(string filename) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} public virtual void TransmitFile(string filename, long offset, long length) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} @@ -566,6 +570,10 @@ public partial class HttpResponseWrapper : System.Web.HttpResponseBase public override void ClearContent() { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} public override void ClearHeaders() { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} public override void End() { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} + public override void Redirect(string url) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} + public override void Redirect(string url, bool endResponse) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} + public override void RedirectPermanent(string url) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} + public override void RedirectPermanent(string url, bool endResponse) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} public override void SetCookie(System.Web.HttpCookie cookie) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} public override void TransmitFile(string filename) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} public override void TransmitFile(string filename, long offset, long length) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} From e77996e45a46aa26a2bb3f60db2c19795bc6f7d9 Mon Sep 17 00:00:00 2001 From: AvremelM <1865736+AvremelM@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:46:46 -0500 Subject: [PATCH 3/4] : Unswap HttpResponseWrapperTests and HttpServerUtilityWrapperTests --- .../HttpResponseWrapperTests.cs | 6 +++--- .../HttpServerUtilityWrapperTests.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpResponseWrapperTests.cs b/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpResponseWrapperTests.cs index a737cccf7..8996f1222 100644 --- a/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpResponseWrapperTests.cs +++ b/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpResponseWrapperTests.cs @@ -4,12 +4,12 @@ namespace Microsoft.AspNetCore.SystemWebAdapters.Tests { - public class HttpServerUtilityWrapperTests + public class HttpResponseWrapperTests { [Fact] public void Constructor() { - Assert.Throws(() => new HttpServerUtilityWrapper(null!)); - } + Assert.Throws(() => new HttpResponseWrapper(null!)); + } } } diff --git a/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpServerUtilityWrapperTests.cs b/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpServerUtilityWrapperTests.cs index 9b588b8ed..a737cccf7 100644 --- a/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpServerUtilityWrapperTests.cs +++ b/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpServerUtilityWrapperTests.cs @@ -4,12 +4,12 @@ namespace Microsoft.AspNetCore.SystemWebAdapters.Tests { - public class HttpResponseWrapperTests + public class HttpServerUtilityWrapperTests { [Fact] public void Constructor() { - Assert.Throws(() => new HttpResponseWrapper(null!)); + Assert.Throws(() => new HttpServerUtilityWrapper(null!)); } } } From 5f9a2e33c23753c3f2d40f3f077719bc351e01af Mon Sep 17 00:00:00 2001 From: AvremelM <1865736+AvremelM@users.noreply.github.com> Date: Wed, 24 Jan 2024 17:37:41 -0500 Subject: [PATCH 4/4] : Add HttpResponseWrapperTests Copied and adapted from HttpResponseTests to test HttpResponseBase/HttpResponseWrapper --- .../HttpResponseWrapperTests.cs | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpResponseWrapperTests.cs b/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpResponseWrapperTests.cs index 8996f1222..678113f2b 100644 --- a/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpResponseWrapperTests.cs +++ b/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpResponseWrapperTests.cs @@ -1,5 +1,12 @@ using System; using System.Web; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.SystemWebAdapters.Features; +using Microsoft.AspNetCore.SystemWebAdapters.Internal; +using Microsoft.Extensions.Options; +using Microsoft.Net.Http.Headers; +using Moq; using Xunit; namespace Microsoft.AspNetCore.SystemWebAdapters.Tests @@ -11,5 +18,110 @@ public void Constructor() { Assert.Throws(() => new HttpResponseWrapper(null!)); } + + [InlineData("/", "~", "/", true, null)] + [InlineData("/", "~", "/", true, false)] + [InlineData("/", "~", "/", true, true)] + [InlineData("/", "~", "/", false, null)] + [InlineData("/", "~", "/", false, false)] + [InlineData("/", "~", "/", false, true)] + + [InlineData("/", "~/dir", "/dir", true, null)] + [InlineData("/", "~/dir", "/dir", true, false)] + [InlineData("/", "~/dir", "/dir", true, true)] + [InlineData("/", "~/dir", "/dir", false, null)] + [InlineData("/", "~/dir", "/dir", false, false)] + [InlineData("/", "~/dir", "/dir", false, true)] + + [InlineData("/", "/dir", "/dir", true, null)] + [InlineData("/", "/dir", "/dir", true, false)] + [InlineData("/", "/dir", "/dir", true, true)] + [InlineData("/", "/dir", "/dir", false, null)] + [InlineData("/", "/dir", "/dir", false, false)] + [InlineData("/", "/dir", "/dir", false, true)] + + [InlineData("/dir1/", "/dir2", "/dir2", true, null)] + [InlineData("/dir1/", "/dir2", "/dir2", true, false)] + [InlineData("/dir1/", "/dir2", "/dir2", true, true)] + [InlineData("/dir1/", "/dir2", "/dir2", false, null)] + [InlineData("/dir1/", "/dir2", "/dir2", false, false)] + [InlineData("/dir1/", "/dir2", "/dir2", false, true)] + + [InlineData("/dir1/", "~/dir2", "/dir1/dir2", true, null)] + [InlineData("/dir1/", "~/dir2", "/dir1/dir2", true, false)] + [InlineData("/dir1/", "~/dir2", "/dir1/dir2", true, true)] + [InlineData("/dir1/", "~/dir2", "/dir1/dir2", false, null)] + [InlineData("/dir1/", "~/dir2", "/dir1/dir2", false, false)] + [InlineData("/dir1/", "~/dir2", "/dir1/dir2", false, true)] + + [InlineData("/dir1/", "", "/", true, null)] + [InlineData("/dir1/", "", "/", true, false)] + [InlineData("/dir1/", "", "/", true, true)] + [InlineData("/dir1/", "", "/", false, null)] + [InlineData("/dir1/", "", "/", false, false)] + [InlineData("/dir1/", "", "/", false, true)] + + [Theory] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1054:URI-like parameters should not be strings", Justification = "Testing")] + public void Redirect(string vdir, string url, string resolved, bool permanent, bool? endResponse) + { + // Arrange + var isEndCalled = endResponse ?? true; + + var options = new SystemWebAdaptersOptions + { + AppDomainAppVirtualPath = vdir, + }; + + var services = new Mock(); + services.Setup(s => s.GetService(typeof(IOptions))).Returns(Options.Create(options)); + + var endFeature = new Mock(); + endFeature.SetupAllProperties(); + + var context = new DefaultHttpContext(); + context.Features.Set(endFeature.Object); + context.Features.Set(new Mock().Object); + context.RequestServices = services.Object; + + + // Assemble: The HttpResponse and HttpResponseWrapper + HttpResponse response = new HttpResponse(context.Response); + HttpResponseBase responseBase = new HttpResponseWrapper(response); + + // Act: On the HttpResponseBase + if (endResponse.HasValue) + { + if (permanent) + { + responseBase.RedirectPermanent(url, endResponse.Value); + } + else + { + responseBase.Redirect(url, endResponse.Value); + } + } + else + { + if (permanent) + { + responseBase.RedirectPermanent(url); + } + else + { + responseBase.Redirect(url); + } + } + + // Assert: On the inner HttpResponse + Assert.Equal(resolved, response.RedirectLocation); + Assert.Null(context.Features.GetRequired().ReasonPhrase); + Assert.Equal(2, context.Response.Headers.Count); + Assert.Equal(resolved, context.Response.Headers.Location); + Assert.Equal("text/html", context.Response.Headers.ContentType); + Assert.Equal(permanent ? 301 : 302, context.Response.StatusCode); + + endFeature.Verify(b => b.EndAsync(), isEndCalled ? Times.Once : Times.Never); + } } }