Beispiel #1
0
        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));
        }
Beispiel #2
0
        /// <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));
 }
Beispiel #4
0
        /// <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));
        }
Beispiel #5
0
        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));
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
 public UrlSegment(UriMatchPart uriMatchPart)
 {
     _uriMatchPart = uriMatchPart;
 }
Beispiel #8
0
 private static Pattern CreatePattern(InputParser inputParser, string input, UriMatchPart uriMatchPart)
 {
     return(inputParser.ParseInputString(input, uriMatchPart));
 }
Beispiel #9
0
        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);
        }
Beispiel #10
0
 public UriMatchCondition(InputParser inputParser, string input, string pattern, UriMatchPart uriMatchPart, bool ignoreCase, bool negate)
     : base(CreatePattern(inputParser, input, uriMatchPart), CreateRegexMatch(pattern, ignoreCase, negate))
 {
 }
Beispiel #11
0
        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);
        }
Beispiel #12
0
        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);
        }
Beispiel #14
0
        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);
        }