Validate the maximum number of route segments (#911)
This commit is contained in:
parent
bd481034fe
commit
b6a1de5676
|
|
@ -20,6 +20,8 @@ namespace Microsoft.AspNetCore.Routing.Template
|
|||
// /api/template/{id:int} == 1.12
|
||||
public static decimal ComputeInbound(RouteTemplate template)
|
||||
{
|
||||
ValidateSegementLength(template.Segments.Count);
|
||||
|
||||
// Each precedence digit corresponds to one decimal place. For example, 3 segments with precedences 2, 1,
|
||||
// and 4 results in a combined precedence of 2.14 (decimal).
|
||||
var precedence = 0m;
|
||||
|
|
@ -40,6 +42,8 @@ namespace Microsoft.AspNetCore.Routing.Template
|
|||
// See description on ComputeInbound(RouteTemplate)
|
||||
internal static decimal ComputeInbound(RoutePattern routePattern)
|
||||
{
|
||||
ValidateSegementLength(routePattern.PathSegments.Count);
|
||||
|
||||
var precedence = 0m;
|
||||
|
||||
for (var i = 0; i < routePattern.PathSegments.Count; i++)
|
||||
|
|
@ -62,6 +66,8 @@ namespace Microsoft.AspNetCore.Routing.Template
|
|||
// /api/template/{id:int} == 5.54
|
||||
public static decimal ComputeOutbound(RouteTemplate template)
|
||||
{
|
||||
ValidateSegementLength(template.Segments.Count);
|
||||
|
||||
// Each precedence digit corresponds to one decimal place. For example, 3 segments with precedences 2, 1,
|
||||
// and 4 results in a combined precedence of 2.14 (decimal).
|
||||
var precedence = 0m;
|
||||
|
|
@ -82,6 +88,8 @@ namespace Microsoft.AspNetCore.Routing.Template
|
|||
// see description on ComputeOutbound(RouteTemplate)
|
||||
internal static decimal ComputeOutbound(RoutePattern routePattern)
|
||||
{
|
||||
ValidateSegementLength(routePattern.PathSegments.Count);
|
||||
|
||||
// Each precedence digit corresponds to one decimal place. For example, 3 segments with precedences 2, 1,
|
||||
// and 4 results in a combined precedence of 2.14 (decimal).
|
||||
var precedence = 0m;
|
||||
|
|
@ -99,6 +107,15 @@ namespace Microsoft.AspNetCore.Routing.Template
|
|||
return precedence;
|
||||
}
|
||||
|
||||
private static void ValidateSegementLength(int length)
|
||||
{
|
||||
if (length > 28)
|
||||
{
|
||||
// An OverflowException will be thrown by Math.Pow when greater than 28
|
||||
throw new InvalidOperationException("Route exceeds the maximum number of allowed segments of 28 and is unable to be processed.");
|
||||
}
|
||||
}
|
||||
|
||||
// Segments have the following order:
|
||||
// 5 - Literal segments
|
||||
// 4 - Multi-part segments && Constrained parameter segments
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Routing.Patterns;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Template
|
||||
{
|
||||
public class RoutePatternPrecedenceTests : RoutePrecedenceTestsBase
|
||||
{
|
||||
protected override decimal ComputeMatched(string template)
|
||||
{
|
||||
return ComputeRoutePattern(template, RoutePrecedence.ComputeInbound);
|
||||
}
|
||||
|
||||
protected override decimal ComputeGenerated(string template)
|
||||
{
|
||||
return ComputeRoutePattern(template, RoutePrecedence.ComputeOutbound);
|
||||
}
|
||||
|
||||
private static decimal ComputeRoutePattern(string template, Func<RoutePattern, decimal> func)
|
||||
{
|
||||
var parsed = RoutePatternFactory.Parse(template);
|
||||
return func(parsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,13 +2,11 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Template
|
||||
{
|
||||
public class RoutePrecedenceTests
|
||||
public abstract class RoutePrecedenceTestsBase
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Employees/{id}", "Employees/{employeeId}")]
|
||||
|
|
@ -100,22 +98,34 @@ namespace Microsoft.AspNetCore.Routing.Template
|
|||
Assert.True(xPrecedence > yPrecedence);
|
||||
}
|
||||
|
||||
private static decimal ComputeMatched(string template)
|
||||
[Fact]
|
||||
public void ComputeGenerated_TooManySegments_ThrowHumaneError()
|
||||
{
|
||||
return Compute(template, RoutePrecedence.ComputeInbound);
|
||||
}
|
||||
private static decimal ComputeGenerated(string template)
|
||||
{
|
||||
return Compute(template, RoutePrecedence.ComputeOutbound);
|
||||
var ex = Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
// Arrange & Act
|
||||
ComputeGenerated("{a}/{b}/{c}/{d}/{e}/{f}/{g}/{h}/{i}/{j}/{k}/{l}/{m}/{n}/{o}/{p}/{q}/{r}/{s}/{t}/{u}/{v}/{w}/{x}/{y}/{z}/{a2}/{b2}/{b3}");
|
||||
});
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Route exceeds the maximum number of allowed segments of 28 and is unable to be processed.", ex.Message);
|
||||
}
|
||||
|
||||
private static decimal Compute(string template, Func<RouteTemplate, decimal> func)
|
||||
[Fact]
|
||||
public void ComputeMatched_TooManySegments_ThrowHumaneError()
|
||||
{
|
||||
var options = new Mock<IOptions<RouteOptions>>();
|
||||
options.SetupGet(o => o.Value).Returns(new RouteOptions());
|
||||
var ex = Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
// Arrange & Act
|
||||
ComputeMatched("{a}/{b}/{c}/{d}/{e}/{f}/{g}/{h}/{i}/{j}/{k}/{l}/{m}/{n}/{o}/{p}/{q}/{r}/{s}/{t}/{u}/{v}/{w}/{x}/{y}/{z}/{a2}/{b2}/{b3}");
|
||||
});
|
||||
|
||||
var parsed = TemplateParser.Parse(template);
|
||||
return func(parsed);
|
||||
// Assert
|
||||
Assert.Equal("Route exceeds the maximum number of allowed segments of 28 and is unable to be processed.", ex.Message);
|
||||
}
|
||||
|
||||
protected abstract decimal ComputeMatched(string template);
|
||||
|
||||
protected abstract decimal ComputeGenerated(string template);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Template
|
||||
{
|
||||
public class RouteTemplatePrecedenceTests : RoutePrecedenceTestsBase
|
||||
{
|
||||
protected override decimal ComputeMatched(string template)
|
||||
{
|
||||
return ComputeRouteTemplate(template, RoutePrecedence.ComputeInbound);
|
||||
}
|
||||
|
||||
protected override decimal ComputeGenerated(string template)
|
||||
{
|
||||
return ComputeRouteTemplate(template, RoutePrecedence.ComputeOutbound);
|
||||
}
|
||||
|
||||
private static decimal ComputeRouteTemplate(string template, Func<RouteTemplate, decimal> func)
|
||||
{
|
||||
var parsed = TemplateParser.Parse(template);
|
||||
return func(parsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue