Tolerate leading "~/" or "/" (#509)

This commit is contained in:
Jass Bagga 2018-01-11 13:00:01 -08:00 committed by GitHub
parent 93d20ec78c
commit 57697baedb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 86 additions and 47 deletions

View File

@ -249,7 +249,7 @@ namespace Microsoft.AspNetCore.Routing
=> string.Format(CultureInfo.CurrentCulture, GetString("TemplateRoute_InvalidParameterName"), p0);
/// <summary>
/// The route template cannot start with a '/' or '~' character.
/// The route template cannot start with a '~' character unless followed by a '/'.
/// </summary>
internal static string TemplateRoute_InvalidRouteTemplate
{
@ -257,7 +257,7 @@ namespace Microsoft.AspNetCore.Routing
}
/// <summary>
/// The route template cannot start with a '/' or '~' character.
/// The route template cannot start with a '~' character unless followed by a '/'.
/// </summary>
internal static string FormatTemplateRoute_InvalidRouteTemplate()
=> GetString("TemplateRoute_InvalidRouteTemplate");

View File

@ -169,7 +169,7 @@
<value>The route parameter name '{0}' is invalid. Route parameter names must be non-empty and cannot contain these characters: '{{', '}}', '/'. The '?' character marks a parameter as optional, and can occur only at the end of the parameter. The '*' character marks a parameter as catch-all, and can occur only at the start of the parameter.</value>
</data>
<data name="TemplateRoute_InvalidRouteTemplate" xml:space="preserve">
<value>The route template cannot start with a '/' or '~' character.</value>
<value>The route template cannot start with a '~' character unless followed by a '/'.</value>
</data>
<data name="TemplateRoute_MismatchedParameter" xml:space="preserve">
<value>There is an incomplete parameter in the route template. Check that each '{' character has a matching '}' character.</value>

View File

@ -25,12 +25,9 @@ namespace Microsoft.AspNetCore.Routing.Template
routeTemplate = String.Empty;
}
if (IsInvalidRouteTemplate(routeTemplate))
{
throw new ArgumentException(Resources.TemplateRoute_InvalidRouteTemplate, nameof(routeTemplate));
}
var trimmedRouteTemplate = TrimPrefix(routeTemplate);
var context = new TemplateParserContext(routeTemplate);
var context = new TemplateParserContext(trimmedRouteTemplate);
var segments = new List<TemplateSegment>();
while (context.Next())
@ -61,6 +58,23 @@ namespace Microsoft.AspNetCore.Routing.Template
}
}
private static string TrimPrefix(string routeTemplate)
{
if (routeTemplate.StartsWith("~/", StringComparison.Ordinal))
{
return routeTemplate.Substring(2);
}
else if (routeTemplate.StartsWith("/", StringComparison.Ordinal))
{
return routeTemplate.Substring(1);
}
else if (routeTemplate.StartsWith("~", StringComparison.Ordinal))
{
throw new ArgumentException(Resources.TemplateRoute_InvalidRouteTemplate, nameof(routeTemplate));
}
return routeTemplate;
}
private static bool ParseSegment(TemplateParserContext context, List<TemplateSegment> segments)
{
Debug.Assert(context != null);

View File

@ -691,6 +691,28 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
"/UrlEncode[[v1]]");
}
[Fact]
public void GetUrlWithLeadingTildeSlash()
{
RunTest(
"~/foo",
null,
null,
new RouteValueDictionary(new { }),
"/UrlEncode[[foo]]");
}
[Fact]
public void GetUrlWithLeadingSlash()
{
RunTest(
"/foo",
null,
null,
new RouteValueDictionary(new { }),
"/UrlEncode[[foo]]");
}
[Fact]
public void TemplateBinder_KeepsExplicitlySuppliedRouteValues_OnFailedRouetMatch()
{
@ -721,7 +743,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
#if ROUTE_COLLECTION
[Fact]
[Fact]
public void GetUrlShouldValidateOnlyAcceptedParametersAndUserDefaultValuesForInvalidatedParameters()
{
// Arrange
@ -755,7 +777,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
Assert.Equal<string>("/app1/UrlConstraints/Validation.mvc/Input5/MissmatchedValidateParameters2/valid1", vpd.VirtualPath);
}
[Fact]
[Fact]
public void GetUrlWithRouteThatHasExtensionWithSubsequentDefaultValueIncludesExtensionButNotDefaultValue()
{
// Arrange

View File

@ -655,6 +655,18 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
"Parameter name: routeTemplate");
}
[Theory]
[InlineData("/foo")]
[InlineData("~/foo")]
public void ValidTemplate_CanStartWithSlashOrTildeSlash(string routeTemplate)
{
// Arrange & Act
var template = TemplateParser.Parse(routeTemplate);
// Assert
Assert.Equal(routeTemplate, template.TemplateText);
}
[Fact]
public void InvalidTemplate_CannotHaveConsecutiveOpenBrace()
{
@ -768,21 +780,12 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
"Parameter name: routeTemplate");
}
[Fact]
public void InvalidTemplate_CannotStartWithSlash()
{
ExceptionAssert.Throws<ArgumentException>(
() => TemplateParser.Parse("/foo"),
"The route template cannot start with a '/' or '~' character." + Environment.NewLine +
"Parameter name: routeTemplate");
}
[Fact]
public void InvalidTemplate_CannotStartWithTilde()
{
ExceptionAssert.Throws<ArgumentException>(
() => TemplateParser.Parse("~foo"),
"The route template cannot start with a '/' or '~' character." + Environment.NewLine +
"The route template cannot start with a '~' character unless followed by a '/'." + Environment.NewLine +
"Parameter name: routeTemplate");
}