public void Pattern_CreatesConstraintFromString() { // Arrange var template = "{a}/{b}/{c}"; var defaults = new { }; var constraints = new { d = "foo", }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.ParameterPolicies.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("d", kvp.Key); var regex = Assert.IsType <RegexRouteConstraint>(Assert.Single(kvp.Value).ParameterPolicy); Assert.Equal("^(foo)$", regex.Constraint.ToString()); }); }
public void Pattern_ExtraConstraints_MultipleConstraintsForKey() { // Arrange var template = "{a}/{b}/{c}"; var defaults = new { }; var constraints = new { d = new object[] { new RegexRouteConstraint("foo"), new RegexRouteConstraint("bar"), "baz" } }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.ParameterPolicies.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("d", kvp.Key); Assert.Collection( kvp.Value, c => Assert.Equal("foo", Assert.IsType <RegexRouteConstraint>(c.ParameterPolicy).Constraint.ToString()), c => Assert.Equal("bar", Assert.IsType <RegexRouteConstraint>(c.ParameterPolicy).Constraint.ToString()), c => Assert.Equal("^(baz)$", Assert.IsType <RegexRouteConstraint>(c.ParameterPolicy).Constraint.ToString())); }); }
public void Pattern_RawTextAndArrayOfSegments_ShouldMakeCopyOfArrayOfSegments() { // Arrange var rawText = "raw"; var literalPartA = RoutePatternFactory.LiteralPart("A"); var paramPartB = RoutePatternFactory.ParameterPart("B"); var paramPartC = RoutePatternFactory.ParameterPart("C"); var paramPartD = RoutePatternFactory.ParameterPart("D"); var segments = new[] { RoutePatternFactory.Segment(literalPartA, paramPartB), RoutePatternFactory.Segment(paramPartC, literalPartA), RoutePatternFactory.Segment(paramPartD), RoutePatternFactory.Segment(literalPartA) }; // Act var actual = RoutePatternFactory.Pattern(rawText, segments); segments[1] = RoutePatternFactory.Segment(RoutePatternFactory.ParameterPart("E")); Array.Resize(ref segments, 2); // Assert Assert.Equal(3, actual.Parameters.Count); Assert.Same(paramPartB, actual.Parameters[0]); Assert.Same(paramPartC, actual.Parameters[1]); Assert.Same(paramPartD, actual.Parameters[2]); }
public void Pattern_MergesDefaultValues() { // Arrange var template = "{a}/{b}/{c=19}"; var defaults = new { a = "15", b = 17 }; var constraints = new { }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Equal("15", actual.GetParameter("a").Default); Assert.Equal(17, actual.GetParameter("b").Default); Assert.Equal("19", actual.GetParameter("c").Default); Assert.Collection( actual.Defaults.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("a", kvp.Key); Assert.Equal("15", kvp.Value); }, kvp => { Assert.Equal("b", kvp.Key); Assert.Equal(17, kvp.Value); }, kvp => { Assert.Equal("c", kvp.Key); Assert.Equal("19", kvp.Value); }); }
public void Pattern_ExtraConstraints_RouteConstraint() { // Arrange var template = "{a}/{b}/{c}"; var defaults = new { }; var constraints = new { d = Mock.Of <IRouteConstraint>(), e = Mock.Of <IRouteConstraint>(), }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.ParameterPolicies.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("d", kvp.Key); Assert.Collection( kvp.Value, c => Assert.NotNull(c.ParameterPolicy)); }, kvp => { Assert.Equal("e", kvp.Key); Assert.Collection( kvp.Value, c => Assert.NotNull(c.ParameterPolicy)); }); }
public async Task AddRoutePatternToClaims() { var context = new DefaultHttpContext(); context.Request.Method = "POST"; IEndpointFeature endpointFeature = Substitute.For <IEndpointFeature>(); RoutePattern routePattern = RoutePatternFactory.Pattern("weather/{town}"); var routeEndpoint = new RouteEndpoint(_ => null, routePattern, default, default, string.Empty);
private RouteEndpoint CreateEndpoint( ActionDescriptor action, IDictionary <string, string> actionRouteValues, string routeName, string patternRawText, IEnumerable <RoutePatternPathSegment> segments, object nonInlineDefaults, int order, RouteValueDictionary dataTokens, bool suppressLinkGeneration, bool suppressPathMatching, List <Action <EndpointModel> > conventions) { RequestDelegate requestDelegate = (context) => { var routeData = context.GetRouteData(); var actionContext = new ActionContext(context, routeData, action); var invoker = _invokerFactory.CreateInvoker(actionContext); return(invoker.InvokeAsync()); }; var defaults = new RouteValueDictionary(nonInlineDefaults); EnsureRequiredValuesInDefaults(actionRouteValues, defaults, segments); var model = new RouteEndpointModel(requestDelegate, RoutePatternFactory.Pattern(patternRawText, defaults, parameterPolicies: null, segments), order); AddEndpointMetadata( model.Metadata, action, routeName, new RouteValueDictionary(actionRouteValues), dataTokens, suppressLinkGeneration, suppressPathMatching); model.DisplayName = action.DisplayName; // REVIEW: When should conventions be run // Metadata should have lower precedence that data source metadata if (conventions != null) { foreach (var convention in conventions) { convention(model); } } return((RouteEndpoint)model.Build()); }
public static RoutePattern Parse(string pattern) { if (pattern == null) { throw new ArgumentNullException(nameof(pattern)); } var trimmedPattern = TrimPrefix(pattern); var context = new Context(trimmedPattern); var segments = new List <RoutePatternPathSegment>(); while (context.MoveNext()) { var i = context.Index; if (context.Current == Separator) { // If we get here is means that there's a consecutive '/' character. // Templates don't start with a '/' and parsing a segment consumes the separator. throw new RoutePatternException(pattern, Resources.TemplateRoute_CannotHaveConsecutiveSeparators); } if (!ParseSegment(context, segments)) { throw new RoutePatternException(pattern, context.Error); } // A successful parse should always result in us being at the end or at a separator. Debug.Assert(context.AtEnd() || context.Current == Separator); if (context.Index <= i) { // This shouldn't happen, but we want to crash if it does. var message = "Infinite loop detected in the parser. Please open an issue."; throw new InvalidProgramException(message); } } if (IsAllValid(context, segments)) { return(RoutePatternFactory.Pattern(pattern, segments)); } else { throw new RoutePatternException(pattern, context.Error); } }
private RouteEndpoint CreateEndpoint( ActionDescriptor action, string routeName, string patternRawText, IEnumerable <RoutePatternPathSegment> segments, object nonInlineDefaults, int order, object source, bool suppressLinkGeneration) { RequestDelegate requestDelegate = (context) => { var values = context.Features.Get <IRouteValuesFeature>().RouteValues; var routeData = new RouteData(); foreach (var kvp in values) { if (kvp.Value != null) { routeData.Values.Add(kvp.Key, kvp.Value); } } var actionContext = new ActionContext(context, routeData, action); var invoker = _invokerFactory.CreateInvoker(actionContext); return(invoker.InvokeAsync()); }; var defaults = new RouteValueDictionary(nonInlineDefaults); EnsureRequiredValuesInDefaults(action.RouteValues, defaults); var metadataCollection = BuildEndpointMetadata( action, routeName, new RouteValueDictionary(action.RouteValues), source, suppressLinkGeneration); var endpoint = new RouteEndpoint( requestDelegate, RoutePatternFactory.Pattern(patternRawText, defaults, parameterPolicies: null, segments), order, metadataCollection, action.DisplayName); return(endpoint); }
private RouteEndpoint CreateEndpoint( ActionDescriptor action, IDictionary <string, string> actionRouteValues, string routeName, string patternRawText, object nonParameterPolicies, IEnumerable <RoutePatternPathSegment> segments, object nonInlineDefaults, int order, RouteValueDictionary dataTokens, bool suppressLinkGeneration, bool suppressPathMatching) { RequestDelegate requestDelegate = (context) => { var routeData = context.GetRouteData(); var actionContext = new ActionContext(context, routeData, action); var invoker = _invokerFactory.CreateInvoker(actionContext); return(invoker.InvokeAsync()); }; var defaults = new RouteValueDictionary(nonInlineDefaults); EnsureRequiredValuesInDefaults(actionRouteValues, defaults, segments); var metadataCollection = BuildEndpointMetadata( action, routeName, new RouteValueDictionary(actionRouteValues), dataTokens, suppressLinkGeneration, suppressPathMatching); var endpoint = new RouteEndpoint( requestDelegate, RoutePatternFactory.Pattern(patternRawText, defaults, nonParameterPolicies, segments), order, metadataCollection, action.DisplayName); return(endpoint); }
public void Pattern_ExtraConstraints_NestedArray_Throws() { // Arrange var template = "{a}/{b}/{c:int}"; var defaults = new { }; var constraints = new { c = new object[] { new object[0] } }; var original = RoutePatternFactory.Parse(template); // Act & Assert Assert.Throws <InvalidOperationException>(() => { RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); }); }
public void Pattern_MergesConstraints() { // Arrange var template = "{a:int}/{b}/{c}"; var defaults = new { }; var constraints = new { a = new RegexRouteConstraint("foo"), b = new RegexRouteConstraint("bar") }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.GetParameter("a").ParameterPolicies, c => Assert.IsType <RegexRouteConstraint>(c.ParameterPolicy), c => Assert.Equal("int", c.Content)); Assert.Collection( actual.GetParameter("b").ParameterPolicies, c => Assert.IsType <RegexRouteConstraint>(c.ParameterPolicy)); Assert.Collection( actual.ParameterPolicies.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("a", kvp.Key); Assert.Collection( kvp.Value, c => Assert.IsType <RegexRouteConstraint>(c.ParameterPolicy), c => Assert.Equal("int", c.Content)); }, kvp => { Assert.Equal("b", kvp.Key); Assert.Collection( kvp.Value, c => Assert.IsType <RegexRouteConstraint>(c.ParameterPolicy)); }); }
public void Pattern_SameDuplicateDefaultValue() { // Arrange var template = "{a=13}/{b}/{c}"; var defaults = new { a = "13", }; var constraints = new { }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.Defaults, kvp => { Assert.Equal("a", kvp.Key); Assert.Equal("13", kvp.Value); }); }
public void Pattern_InvalidConstraintTypeThrows() { // Arrange var template = "{a}/{b}/{c}"; var defaults = new { }; var constraints = new { d = 17, }; var original = RoutePatternFactory.Parse(template); // Act var ex = Assert.Throws <InvalidOperationException>(() => RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments)); // Assert Assert.Equal( $"Invalid constraint '17'. A constraint must be of type 'string' or '{typeof(IRouteConstraint)}'.", ex.Message); }
public void Pattern_OptionalParameterDefaultValue_Throws() { // Arrange var template = "{a}/{b}/{c?}"; var defaults = new { c = "15", }; var constraints = new { }; var original = RoutePatternFactory.Parse(template); // Act var ex = Assert.Throws <InvalidOperationException>(() => RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments)); // Assert Assert.Equal( "An optional parameter cannot have default value.", ex.Message); }
public void Pattern_RawTextAndDefaultsAndParameterPoliciesAndArrayOfSegments_ShouldMakeCopyOfArrayOfSegments() { // Arrange var rawText = "raw"; object defaults = new { B = 12, C = 4 }; object parameterPolicies = null; var literalPartA = RoutePatternFactory.LiteralPart("A"); var paramPartB = RoutePatternFactory.ParameterPart("B"); var paramPartC = RoutePatternFactory.ParameterPart("C"); var paramPartD = RoutePatternFactory.ParameterPart("D"); var segments = new[] { RoutePatternFactory.Segment(literalPartA, paramPartB), RoutePatternFactory.Segment(paramPartC, literalPartA), RoutePatternFactory.Segment(paramPartD), RoutePatternFactory.Segment(literalPartA) }; // Act var actual = RoutePatternFactory.Pattern(rawText, defaults, parameterPolicies, segments); segments[1] = RoutePatternFactory.Segment(RoutePatternFactory.ParameterPart("E")); Array.Resize(ref segments, 2); // Assert Assert.Equal(3, actual.Parameters.Count); Assert.Equal(paramPartB.Name, actual.Parameters[0].Name); Assert.Equal(12, actual.Parameters[0].Default); Assert.Null(paramPartB.Default); Assert.NotSame(paramPartB, actual.Parameters[0]); Assert.Equal(paramPartC.Name, actual.Parameters[1].Name); Assert.Equal(4, actual.Parameters[1].Default); Assert.NotSame(paramPartC, actual.Parameters[1]); Assert.Null(paramPartC.Default); Assert.Equal(paramPartD.Name, actual.Parameters[2].Name); Assert.Null(actual.Parameters[2].Default); Assert.Same(paramPartD, actual.Parameters[2]); Assert.Null(paramPartD.Default); }
public void Pattern_ExtraDefaultValues() { // Arrange var template = "{a}/{b}/{c}"; var defaults = new { d = "15", e = 17 }; var constraints = new { }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.Defaults.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("d", kvp.Key); Assert.Equal("15", kvp.Value); }, kvp => { Assert.Equal("e", kvp.Key); Assert.Equal(17, kvp.Value); }); }
public void Pattern_DifferentDuplicateDefaultValue_Throws() { // Arrange var template = "{a=13}/{b}/{c}"; var defaults = new { a = "15", }; var constraints = new { }; var original = RoutePatternFactory.Parse(template); // Act var ex = Assert.Throws <InvalidOperationException>(() => RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments)); // Assert Assert.Equal( "The route parameter 'a' has both an inline default value and an explicit default " + "value specified. A route parameter cannot contain an inline default value when a " + "default value is specified explicitly. Consider removing one of them.", ex.Message); }
private IReadOnlyList <Endpoint> Update(StaticFileOptionsProvider staticFileOptionsProvider) { const string HtmlExtension = ".html"; const string CatchAllSlugPrefix = "..."; var staticFileOptions = staticFileOptionsProvider.StaticFileOptions; var requestDelegate = CreateRequestDelegate(this.endpointRouteBuilder, staticFileOptions); var endpoints = new List <Endpoint>(); foreach (var filePath in TraverseFiles(staticFileOptions.FileProvider)) { if (!filePath.EndsWith(HtmlExtension)) { continue; } var fileWithoutHtml = filePath.Substring(0, filePath.Length - HtmlExtension.Length); var patternSegments = new List <RoutePatternPathSegment>(); var segments = fileWithoutHtml.Split('/'); // NOTE: Start at 1 because paths here always have a leading slash for (int i = 1; i < segments.Length; i++) { var segment = segments[i]; if (i == segments.Length - 1 && segment == "index") { // Skip `index` segment, match whatever we got so far. // This is so that e.g. file `/a/b/index.html` is served at path `/a/b`, as desired. // TODO: Should we also serve the same file at `/a/b/index`? Note that `/a/b/index.html` will already work // via the UseStaticFiles middleware added by `NextjsStaticHostingExtensions.UseNextjsStaticHosting`. break; } var match = slugRegex.Match(segment); if (match.Success) { string slugName = match.Groups[1].Value; if (slugName.StartsWith(CatchAllSlugPrefix)) { // Catch all route -- see: https://nextjs.org/docs/routing/dynamic-routes#catch-all-routes var parameterName = slugName.Substring(CatchAllSlugPrefix.Length); patternSegments.Add( RoutePatternFactory.Segment( RoutePatternFactory.ParameterPart(parameterName, null, RoutePatternParameterKind.CatchAll))); } else { // Dynamic route -- see: https://nextjs.org/docs/routing/dynamic-routes patternSegments.Add( RoutePatternFactory.Segment( RoutePatternFactory.ParameterPart(slugName))); } } else { // Literal match patternSegments.Add( RoutePatternFactory.Segment( RoutePatternFactory.LiteralPart(segment))); } } var endpointBuilder = new RouteEndpointBuilder(requestDelegate, RoutePatternFactory.Pattern(patternSegments), order: DefaultEndpointOrder); endpointBuilder.Metadata.Add(new StaticFileEndpointMetadata(filePath)); endpointBuilder.DisplayName = $"Next.js {filePath}"; var endpoint = endpointBuilder.Build(); endpoints.Add(endpoint); } return(endpoints); }
public void PathContextProviderConstructor1() { var path = new StringValues("SomePathValue1"); var endpointMock = new Mock <IEndpointFeature>(); endpointMock.Setup(em => em.Endpoint).Returns(new RouteEndpoint(rd => Task.CompletedTask, RoutePatternFactory.Pattern(path), 0, null, null) { }); var featureMock = new Mock <IFeatureCollection>(); featureMock.Setup(fm => fm[typeof(IEndpointFeature)]).Returns(endpointMock.Object); var contextMock = new Mock <HttpContext>(); contextMock.Setup(cm => cm.Features).Returns(featureMock.Object); var accessorMock = new Mock <IHttpContextAccessor>(); accessorMock.Setup(am => am.HttpContext).Returns(contextMock.Object); var contextProvider = new PathContextProvider(accessorMock.Object); contextProvider.Path.Should().Be(path); }
private static Mock <IHttpContextAccessor> SetUpFullHttpContextAccessor(StringValues correlationId, StringValues forwardedFor, StringValues path, Uri referrer, string remoteIpAddress, string requestMethod, StringValues userAgent) { var endpointMock = new Mock <IEndpointFeature>(); endpointMock.Setup(em => em.Endpoint).Returns(new RouteEndpoint(rd => Task.CompletedTask, RoutePatternFactory.Pattern(path), 0, null, null) { }); var featureMock = new Mock <IFeatureCollection>(); featureMock.Setup(fm => fm[typeof(IEndpointFeature)]).Returns(endpointMock.Object); var connectionMock = new Mock <ConnectionInfo>(); connectionMock.Setup(cm => cm.RemoteIpAddress).Returns(IPAddress.Parse(remoteIpAddress)); var headers = new RequestHeaders(new HeaderDictionary()); headers.Set(CorrelationId, correlationId); headers.Set(ForwardedFor, forwardedFor); headers.Set(UserAgent, userAgent); headers.Referer = referrer; var requestMock = new Mock <HttpRequest>(); requestMock.Setup(rm => rm.Headers).Returns(headers.Headers); requestMock.Setup(rm => rm.Method).Returns(requestMethod); var contextMock = new Mock <HttpContext>(); contextMock.Setup(cm => cm.Request).Returns(requestMock.Object); contextMock.Setup(cm => cm.Items).Returns(new Dictionary <object, object>()); contextMock.Setup(cm => cm.Features).Returns(featureMock.Object); contextMock.Setup(cm => cm.Connection).Returns(connectionMock.Object); var accessorMock = new Mock <IHttpContextAccessor>(); accessorMock.Setup(am => am.HttpContext).Returns(contextMock.Object); return(accessorMock); }
public RoutePattern ToRoutePattern() { var segments = Segments.Select(s => s.ToRoutePatternPathSegment()); return(RoutePatternFactory.Pattern(TemplateText, segments)); }
public void SetHttpContextAddsAllIntendedExtendedProperties() { var correlationId = "CorrelationId1"; var forwardedFor = "SomeForwardedForValue1"; var path = "SomePathValue1"; var referrer = new Uri("http://SomeReferrerValue1"); var remoteIpAddress = "10.0.0.1"; var requestMethod = "SomeRequestMethodValue1"; var userAgent = "SomeUserAgentValue1"; var endpointMock = new Mock <IEndpointFeature>(); endpointMock.Setup(em => em.Endpoint).Returns(new RouteEndpoint(rd => Task.CompletedTask, RoutePatternFactory.Pattern(path), 0, null, null) { }); var featureMock = new Mock <IFeatureCollection>(); featureMock.Setup(fm => fm[typeof(IEndpointFeature)]).Returns(endpointMock.Object); var connectionMock = new Mock <ConnectionInfo>(); connectionMock.Setup(cm => cm.RemoteIpAddress).Returns(IPAddress.Parse(remoteIpAddress)); var headers = new RequestHeaders(new HeaderDictionary()); headers.Set(CorrelationId, correlationId); headers.Set(ForwardedFor, forwardedFor); headers.Set(UserAgent, userAgent); headers.Referer = referrer; var requestMock = new Mock <HttpRequest>(); requestMock.Setup(rm => rm.Headers).Returns(headers.Headers); requestMock.Setup(rm => rm.Method).Returns(requestMethod); var contextMock = new Mock <HttpContext>(); contextMock.Setup(cm => cm.Request).Returns(requestMock.Object); contextMock.Setup(cm => cm.Items).Returns(new Dictionary <object, object>()); contextMock.Setup(cm => cm.Features).Returns(featureMock.Object); contextMock.Setup(cm => cm.Connection).Returns(connectionMock.Object); var logEntry = new LogEntry(); logEntry.SetHttpContext(contextMock.Object); logEntry.CorrelationId.Should().Be(correlationId); logEntry.ExtendedProperties["X-Forwarded-For"].Should().Be(forwardedFor); logEntry.ExtendedProperties["Path"].Should().Be(path); logEntry.ExtendedProperties["Referrer"].Should().Be(referrer.ToString()); logEntry.ExtendedProperties["RemoteIpAddress"].Should().Be(remoteIpAddress); logEntry.ExtendedProperties["Method"].Should().Be(requestMethod.ToUpperInvariant()); logEntry.ExtendedProperties["UserAgent"].Should().Be(userAgent); }