AspNetCore.Docs icon indicating copy to clipboard operation
AspNetCore.Docs copied to clipboard

AddIISUrlRewrite - Condition must have an associated match / .NET Framework URL Rewrite equivalence.

Open MarkMcDonald opened this issue 3 years ago • 1 comments

Issue description

I'm migrating a small web app, in particular trying to migrate the existing URL Rewrite rules. It isn't clear if the dotnet 6 .AddIISUrlRewrite should have directly equivalent processing as the Rewrite module in .NET Framework - but I encountered an instance where it doesn't so I though I would flag.

On migrating an existing set of IIS Rewrite rule from a working .NET Framework application we get the error:

Microsoft.AspNetCore.Rewrite.IISUrlRewrite.InvalidUrlRewriteFormatException HResult=0x80131537 Message=Could not parse the UrlRewrite file. Message: 'Condition must have an associated match'. Line number '3': '4'. Source=Microsoft.AspNetCore.Rewrite StackTrace: at Microsoft.AspNetCore.Rewrite.IISUrlRewrite.UrlRewriteFileParser.ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder) at Microsoft.AspNetCore.Rewrite.IISUrlRewrite.UrlRewriteFileParser.ParseRules(XElement rules, IList`1 result, Boolean global) at Microsoft.AspNetCore.Rewrite.IISUrlRewrite.UrlRewriteFileParser.Parse(TextReader reader, Boolean alwaysUseManagedServerVariables) at Microsoft.AspNetCore.Rewrite.IISUrlRewriteOptionsExtensions.AddIISUrlRewrite(RewriteOptions options, TextReader reader, Boolean alwaysUseManagedServerVariables) at Program.<Main>$(String[] args)

I believe the cause is the following section:

<rewrite>
	<rules>
		<rule name="Whitelist" stopProcessing="true">
			<conditions logicalGrouping="MatchAny" trackAllCaptures="false">
				<add input="{REQUEST_FILENAME}" pattern="(.*?)\.gif$" />
				<add input="{REQUEST_FILENAME}" pattern="(.*?)\.png$" />
				<add input="{REQUEST_FILENAME}" pattern="(.*?)\.css$" />
				<add input="{REQUEST_FILENAME}" pattern="(.*?)\.js$" />
				<add input="{REQUEST_FILENAME}" pattern="(.*?)\.jpg$" />
				<add input="{REQUEST_FILENAME}" pattern="(.*?)\.jpeg$" />
				<add input="{REQUEST_FILENAME}" pattern="(.*?)\.svg$" />
				<add input="{REQUEST_FILENAME}" pattern="(.*?)\.axd$" />
				<add input="{REQUEST_URI}" pattern="^(/-/).*$" ignoreCase="true" />
				<add input="{REQUEST_URI}" pattern="^(/content/).*$" ignoreCase="true" />
				<add input="{REQUEST_URI}" pattern="^(/layouts/).*$" ignoreCase="true" />
				<add input="{REQUEST_URI}" pattern="^(/sitecore).*$" ignoreCase="true" />
				<add input="{REQUEST_URI}" pattern="^(/ui/).*$" ignoreCase="true" />
				<add input="{HTTP_METHOD}" pattern="GET" negate="true" />
			</conditions>
			<action type="None" />
		</rule>
	</rules>
    ....
</rewrite>

In .NET Framework applications we typically use this to prevent processing particular URLs as an ignore list, often used with CMS systems where we have no control over certain URLs. It would be nice if this would work in dotnet 6 as it does with IIS / .NET Framework, as it would help with porting applications across the different frameworks.

Software versions

.NET 6

MarkMcDonald avatar Aug 26 '22 09:08 MarkMcDonald

Even removing this rule we also get other errors based on previously working URL Rewrite rules:

System.FormatException HResult=0x80131537 Message=Unrecognized parameter type: 'HTTP_METHOD', terminated at string index: '12' Source=Microsoft.AspNetCore.Rewrite StackTrace: at Microsoft.AspNetCore.Rewrite.IISUrlRewrite.ServerVariables.FindServerVariable(String serverVariable, ParserContext context, UriMatchPart uriMatchPart, Boolean alwaysUseManagedServerVariables) at Microsoft.AspNetCore.Rewrite.IISUrlRewrite.InputParser.ParseParameter(ParserContext context, IList1 results, UriMatchPart uriMatchPart) at Microsoft.AspNetCore.Rewrite.IISUrlRewrite.InputParser.ParseString(ParserContext context, UriMatchPart uriMatchPart) at Microsoft.AspNetCore.Rewrite.IISUrlRewrite.InputParser.ParseInputString(String testString, UriMatchPart uriMatchPart) at Microsoft.AspNetCore.Rewrite.IISUrlRewrite.UrlRewriteFileParser.ParseCondition(XElement conditionElement, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) at Microsoft.AspNetCore.Rewrite.IISUrlRewrite.UrlRewriteFileParser.ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) at Microsoft.AspNetCore.Rewrite.IISUrlRewrite.UrlRewriteFileParser.ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder) at Microsoft.AspNetCore.Rewrite.IISUrlRewrite.UrlRewriteFileParser.ParseRules(XElement rules, IList1 result, Boolean global) at Microsoft.AspNetCore.Rewrite.IISUrlRewrite.UrlRewriteFileParser.Parse(TextReader reader, Boolean alwaysUseManagedServerVariables) at Microsoft.AspNetCore.Rewrite.IISUrlRewriteOptionsExtensions.AddIISUrlRewrite(RewriteOptions options, TextReader reader, Boolean alwaysUseManagedServerVariables) at Program.<Main>$(String[] args)

Which I believe corresponds to:

		<rule name="Redirect" enabled="true" stopProcessing="true">
			<match url="^(_+)(.*)$" />
			<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
				<add input="{HTTP_METHOD}" pattern="GET" />
			</conditions>
			<action type="Redirect" url="http://{HTTP_HOST}/{R:2}" />
		</rule>

This is a rule that has often been used in some form or another to prevent things like case based redirection to POST or PUT requests which may cause the post to fail.

MarkMcDonald avatar Aug 26 '22 10:08 MarkMcDonald

It isn't clear if the dotnet 6 .AddIISUrlRewrite should have directly equivalent processing as the Rewrite module in .NET Framework

You're correct, they don't.

Rick-Anderson avatar Sep 30 '22 03:09 Rick-Anderson