private Pattern ParseString(ParserContext context, UriMatchPart uriMatchPart) { var results = new List <PatternSegment>(); while (context.Next()) { if (context.Current == OpenBrace) { // This is a server parameter, parse for a condition variable if (!context.Next()) { // missing { throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } ParseParameter(context, results, uriMatchPart); } else if (context.Current == CloseBrace) { return(new Pattern(results)); } else { // Parse for literals, which will return on either the end of the test string // or when it hits a special character ParseLiteral(context, results); } } return(new Pattern(results)); }
/// <summary> /// Creates a pattern, which is a template to create a new test string to /// compare to the condition. Can contain server variables, back references, etc. /// </summary> /// <param name="testString"></param> /// <param name="uriMatchPart">When testString evaluates to a URL segment, specify which part of the URI to evaluate.</param> /// <returns>A new <see cref="Pattern"/>, containing a list of <see cref="PatternSegment"/></returns> public Pattern ParseInputString(string testString, UriMatchPart uriMatchPart) { if (testString == null) { testString = string.Empty; } var context = new ParserContext(testString); return(ParseString(context, uriMatchPart)); }
// Creates a rule with appropriate default values of the url rewrite rule. private IISUrlRewriteRule CreateTestRule(ConditionCollection conditions, string name = "", bool enabled = true, PatternSyntax patternSyntax = PatternSyntax.ECMAScript, bool stopProcessing = false, string url = "", bool ignoreCase = true, bool negate = false, ActionType actionType = ActionType.None, string pattern = "", bool appendQueryString = false, bool rewrittenUrl = false, bool global = false, UriMatchPart uriMatchPart = UriMatchPart.Path, RedirectType redirectType = RedirectType.Permanent ) { return(new IISUrlRewriteRule( name, new RegexMatch(new Regex("^OFF$"), negate), conditions, new RewriteAction(RuleResult.ContinueRules, new InputParser().ParseInputString(url, uriMatchPart), queryStringAppend: false), global)); }
/// <summary> /// Returns the matching <see cref="PatternSegment"/> for the given <paramref name="serverVariable"/> /// </summary> /// <param name="serverVariable">The server variable</param> /// <param name="context">The parser context which is utilized when an exception is thrown</param> /// <param name="uriMatchPart">Indicates whether the full URI or the path should be evaluated for URL segments</param> /// <param name="alwaysUseManagedServerVariables">Determines whether server variables are sourced from the managed server</param> /// <exception cref="FormatException">Thrown when the server variable is unknown</exception> /// <returns>The matching <see cref="PatternSegment"/></returns> public static PatternSegment FindServerVariable(string serverVariable, ParserContext context, UriMatchPart uriMatchPart, bool alwaysUseManagedServerVariables) { Func <PatternSegment> managedVariableThunk = default; switch (serverVariable) { // TODO Add all server variables here. case "ALL_RAW": managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); break; case "APP_POOL_ID": managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); break; case "CONTENT_LENGTH": managedVariableThunk = () => new HeaderSegment(HeaderNames.ContentLength); break; case "CONTENT_TYPE": managedVariableThunk = () => new HeaderSegment(HeaderNames.ContentType); break; case "HTTP_ACCEPT": managedVariableThunk = () => new HeaderSegment(HeaderNames.Accept); break; case "HTTP_COOKIE": managedVariableThunk = () => new HeaderSegment(HeaderNames.Cookie); break; case "HTTP_HOST": managedVariableThunk = () => new HeaderSegment(HeaderNames.Host); break; case "HTTP_REFERER": managedVariableThunk = () => new HeaderSegment(HeaderNames.Referer); break; case "HTTP_USER_AGENT": managedVariableThunk = () => new HeaderSegment(HeaderNames.UserAgent); break; case "HTTP_CONNECTION": managedVariableThunk = () => new HeaderSegment(HeaderNames.Connection); break; case "HTTP_URL": managedVariableThunk = () => new UrlSegment(uriMatchPart); break; case "HTTPS": managedVariableThunk = () => new IsHttpsUrlSegment(); break; case "LOCAL_ADDR": managedVariableThunk = () => new LocalAddressSegment(); break; case "HTTP_PROXY_CONNECTION": managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); break; case "QUERY_STRING": managedVariableThunk = () => new QueryStringSegment(); break; case "REMOTE_ADDR": managedVariableThunk = () => new RemoteAddressSegment(); break; case "REMOTE_HOST": managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); break; case "REMOTE_PORT": managedVariableThunk = () => new RemotePortSegment(); break; case "REQUEST_FILENAME": managedVariableThunk = () => new RequestFileNameSegment(); break; case "REQUEST_METHOD": managedVariableThunk = () => new RequestMethodSegment(); break; case "REQUEST_URI": managedVariableThunk = () => new UrlSegment(uriMatchPart); break; default: throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(serverVariable, context.Index)); } if (alwaysUseManagedServerVariables) { return(managedVariableThunk()); } return(new IISServerVariableSegment(serverVariable, managedVariableThunk)); }
private void ParseParameter(ParserContext context, IList <PatternSegment> results, UriMatchPart uriMatchPart) { context.Mark(); // Four main cases: // 1. {NAME} - Server Variable, create lambda to get the part of the context // 2. {R:1} - IRule parameter // 3. {C:1} - Condition Parameter // 4. {function:xxx} - String function // (unless we support Reload) string parameter; while (context.Next()) { if (context.Current == CloseBrace) { // This is just a server variable, so we do a lookup and verify the server variable exists. parameter = context.Capture(); results.Add(ServerVariables.FindServerVariable(parameter, context, uriMatchPart)); return; } else if (context.Current == Colon) { parameter = context.Capture(); // Only 5 strings to expect here. Case sensitive. switch (parameter) { case "ToLower": { var pattern = ParseString(context, uriMatchPart); results.Add(new ToLowerSegment(pattern)); // at this point, we expect our context to be on the ending closing brace, // because the ParseString() call will increment the context until it // has processed the new string. if (context.Current != CloseBrace) { throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } return; } case "UrlDecode": { throw new NotImplementedException("UrlDecode is not implemented because of no great library available"); } case "UrlEncode": { var pattern = ParseString(context, uriMatchPart); results.Add(new UrlEncodeSegment(pattern)); if (context.Current != CloseBrace) { throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } return; } case "R": { var index = GetBackReferenceIndex(context); results.Add(new RuleMatchSegment(index)); return; } case "C": { var index = GetBackReferenceIndex(context); results.Add(new ConditionMatchSegment(index)); return; } default: var rewriteMap = _rewriteMaps?[parameter]; if (rewriteMap != null) { var pattern = ParseString(context, uriMatchPart); results.Add(new RewriteMapSegment(rewriteMap, pattern)); return; } throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(parameter, context.Index)); } } } throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); }
public void CheckServerVariableFeatureHasPrecedenceWhenEnabled(string variable, string expected, UriMatchPart uriMatchPart) { // Arrange and Act var testParserContext = new ParserContext("test"); var serverVar = ServerVariables.FindServerVariable(variable, testParserContext, uriMatchPart, false); var httpContext = CreateTestHttpContext(); httpContext.Features.Set <IServerVariablesFeature>(new TestServerVariablesFeature(new Dictionary <string, string> { ["CONTENT_LENGTH"] = "20", ["CONTENT_TYPE"] = "text/xml", ["HTTP_ACCEPT"] = "other-accept", ["HTTP_COOKIE"] = "other-cookie", ["HTTP_HOST"] = "otherexample.com", ["HTTP_REFERER"] = "other-referer", ["HTTP_USER_AGENT"] = "other-useragent", ["HTTP_CONNECTION"] = "other-connection", ["HTTP_URL"] = "http://otherexample.com/other-foo?bar=2", ["QUERY_STRING"] = "bar=2", ["REQUEST_FILENAME"] = "/other-foo", ["REQUEST_URI"] = "/other-foo", ["REQUEST_METHOD"] = "POST" })); var rewriteContext = CreateTestRewriteContext(httpContext); var lookup = serverVar.Evaluate(rewriteContext, CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences); // Assert Assert.Equal(expected, lookup); }
public UrlSegment(UriMatchPart uriMatchPart) { _uriMatchPart = uriMatchPart; }
private static Pattern CreatePattern(InputParser inputParser, string input, UriMatchPart uriMatchPart) { return(inputParser.ParseInputString(input, uriMatchPart)); }
public void CheckServerVariableParsingAndApplication(string variable, string expected, UriMatchPart uriMatchPart) { // Arrange and Act var testParserContext = new ParserContext("test"); var serverVar = ServerVariables.FindServerVariable(variable, testParserContext, uriMatchPart, true); var lookup = serverVar.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences); // Assert Assert.Equal(expected, lookup); }
public UriMatchCondition(InputParser inputParser, string input, string pattern, UriMatchPart uriMatchPart, bool ignoreCase, bool negate) : base(CreatePattern(inputParser, input, uriMatchPart), CreateRegexMatch(pattern, ignoreCase, negate)) { }
public void AssertSegmentIsCorrect(string scheme, string host, int port, string path, UriMatchPart uriMatchPart, string expectedResult) { // Arrange var httpContext = new DefaultHttpContext(); httpContext.Request.Scheme = scheme; httpContext.Request.Host = new HostString(host, port); httpContext.Request.Path = new PathString(path); var context = new RewriteContext { HttpContext = httpContext }; context.HttpContext = httpContext; // Act var segment = new UrlSegment(uriMatchPart); var results = segment.Evaluate(context, null, null); // Assert Assert.Equal(expectedResult, results); }
public async Task Invoke_GlobalRuleConditionMatchesAgainstFullUri_CodedRule(string conditionInputPattern, string expectedResult, UriMatchPart uriMatchPart) { // arrange var inputParser = new InputParser(); var ruleBuilder = new UrlRewriteRuleBuilder { Name = "test", Global = false }; ruleBuilder.AddUrlMatch(".*"); var condition = new UriMatchCondition( inputParser, "{REQUEST_URI}", conditionInputPattern, uriMatchPart, ignoreCase: true, negate: false); ruleBuilder.ConfigureConditionBehavior(LogicalGrouping.MatchAll, trackAllCaptures: true); ruleBuilder.AddUrlCondition(condition); var action = new RewriteAction( RuleResult.SkipRemainingRules, inputParser.ParseInputString(@"http://www.test.com{C:1}", uriMatchPart), queryStringAppend: false); ruleBuilder.AddUrlAction(action); var options = new RewriteOptions().Add(ruleBuilder.Build()); var builder = new WebHostBuilder() .Configure(app => { app.UseRewriter(options); app.Run(context => context.Response.WriteAsync(context.Request.GetEncodedUrl())); }); var server = new TestServer(builder); // act var response = await server.CreateClient().GetStringAsync("http://localhost/foo/bar"); // assert Assert.Equal(expectedResult, response); }
public UriMatchCondition(InputParser inputParser, string input, string pattern, UriMatchPart uriMatchPart, bool ignoreCase, bool negate) { var regexOptions = RegexOptions.CultureInvariant | RegexOptions.Compiled; regexOptions = ignoreCase ? regexOptions | RegexOptions.IgnoreCase : regexOptions; var regex = new Regex( pattern, regexOptions, _regexTimeout ); Input = inputParser.ParseInputString(input, uriMatchPart); Match = new RegexMatch(regex, negate); }
public UriMatchCondition(InputParser inputParser, string input, string pattern, UriMatchPart uriMatchPart, bool ignoreCase, bool negate) { var regex = new Regex( pattern, ignoreCase ? RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase : RegexOptions.CultureInvariant | RegexOptions.Compiled, TimeSpan.FromMilliseconds(1)); Input = inputParser.ParseInputString(input, uriMatchPart); Match = new RegexMatch(regex, negate); }