Skip to content

Commit 8fd758f

Browse files
Add RedirectHttpResult.IsLocalUrl() (#57363)
Add `IsLocalUrl()` method to `RedirectHttpResult`, which is just a wrapper around `SharedUrlHelper.IsLocalUrl()`. Resolves #56770.
1 parent bc0ed99 commit 8fd758f

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-0
lines changed

src/Http/Http.Results/src/PublicAPI.Unshipped.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Microsoft.AspNetCore.Http.HttpResults.InternalServerError<TValue>
66
Microsoft.AspNetCore.Http.HttpResults.InternalServerError<TValue>.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task!
77
Microsoft.AspNetCore.Http.HttpResults.InternalServerError<TValue>.StatusCode.get -> int
88
Microsoft.AspNetCore.Http.HttpResults.InternalServerError<TValue>.Value.get -> TValue?
9+
static Microsoft.AspNetCore.Http.HttpResults.RedirectHttpResult.IsLocalUrl(string? url) -> bool
910
static Microsoft.AspNetCore.Http.Results.InternalServerError() -> Microsoft.AspNetCore.Http.IResult!
1011
static Microsoft.AspNetCore.Http.Results.InternalServerError<TValue>(TValue? error) -> Microsoft.AspNetCore.Http.IResult!
1112
static Microsoft.AspNetCore.Http.Results.Problem(string? detail = null, string? instance = null, int? statusCode = null, string? title = null, string? type = null, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string!, object?>>? extensions = null) -> Microsoft.AspNetCore.Http.IResult!

src/Http/Http.Results/src/RedirectHttpResult.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,18 @@ public Task ExecuteAsync(HttpContext httpContext)
121121
return Task.CompletedTask;
122122
}
123123

124+
/// <summary>
125+
/// Returns a value that indicates whether the URL is local. A URL is considered
126+
/// local if it does not have a host / authority part and it has an absolute path.
127+
/// URLs using virtual paths (<c>'~/'</c>) are also local.
128+
/// </summary>
129+
/// <param name="url">The URL.</param>
130+
/// <returns>
131+
/// <see langword="true"/> if the URL is local; otherwise, <see langword="false"/>.
132+
/// </returns>
133+
public static bool IsLocalUrl([NotNullWhen(true)][StringSyntax(StringSyntaxAttribute.Uri)] string? url)
134+
=> SharedUrlHelper.IsLocalUrl(url);
135+
124136
private static partial class Log
125137
{
126138
[LoggerMessage(1, LogLevel.Information,

src/Http/Http.Results/test/RedirectResultTests.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,56 @@ public void ExecuteAsync_ThrowsArgumentNullException_WhenHttpContextIsNull()
3333
Assert.ThrowsAsync<ArgumentNullException>("httpContext", () => result.ExecuteAsync(httpContext));
3434
}
3535

36+
[Theory]
37+
[InlineData("/")]
38+
[InlineData("/test/path")]
39+
[InlineData("/test/path?foo=bar#baz")]
40+
[InlineData("~/")]
41+
[InlineData("~/Home/About")]
42+
public void IsLocalUrl_True_ForLocalUrl(string url)
43+
{
44+
// Act
45+
var actual = RedirectHttpResult.IsLocalUrl(url);
46+
47+
// Assert
48+
Assert.True(actual);
49+
}
50+
51+
[Theory]
52+
[InlineData(null)]
53+
[InlineData("")]
54+
[InlineData("//")]
55+
[InlineData("/\\")]
56+
[InlineData("//foo")]
57+
[InlineData("/\\foo")]
58+
[InlineData("Home/About")]
59+
[InlineData("test/path")]
60+
[InlineData("http://www.example.com")]
61+
[InlineData("https://example.com/non-local-url/example")]
62+
[InlineData("https://example.com/non-local-url/example?foo=bar#baz")]
63+
public void IsLocalUrl_False_ForNonLocalUrl(string url)
64+
{
65+
// Act
66+
var actual = RedirectHttpResult.IsLocalUrl(url);
67+
68+
// Assert
69+
Assert.False(actual);
70+
}
71+
72+
[Theory]
73+
[InlineData("~//")]
74+
[InlineData("~/\\")]
75+
[InlineData("~//foo")]
76+
[InlineData("~/\\foo")]
77+
public void IsLocalUrl_False_ForNonLocalUrlTilde(string url)
78+
{
79+
// Act
80+
var actual = RedirectHttpResult.IsLocalUrl(url);
81+
82+
// Assert
83+
Assert.False(actual);
84+
}
85+
3686
protected override Task ExecuteAsync(HttpContext httpContext, string contentPath)
3787
{
3888
var redirectResult = new RedirectHttpResult(contentPath, false, false);

0 commit comments

Comments
 (0)