229 lines
7.7 KiB
C#
229 lines
7.7 KiB
C#
// 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 System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using System.Xml.Linq;
|
|
|
|
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
|
{
|
|
// TODO rename
|
|
public static class UrlRewriteFileParser
|
|
{
|
|
private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1);
|
|
public static List<UrlRewriteRule> Parse(TextReader reader)
|
|
{
|
|
var temp = XDocument.Load(reader);
|
|
var xmlRoot = temp.Descendants(RewriteTags.Rewrite);
|
|
var rules = new List<UrlRewriteRule>();
|
|
|
|
if (xmlRoot != null)
|
|
{
|
|
// there is a valid rewrite block, go through each rule and process
|
|
GetGlobalRules(xmlRoot.Descendants(RewriteTags.GlobalRules), rules);
|
|
GetRules(xmlRoot.Descendants(RewriteTags.Rules), rules);
|
|
}
|
|
return rules;
|
|
}
|
|
|
|
private static void GetGlobalRules(IEnumerable<XElement> globalRules, List<UrlRewriteRule> result)
|
|
{
|
|
foreach (var rule in globalRules.Elements(RewriteTags.Rule) ?? Enumerable.Empty<XElement>())
|
|
{
|
|
var res = new UrlRewriteRule();
|
|
SetRuleAttributes(rule, res);
|
|
// TODO handle full url with global rules - may or may not support
|
|
res.Action = CreateUrlAction(rule.Element(RewriteTags.Action));
|
|
result.Add(res);
|
|
}
|
|
}
|
|
|
|
private static void GetRules(IEnumerable<XElement> rules, List<UrlRewriteRule> result)
|
|
{
|
|
// TODO Better null check?
|
|
foreach (var rule in rules.Elements(RewriteTags.Rule) ?? Enumerable.Empty<XElement>())
|
|
{
|
|
var res = new UrlRewriteRule();
|
|
SetRuleAttributes(rule, res);
|
|
res.Action = CreateUrlAction(rule.Element(RewriteTags.Action));
|
|
result.Add(res);
|
|
}
|
|
}
|
|
|
|
private static void SetRuleAttributes(XElement rule, UrlRewriteRule res)
|
|
{
|
|
if (rule == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
res.Name = rule.Attribute(RewriteTags.Name)?.Value;
|
|
|
|
bool enabled;
|
|
if (bool.TryParse(rule.Attribute(RewriteTags.Enabled)?.Value, out enabled))
|
|
{
|
|
res.Enabled = enabled;
|
|
}
|
|
|
|
PatternSyntax patternSyntax;
|
|
if (Enum.TryParse(rule.Attribute(RewriteTags.PatternSyntax)?.Value, out patternSyntax))
|
|
{
|
|
res.PatternSyntax = patternSyntax;
|
|
}
|
|
|
|
bool stopProcessing;
|
|
if (bool.TryParse(rule.Attribute(RewriteTags.StopProcessing)?.Value, out stopProcessing))
|
|
{
|
|
res.StopProcessing = stopProcessing;
|
|
}
|
|
|
|
res.Match = CreateMatch(rule.Element(RewriteTags.Match));
|
|
res.Conditions = CreateConditions(rule.Element(RewriteTags.Conditions));
|
|
}
|
|
|
|
private static InitialMatch CreateMatch(XElement match)
|
|
{
|
|
if (match == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var matchRes = new InitialMatch();
|
|
|
|
bool parBool;
|
|
if (bool.TryParse(match.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool))
|
|
{
|
|
matchRes.IgnoreCase = parBool;
|
|
}
|
|
|
|
if (bool.TryParse(match.Attribute(RewriteTags.Negate)?.Value, out parBool))
|
|
{
|
|
matchRes.Negate = parBool;
|
|
}
|
|
|
|
var parsedInputString = match.Attribute(RewriteTags.Url)?.Value;
|
|
|
|
if (matchRes.IgnoreCase)
|
|
{
|
|
matchRes.Url = new Regex(parsedInputString, RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout);
|
|
}
|
|
else
|
|
{
|
|
matchRes.Url = new Regex(parsedInputString, RegexOptions.Compiled, RegexTimeout);
|
|
}
|
|
return matchRes;
|
|
}
|
|
|
|
|
|
private static Conditions CreateConditions(XElement conditions)
|
|
{
|
|
var condRes = new Conditions();
|
|
if (conditions == null)
|
|
{
|
|
return condRes; // TODO make sure no null exception on Conditions
|
|
}
|
|
|
|
LogicalGrouping grouping;
|
|
if (Enum.TryParse(conditions.Attribute(RewriteTags.MatchType)?.Value, out grouping))
|
|
{
|
|
condRes.MatchType = grouping;
|
|
}
|
|
|
|
bool parBool;
|
|
if (bool.TryParse(conditions.Attribute(RewriteTags.TrackingAllCaptures)?.Value, out parBool))
|
|
{
|
|
condRes.TrackingAllCaptures = parBool;
|
|
}
|
|
|
|
foreach (var cond in conditions.Elements(RewriteTags.Add))
|
|
{
|
|
condRes.ConditionList.Add(CreateCondition(cond));
|
|
}
|
|
return condRes;
|
|
}
|
|
|
|
private static Condition CreateCondition(XElement condition)
|
|
{
|
|
if (condition == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var condRes = new Condition();
|
|
|
|
bool parBool;
|
|
if (bool.TryParse(condition.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool))
|
|
{
|
|
condRes.IgnoreCase = parBool;
|
|
}
|
|
|
|
if (bool.TryParse(condition.Attribute(RewriteTags.Negate)?.Value, out parBool))
|
|
{
|
|
condRes.Negate = parBool;
|
|
}
|
|
|
|
MatchType matchType;
|
|
if (Enum.TryParse(condition.Attribute(RewriteTags.MatchPattern)?.Value, out matchType))
|
|
{
|
|
condRes.MatchType = matchType;
|
|
}
|
|
|
|
var parsedInputString = condition.Attribute(RewriteTags.Input)?.Value;
|
|
if (parsedInputString != null)
|
|
{
|
|
condRes.Input = InputParser.ParseInputString(parsedInputString);
|
|
}
|
|
|
|
parsedInputString = condition.Attribute(RewriteTags.Pattern)?.Value;
|
|
|
|
if (condRes.IgnoreCase)
|
|
{
|
|
condRes.MatchPattern = new Regex(parsedInputString, RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout);
|
|
}
|
|
else
|
|
{
|
|
condRes.MatchPattern = new Regex(parsedInputString, RegexOptions.Compiled, RegexTimeout);
|
|
}
|
|
return condRes;
|
|
}
|
|
|
|
private static UrlAction CreateUrlAction(XElement urlAction)
|
|
{
|
|
if (urlAction == null)
|
|
{
|
|
throw new FormatException("Action is a required element of a rule.");
|
|
}
|
|
var actionRes = new UrlAction();
|
|
|
|
ActionType actionType;
|
|
if (Enum.TryParse(urlAction.Attribute(RewriteTags.Type)?.Value, out actionType))
|
|
{
|
|
actionRes.Type = actionType;
|
|
}
|
|
|
|
bool parseBool;
|
|
if (bool.TryParse(urlAction.Attribute(RewriteTags.AppendQuery)?.Value, out parseBool))
|
|
{
|
|
actionRes.AppendQueryString = parseBool;
|
|
}
|
|
|
|
if (bool.TryParse(urlAction.Attribute(RewriteTags.LogRewrittenUrl)?.Value, out parseBool))
|
|
{
|
|
actionRes.LogRewrittenUrl = parseBool;
|
|
}
|
|
|
|
RedirectType redirectType;
|
|
if (Enum.TryParse(urlAction.Attribute(RewriteTags.RedirectType)?.Value, out redirectType))
|
|
{
|
|
actionRes.RedirectType = redirectType;
|
|
}
|
|
|
|
actionRes.Url = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value);
|
|
return actionRes;
|
|
}
|
|
}
|
|
}
|