Skip to content

Commit e436fd9

Browse files
huysentruitwTratcher
authored andcommitted
Add support for Redirect preserving method/body (HTTP 307 and 308) (dotnet#9968)
1 parent 0dfe695 commit e436fd9

File tree

3 files changed

+43
-0
lines changed

3 files changed

+43
-0
lines changed

src/Http/Http.Extensions/ref/Microsoft.AspNetCore.Http.Extensions.netcoreapp3.0.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public static void AppendList<T>(this Microsoft.AspNetCore.Http.IHeaderDictionar
1212
public static partial class ResponseExtensions
1313
{
1414
public static void Clear(this Microsoft.AspNetCore.Http.HttpResponse response) { }
15+
public static void Redirect(this Microsoft.AspNetCore.Http.HttpResponse response, string location, bool permanent, bool preserveMethod) { }
1516
}
1617
public static partial class SendFileResponseExtensions
1718
{

src/Http/Http.Extensions/src/ResponseExtensions.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using Microsoft.AspNetCore.Http.Features;
6+
using Microsoft.Net.Http.Headers;
67

78
namespace Microsoft.AspNetCore.Http
89
{
@@ -22,5 +23,26 @@ public static void Clear(this HttpResponse response)
2223
response.Body.SetLength(0);
2324
}
2425
}
26+
27+
/// <summary>
28+
/// Returns a redirect response (HTTP 301, HTTP 302, HTTP 307 or HTTP 308) to the client.
29+
/// </summary>
30+
/// <param name="response">The <see cref="HttpResponse"/> to redirect.</param>
31+
/// <param name="location">The URL to redirect the client to. This must be properly encoded for use in http headers where only ASCII characters are allowed.</param>
32+
/// <param name="permanent"><c>True</c> if the redirect is permanent (301 or 308), otherwise <c>false</c> (302 or 307).</param>
33+
/// <param name="preserveMethod"><c>True</c> if the redirect needs to reuse the method and body (308 or 307), otherwise <c>false</c> (301 or 302).</param>
34+
public static void Redirect(this HttpResponse response, string location, bool permanent, bool preserveMethod)
35+
{
36+
if (preserveMethod)
37+
{
38+
response.StatusCode = permanent ? StatusCodes.Status308PermanentRedirect : StatusCodes.Status307TemporaryRedirect;
39+
}
40+
else
41+
{
42+
response.StatusCode = permanent ? StatusCodes.Status301MovedPermanently : StatusCodes.Status302Found;
43+
}
44+
45+
response.Headers[HeaderNames.Location] = location;
46+
}
2547
}
2648
}

src/Http/Http.Extensions/test/ResponseExtensionTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33

44
using System;
55
using System.IO;
6+
using System.Linq;
7+
using System.Net;
68
using System.Threading.Tasks;
79
using Microsoft.AspNetCore.Http.Features;
10+
using Microsoft.Net.Http.Headers;
811
using Xunit;
912

1013
namespace Microsoft.AspNetCore.Http.Extensions
@@ -35,6 +38,23 @@ public void Clear_AlreadyStarted_Throws()
3538
Assert.Throws<InvalidOperationException>(() => context.Response.Clear());
3639
}
3740

41+
[Theory]
42+
[InlineData(true, false, 301)]
43+
[InlineData(false, false, 302)]
44+
[InlineData(true, true, 308)]
45+
[InlineData(false, true, 307)]
46+
public void Redirect_SetsResponseCorrectly(bool permanent, bool preserveMethod, int expectedStatusCode)
47+
{
48+
var location = "http://localhost/redirect";
49+
var context = new DefaultHttpContext();
50+
context.Response.StatusCode = StatusCodes.Status200OK;
51+
52+
context.Response.Redirect(location, permanent, preserveMethod);
53+
54+
Assert.Equal(location, context.Response.Headers[HeaderNames.Location].First());
55+
Assert.Equal(expectedStatusCode, context.Response.StatusCode);
56+
}
57+
3858
private class StartedResponseFeature : IHttpResponseFeature
3959
{
4060
public Stream Body { get; set; }

0 commit comments

Comments
 (0)