/// <summary> /// Initializes a new instance of the <see cref="ConditionContext"/> class. /// </summary> /// <param name="index">The index.</param> /// <param name="ruleContext">The rule context.</param> /// <param name="condition">The condition.</param> public ConditionContext(int index, RuleContext ruleContext, ICondition condition) : base(ruleContext) { if (condition == null) { throw new ArgumentNullException("condition"); } ConditionIndex = index; LogCategory = "Condition " + index; CurrentCondition = condition; }
public string GetValue(string input, RuleContext context) { var startIndex = 1; for (var i = 0; i < context.Conditions.Count; i++) { var cond = context.Conditions[i]; var groupCount = cond.Pattern.GetGroupCount(input); var condContext = new ConditionContext(i, context, cond); if ((startIndex + groupCount) >= Index) { var varIndex = Math.Abs(startIndex - _index); return cond.Pattern.GetValue(cond.Test.GetValue(condContext), varIndex, condContext); } startIndex += groupCount; } return null; }
/// <summary> /// Runs the rules. /// </summary> /// <param name="httpContext">The HTTP context.</param> /// <param name="url">The URL.</param> /// <returns> /// Returns a rewritten <see cref="System.Uri"/>, or a value of <see langword="null"/> if no rewriting was done to <paramref name="url"/>. /// </returns> public Uri RunRules(HttpContextBase httpContext, Uri url) { var context = new RuleSetContext(this, url, httpContext); var currentUrl = url; if (!EngineEnabled) { Logger.Info("Rewrite Engine Is DISABLED"); } if (_rules.Count > 0 && EngineEnabled) { Logger.InfoFormat("Input: " + currentUrl); // check if max number of internal transfers have been exceeded if (InternalTransferCount(httpContext) > MaxInternalTransfers) { string message = "Exceeded the max number of internal transfers."; throw new HttpException(500, message); } IRuleFlagProcessor temporyFlags = null; var skipNextChain = false; var initialUrl = currentUrl; if (!string.IsNullOrEmpty(VirtualBase) && VirtualBase != "/") { currentUrl = RemoveBase(VirtualBase, currentUrl); } // process rules according to their settings for (var i = 0; i < _rules.Count; i++) { var ruleContext = new RuleContext(i, context, currentUrl, _rules[i]); temporyFlags = _rules[i].Flags; // continue if this rule shouldn't be processed because it doesn't allow internal transfer requests if (RuleFlagsProcessor.HasNotForInternalSubRequests(temporyFlags) && IsInternalTransfer(httpContext)) { continue; } var containsChain = RuleFlagsProcessor.HasChain(_rules[i].Flags); var previousContainsChain = RuleFlagsProcessor.HasChain(_rules[Math.Max(0, i - 1)].Flags); // if the previous rule doesn't contain a chain flag then set the initial URL // this will be used to reset a chain if one of the chain rules fail if (!previousContainsChain) { initialUrl = currentUrl; } // skip if the current rule or the last rule has a chain flag // and if the skip next chain is set if (skipNextChain && (previousContainsChain || containsChain)) { continue; } else { skipNextChain = false; } if (_rules[i].TryExecute(ruleContext)) { var flagResponse = temporyFlags.Apply(ruleContext); currentUrl = ruleContext.SubstitutedUrl; i = ruleContext.RuleIndex ?? -1; var breakLoop = false; // apply the flags to the rules, and only do special processing // for the flag responses listed in the switch statement below switch (flagResponse) { case RuleFlagProcessorResponse.ExitRuleSet: return null; case RuleFlagProcessorResponse.LastRule: breakLoop = true; break; } // break the loop because we have reached the last rule as indicated by a flag if (breakLoop) { break; } } else if (containsChain) { skipNextChain = true; // reset the current URL back to the initial URL from the start of the chain currentUrl = initialUrl; } else if (previousContainsChain) { // reset the current URL back to the initial URL from the start of the chain currentUrl = initialUrl; } } if (!string.IsNullOrEmpty(VirtualBase) && VirtualBase != "/") { currentUrl = AddBase(VirtualBase, currentUrl); } Logger.InfoFormat("Output: {0}", currentUrl); } // if the http request url matches for both the request and the rewrite no work was done so the url should be null if (Uri.Compare(currentUrl, url, UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped, StringComparison.OrdinalIgnoreCase) == 0) { currentUrl = null; } return currentUrl; }
/// <summary> /// Initializes a new instance of the <see cref="RuleContext"/> class. /// </summary> /// <param name="copy">The copy.</param> internal RuleContext(RuleContext copy) : base(copy) { RuleIndex = copy.RuleIndex; LogCategory = copy.LogCategory; _currentContent = copy._currentContent; _substitutedContent = copy.SubstitutedContent; CurrentUrl = copy.CurrentUrl; _substitutedUrl = copy.SubstitutedUrl; CurrentRule = copy.CurrentRule; }
/// <summary> /// /// </summary> /// <param name="httpContext"></param> /// <param name="content"></param> /// <returns></returns> public byte[] RunOutputRules(HttpContextBase httpContext, byte[] content) { var context = new RuleSetContext(this, content, httpContext); var currentContent = content; if (!EngineEnabled) { Logger.Info("Rewrite Engine Is DISABLED"); } if (_outputRules.Count > 0 && EngineEnabled) { IRuleFlagProcessor temporyFlags = null; var skipNextChain = false; var initialContent = currentContent; // process rules according to their settings for (var i = 0; i < _outputRules.Count; i++) { var ruleContext = new RuleContext(i, context, currentContent, _outputRules[i]); temporyFlags = _outputRules[i].Flags; var containsChain = RuleFlagsProcessor.HasChain(_outputRules[i].Flags); var previousContainsChain = RuleFlagsProcessor.HasChain(_outputRules[Math.Max(0, i - 1)].Flags); // if the previous rule doesn't contain a chain flag then set the initial URL // this will be used to reset a chain if one of the chain rules fail if (!previousContainsChain) { initialContent = currentContent; } // skip if the current rule or the last rule has a chain flag // and if the skip next chain is set if (skipNextChain && (previousContainsChain || containsChain)) { continue; } else { skipNextChain = false; } if (_outputRules[i].TryExecute(ruleContext)) { var flagResponse = temporyFlags.Apply(ruleContext); currentContent = ruleContext.SubstitutedContent; i = ruleContext.RuleIndex ?? -1; var breakLoop = false; // apply the flags to the rules, and only do special processing // for the flag responses listed in the switch statement below switch (flagResponse) { case RuleFlagProcessorResponse.ExitRuleSet: return null; case RuleFlagProcessorResponse.LastRule: breakLoop = true; break; } // break the loop because we have reached the last rule as indicated by a flag if (breakLoop) { break; } } else if (containsChain) { skipNextChain = true; // reset the current URL back to the initial URL from the start of the chain currentContent = initialContent; } else if (previousContainsChain) { // reset the current URL back to the initial URL from the start of the chain currentContent = initialContent; } } } return currentContent; }
/// <summary> /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>. /// </summary> /// <returns> /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>. /// </returns> public string ToString(RuleContext context) { return Replace(ToString(false), context); }
/// <summary> /// Replaces the specified input for a rule variable. /// </summary> /// <param name="input">The input.</param> /// <param name="replacement">The replacement.</param> /// <param name="context">The context.</param> /// <returns></returns> public string Replace(string input, string replacement, RuleContext context) { if (context != null) { replacement = Variables.Replace(replacement, match => { if (match.Groups["condvar"].Success) { var condVar = GetConditionVariable(match); return condVar.GetValue(input, context); } else if (match.Groups["servervar"].Success) { var serverVar = GetServerVariable(match); return serverVar.GetValue(input, context); } return match.Value; }); } return _pattern.Replace(input, replacement); }
/// <summary> /// Determines whether the specified input is match. /// </summary> /// <param name="input">The input.</param> /// <param name="context">The context.</param> /// <returns> /// <see langword="true"/> if the specified input is match; otherwise, <see langword="false"/>. /// </returns> public bool IsMatch(string input, RuleContext context) { // if the input contains a rule or a condition placeholders that need to be // replaced from the input URL it needs to be processed by the rule pattern // before we can check if it is a match if (input.IndexOfAny(new[] { '%', '$' }) >= 0) { input = Replace(input, context); } return IsMatch(input); }
/// <summary> /// Gets the value. /// </summary> /// <param name="input">The input.</param> /// <param name="index">The index.</param> /// <param name="context">The context.</param> /// <returns>Returns the value of the pattern for the <paramref name="index"/></returns> public string GetValue(string input, int index, RuleContext context) { return GetValue(input, index); }