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");} 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); + } } diff --git a/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpResponseWrapperTests.cs b/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpResponseWrapperTests.cs index a737cccf7..678113f2b 100644 --- a/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpResponseWrapperTests.cs +++ b/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpResponseWrapperTests.cs @@ -1,15 +1,127 @@ 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 { - public class HttpServerUtilityWrapperTests + public class HttpResponseWrapperTests { [Fact] public void Constructor() { - Assert.Throws(() => new HttpServerUtilityWrapper(null!)); - } + 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); + } } } 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!)); } } }