diff --git a/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Configuration/InboundRules/InboundRuleElement.cs b/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Configuration/InboundRules/InboundRuleElement.cs index 3cc9db1..8847440 100644 --- a/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Configuration/InboundRules/InboundRuleElement.cs +++ b/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Configuration/InboundRules/InboundRuleElement.cs @@ -6,6 +6,7 @@ namespace Microsoft.IIS.Administration.WebServer.UrlRewrite { sealed class InboundRule : RuleElement { + public const string RedirectTypeAttribute = "redirectType"; public const string ResponseCacheDirectiveAttribute = "responseCacheDirective"; private InboundActionElement _action; diff --git a/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Configuration/Rule/LogicalGrouping.cs b/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Configuration/Rule/LogicalGrouping.cs index 15a5e17..2c59266 100644 --- a/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Configuration/Rule/LogicalGrouping.cs +++ b/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Configuration/Rule/LogicalGrouping.cs @@ -4,12 +4,40 @@ namespace Microsoft.IIS.Administration.WebServer.UrlRewrite { + using Microsoft.IIS.Administration.Core; + using System; + // Keep public for resolution of enums from 'dynamic' types in helper classes i.e. DynamicHelper public enum LogicalGrouping { - MatchAll = 0, - MatchAny = 1, } + + static class LogicalGroupingHelper + { + public static string ToJsonModel(LogicalGrouping logicalGrouping) + { + switch (logicalGrouping) { + case LogicalGrouping.MatchAll: + return "match_all"; + case LogicalGrouping.MatchAny: + return "match_any"; + default: + throw new ArgumentException(nameof(logicalGrouping)); + } + } + + public static LogicalGrouping FromJsonModel(string model) + { + switch (model.ToLowerInvariant()) { + case "match_all": + return LogicalGrouping.MatchAll; + case "match_any": + return LogicalGrouping.MatchAny; + default: + throw new ApiArgumentException("condition_match_constraints"); + } + } + } } diff --git a/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Helpers/GlobalRulesHelper.cs b/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Helpers/GlobalRulesHelper.cs index b09ba31..ee884a1 100644 --- a/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Helpers/GlobalRulesHelper.cs +++ b/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Helpers/GlobalRulesHelper.cs @@ -174,15 +174,23 @@ namespace Microsoft.IIS.Administration.WebServer.UrlRewrite // // action if (fields.Exists("action")) { - obj.action = new { - type = ActionTypeHelper.ToJsonModel(rule.Action.Type), - url = rule.Action.Url, - append_query_string = rule.Action.AppendQueryString, - status_code = rule.Action.StatusCode, - sub_status_code = rule.Action.SubStatusCode, - description = rule.Action.StatusDescription, - reason = rule.Action.StatusReason - }; + obj.action = new ExpandoObject(); + dynamic action = obj.action; + + action.type = ActionTypeHelper.ToJsonModel(rule.Action.Type); + action.url = rule.Action.Url; + action.append_query_string = rule.Action.AppendQueryString; + + if (rule.Action.Type == ActionType.Redirect) { + action.redirect_type = Enum.GetName(typeof(RedirectType), rule.Action.RedirectType).ToLowerInvariant(); + } + + if (rule.Action.Type == ActionType.CustomResponse) { + action.status_code = rule.Action.StatusCode; + action.sub_status_code = rule.Action.SubStatusCode; + action.description = rule.Action.StatusDescription; + action.reason = rule.Action.StatusReason; + } } // @@ -195,6 +203,18 @@ namespace Microsoft.IIS.Administration.WebServer.UrlRewrite }); } + // + // condition_match_constraints + if (fields.Exists("condition_match_constraints")) { + obj.condition_match_constraints = LogicalGroupingHelper.ToJsonModel(rule.Conditions.LogicalGrouping); + } + + // + // track_all_captures + if (fields.Exists("track_all_captures")) { + obj.track_all_captures = rule.Conditions.TrackAllCaptures; + } + // // conditions if (fields.Exists("conditions")) { @@ -381,6 +401,7 @@ namespace Microsoft.IIS.Administration.WebServer.UrlRewrite DynamicHelper.If((object)action.sub_status_code, v => rule.Action.SubStatusCode = v); DynamicHelper.If((object)action.description, v => rule.Action.StatusDescription = v); DynamicHelper.If((object)action.reason, v => rule.Action.StatusReason = v); + DynamicHelper.If((object)action.redirect_type, v => rule.Action.RedirectType = v); } // @@ -421,6 +442,9 @@ namespace Microsoft.IIS.Administration.WebServer.UrlRewrite } } + DynamicHelper.If((object)model.condition_match_constraints, v => rule.Conditions.LogicalGrouping = LogicalGroupingHelper.FromJsonModel(v)); + DynamicHelper.If((object)model.track_all_captures, v => rule.Conditions.TrackAllCaptures = v); + // // Conditions if (model.conditions != null) { diff --git a/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Helpers/InboundRulesHelper.cs b/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Helpers/InboundRulesHelper.cs index 9467c3a..232973c 100644 --- a/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Helpers/InboundRulesHelper.cs +++ b/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Helpers/InboundRulesHelper.cs @@ -158,15 +158,24 @@ namespace Microsoft.IIS.Administration.WebServer.UrlRewrite // // action if (fields.Exists("action")) { - obj.action = new { - type = ActionTypeHelper.ToJsonModel(rule.Action.Type), - url = rule.Action.Url, - append_query_string = rule.Action.AppendQueryString, - status_code = rule.Action.StatusCode, - sub_status_code = rule.Action.SubStatusCode, - description = rule.Action.StatusDescription, - reason = rule.Action.StatusReason - }; + obj.action = new ExpandoObject(); + dynamic action = obj.action; + + action.type = ActionTypeHelper.ToJsonModel(rule.Action.Type); + action.url = rule.Action.Url; + action.append_query_string = rule.Action.AppendQueryString; + action.log_rewritten_url = rule.Action.LogRewrittenUrl; + + if (rule.Action.Type == ActionType.Redirect) { + action.redirect_type = Enum.GetName(typeof(RedirectType), rule.Action.RedirectType).ToLowerInvariant(); + } + + if (rule.Action.Type == ActionType.CustomResponse) { + action.status_code = rule.Action.StatusCode; + action.sub_status_code = rule.Action.SubStatusCode; + action.description = rule.Action.StatusDescription; + action.reason = rule.Action.StatusReason; + } } // @@ -179,6 +188,18 @@ namespace Microsoft.IIS.Administration.WebServer.UrlRewrite }); } + // + // condition_match_constraints + if (fields.Exists("condition_match_constraints")) { + obj.condition_match_constraints = LogicalGroupingHelper.ToJsonModel(rule.Conditions.LogicalGrouping); + } + + // + // track_all_captures + if (fields.Exists("track_all_captures")) { + obj.track_all_captures = rule.Conditions.TrackAllCaptures; + } + // // conditions if (fields.Exists("conditions")) { @@ -397,10 +418,12 @@ namespace Microsoft.IIS.Administration.WebServer.UrlRewrite DynamicHelper.If((object)action.type, v => rule.Action.Type = ActionTypeHelper.FromJsonModel(v)); DynamicHelper.If((object)action.url, v => rule.Action.Url = v); DynamicHelper.If((object)action.append_query_string, v => rule.Action.AppendQueryString = v); + DynamicHelper.If((object)action.log_rewritten_url, v => rule.Action.LogRewrittenUrl = v); DynamicHelper.If((object)action.status_code, v => rule.Action.StatusCode = v); DynamicHelper.If((object)action.sub_status_code, v => rule.Action.SubStatusCode = v); DynamicHelper.If((object)action.description, v => rule.Action.StatusDescription = v); DynamicHelper.If((object)action.reason, v => rule.Action.StatusReason = v); + DynamicHelper.If((object)action.redirect_type, v => rule.Action.RedirectType = v); } // @@ -443,6 +466,9 @@ namespace Microsoft.IIS.Administration.WebServer.UrlRewrite } } + DynamicHelper.If((object)model.condition_match_constraints, v => rule.Conditions.LogicalGrouping = LogicalGroupingHelper.FromJsonModel(v)); + DynamicHelper.If((object)model.track_all_captures, v => rule.Conditions.TrackAllCaptures = v); + // // Conditions if (model.conditions != null) { diff --git a/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Helpers/OutboundRulesHelper.cs b/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Helpers/OutboundRulesHelper.cs index f00fed9..3897197 100644 --- a/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Helpers/OutboundRulesHelper.cs +++ b/src/Microsoft.IIS.Administration.WebServer.UrlRewrite/Helpers/OutboundRulesHelper.cs @@ -345,6 +345,18 @@ namespace Microsoft.IIS.Administration.WebServer.UrlRewrite obj.replace_server_variable = rule.Action.ReplaceServerVariable; } + // + // condition_match_constraints + if (fields.Exists("condition_match_constraints")) { + obj.condition_match_constraints = LogicalGroupingHelper.ToJsonModel(rule.Conditions.LogicalGrouping); + } + + // + // track_all_captures + if (fields.Exists("track_all_captures")) { + obj.track_all_captures = rule.Conditions.TrackAllCaptures; + } + // // conditions if (fields.Exists("conditions")) { @@ -771,6 +783,9 @@ namespace Microsoft.IIS.Administration.WebServer.UrlRewrite rule.PreCondition = pc.Name; } + DynamicHelper.If((object)model.condition_match_constraints, v => rule.Conditions.LogicalGrouping = LogicalGroupingHelper.FromJsonModel(v)); + DynamicHelper.If((object)model.track_all_captures, v => rule.Conditions.TrackAllCaptures = v); + // // Conditions if (model.conditions != null) { diff --git a/test/Microsoft.IIS.Administration.Tests/UrlRewrite.cs b/test/Microsoft.IIS.Administration.Tests/UrlRewrite.cs index 7646afb..e64a6fb 100644 --- a/test/Microsoft.IIS.Administration.Tests/UrlRewrite.cs +++ b/test/Microsoft.IIS.Administration.Tests/UrlRewrite.cs @@ -63,8 +63,7 @@ namespace Microsoft.IIS.Administration.Tests type = "rewrite", url = "def.aspx?a={R:1}&c={R:2}", append_query_string = true, - description = "A test rule", - reason = "Replace url" + log_rewritten_url = true }, server_variables = new object[] { new { @@ -73,6 +72,8 @@ namespace Microsoft.IIS.Administration.Tests replace = true } }, + condition_match_constraints = "match_any", + track_all_captures = false, conditions = new object[] { new { input = "{REQUEST_FILENAME}", @@ -102,8 +103,8 @@ namespace Microsoft.IIS.Administration.Tests type = "redirect", url = "def.aspx", append_query_string = false, - description = "A test rule2", - reason = "Replace url2" + log_rewritten_url = false, + redirect_type = "found" }, server_variables = new object[] { new { @@ -112,6 +113,8 @@ namespace Microsoft.IIS.Administration.Tests replace = false } }, + condition_match_constraints = "match_all", + track_all_captures = true, conditions = new object[] { new { input = "{REQUEST_FILENAME}2", @@ -168,9 +171,8 @@ namespace Microsoft.IIS.Administration.Tests action = new { type = "rewrite", url = "def.aspx?a={R:1}&c={R:2}", - append_query_string = true, - description = "A test rule", - reason = "Replace url" + append_query_string = true + // log_rewritten_url not present in schema for global rule }, server_variables = new object[] { new { @@ -179,6 +181,8 @@ namespace Microsoft.IIS.Administration.Tests replace = true } }, + condition_match_constraints = "match_any", + track_all_captures = true, conditions = new object[] { new { input = "{REQUEST_FILENAME}", @@ -208,8 +212,8 @@ namespace Microsoft.IIS.Administration.Tests type = "redirect", url = "def.aspx", append_query_string = false, - description = "A test rule2", - reason = "Replace url2" + redirect_type = "found" + // log_rewritten_url not present in schema for global rule }, server_variables = new object[] { new { @@ -218,6 +222,8 @@ namespace Microsoft.IIS.Administration.Tests replace = false } }, + condition_match_constraints = "match_all", + track_all_captures = false, conditions = new object[] { new { input = "{REQUEST_FILENAME}2", @@ -544,6 +550,8 @@ namespace Microsoft.IIS.Administration.Tests negate = true, stop_processing = false, rewrite_value = "test rewrite value", + condition_match_constraints = "match_any", + track_all_captures = true, conditions = new object[] { new { input = "{URL}", @@ -575,6 +583,8 @@ namespace Microsoft.IIS.Administration.Tests negate = false, stop_processing = true, rewrite_value = "test rewrite update", + condition_match_constraints = "match_all", + track_all_captures = false, conditions = new object[] { new { input = "{CONTENT_TYPE}", @@ -728,6 +738,8 @@ namespace Microsoft.IIS.Administration.Tests Assert.Equal(a.Value("ignore_case"), b.Value("ignore_case")); Assert.Equal(a.Value("negate"), b.Value("negate")); Assert.Equal(a.Value("stop_processing"), b.Value("stop_processing")); + Assert.Equal(a.Value("condition_match_constraints"), b.Value("condition_match_constraints")); + Assert.Equal(a.Value("track_all_captures"), b.Value("track_all_captures")); JObject action = a.Value("action"); JObject resultAction = b.Value("action"); @@ -735,8 +747,22 @@ namespace Microsoft.IIS.Administration.Tests Assert.Equal(action.Value("type"), resultAction.Value("type")); Assert.Equal(action.Value("append_query_string"), resultAction.Value("append_query_string")); Assert.Equal(action.Value("url"), resultAction.Value("url")); - Assert.Equal(action.Value("description"), resultAction.Value("description")); - Assert.Equal(action.Value("reason"), resultAction.Value("reason")); + Assert.Equal(action.Value("log_rewritten_url"), resultAction.Value("log_rewritten_url")); + + // + // redirect rule + if (action.Value("type").Equals("redirect", StringComparison.OrdinalIgnoreCase)) { + Assert.Equal(action.Value("redirect_type"), resultAction.Value("redirect_type")); + } + + // + // custom response rule + if (action.Value("type").Equals("custom_response", StringComparison.OrdinalIgnoreCase)) { + Assert.Equal(action.Value("description"), resultAction.Value("description")); + Assert.Equal(action.Value("reason"), resultAction.Value("reason")); + Assert.Equal(action.Value("status_code"), resultAction.Value("status_code")); + Assert.Equal(action.Value("sub_status_code"), resultAction.Value("sub_status_code")); + } JObject[] aServerVariables = a["server_variables"].ToObject(); JObject[] bServerVariables = b["server_variables"].ToObject(); @@ -856,6 +882,8 @@ namespace Microsoft.IIS.Administration.Tests Assert.Equal(a.Value("negate"), b.Value("negate")); Assert.Equal(a.Value("stop_processing"), b.Value("stop_processing")); Assert.Equal(a.Value("rewrite_value"), b.Value("rewrite_value")); + Assert.Equal(a.Value("condition_match_constraints"), b.Value("condition_match_constraints")); + Assert.Equal(a.Value("track_all_captures"), b.Value("track_all_captures")); // // Conditions