richard.herbert
06/16/2022, 2:08 PMweb.config
file to use the CommandBox
Undertow Server Rules in my server.json
file.
I’ve managed to sort the simple rewrites but I seem to be failing with the regex rules. I have a request to /44423ee780249169596c419e18f13e15/stocklist/
which I think is being caught by this rule in IIS...
<rule name="stocklist filters" enabled="true" stopProcessing="true">
<match url="^([0-9a-z]+)/stocklist/([^/]+)/?$" />
<action type="Rewrite" url="?page=stocklist&aId={R:1}&f={R:2}" />
</rule>
My conversion of this IIS rule to Undertow in my server.json
is...
"rules":[
"regex( '^([0-9a-z]+)/stocklist/([^/]+)/?$' ) -> rewrite( '?page=stocklist&aId={R:1}&f={R:2}' )"
]
...but it seems like the request just sails on pass this rewrite. The situation is a little more complicated as it’s part of a SSO request and callback but I’ve worked through the request and I’m sure this is the point where it’s coming apart.
Now plugging that regex into my favourite helper, the request /44423ee780249169596c419e18f13e15/stocklist/
isn’t being caught by ^([0-9a-z]+)/stocklist/([^/]+)/?$
and it says that the /
needs to be escaped with \/
but when I do that, the \/
is automatically replaced with /
in the server.json
when I start the server. Also I’m not sure what the ([^/]+)/?
part does at the end?
So in my regex helper, if I use ^\/([0-9a-z]+)\/stocklist\/([^\/]+)\/?$
that will match /44423ee780249169596c419e18f13e15/stocklist/foo
and if I use ^\/([0-9a-z]+)\/stocklist\/$
it will find /44423ee780249169596c419e18f13e15/stocklist/
So is IIS more tolerant than Undertow or have I got it all wrong (very possible!)?thisOldDave
06/16/2022, 2:22 PM/
([^/]+)/?$
means match anything that isnt a /
followed by an optional / upto the end of the url and save it
so if you url was 1234/stocklist/wibble
it would match and save wibble
or if it was 1234/stocklist/foobarbaz/
it would save foobarbaz
but if it was 1234/stocklist/wibble/blather
it wouldnt save anythingrichard.herbert
06/16/2022, 2:32 PMmatch url=
directly from the web.config
and dropped it into Undertow regex. I agree that starting the regex with ^\/([0-9
would match the incoming string but it’s strange, to me, that the regex is different.
For that last part, if there’s no trailing part the whole regex fails to match.richard.herbert
06/16/2022, 2:33 PMbdw429s
06/16/2022, 3:28 PMbdw429s
06/16/2022, 3:29 PMbdw429s
06/16/2022, 3:31 PMbdw429s
06/16/2022, 3:32 PMrichard.herbert
06/16/2022, 3:34 PMbdw429s
06/16/2022, 3:34 PMbdw429s
06/16/2022, 3:35 PMbdw429s
06/16/2022, 3:35 PMrichard.herbert
06/16/2022, 3:36 PMbdw429s
06/16/2022, 3:36 PMbdw429s
06/16/2022, 3:36 PMbdw429s
06/16/2022, 3:37 PMrichard.herbert
06/16/2022, 3:37 PMbdw429s
06/16/2022, 3:37 PMbdw429s
06/16/2022, 3:37 PMrichard.herbert
06/16/2022, 3:38 PMbdw429s
06/16/2022, 3:38 PMbdw429s
06/16/2022, 3:38 PMbdw429s
06/16/2022, 3:39 PMrichard.herbert
06/16/2022, 3:40 PMbdw429s
06/21/2022, 3:11 AMrichard.herbert
06/21/2022, 10:00 AM.htaccess
route which is a great alternative given the automatic polling of the file. So if I give you one example of my conversion I’d be grateful for your opinion.
This is a rule from the web.config
file…
<rule name="oidc_login_validation/" enabled="true" stopProcessing="true">
<match url="^oidc_login_validation/?$" />
<action type="Rewrite" url="/pages/system/oidc_login_validation.cfm?includeHeader=false&page=oidc_login_validation" />
</rule>
…and here is the section from my rewriteRules.txt
regex( pattern='^/oidc_login_validation/?$', case-sensitive=false ) -> rewrite( '/pages/system/oidc_login_validation.cfm?includeHeader=false&page=oidc_login_validation' )
…and this is my .htaccess
RewriteRule ^/oidc_logout_validation/?$ /pages/system/oidc_logout_validation.cfm?includeHeader=false&page=oidc_logout_validation
…which all seems fair.
The only part I’m not sure about is the stopProcessing="true"
and how I should implement that?richard.herbert
06/21/2022, 12:59 PM[L]
which I’ve added to stop it processingrichard.herbert
06/21/2022, 3:10 PM<rule name="redirect to vdp" enabled="true" stopProcessing="true">
<match url="^redirect/?$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{QUERY_STRING}" pattern="raId=(aeta[0-9]+)" />
<add input="{QUERY_STRING}" pattern="rvId=(aetv[0-9]+)" />
</conditions>
<action type="Rewrite" url="/pages/system/redirect.cfm?includeHeader=false&page=redirect" appendQueryString="true" />
</rule>
…this…
<rule name="LowerCase Rule" stopProcessing="true">
<match url="[A-Z]" ignoreCase="false" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{URL}" pattern="^.*\.(css|js|jpg|jpeg|png|gif|pdf|csv|xml|ttf|eot|svg|woff|ico|woff2|json|swf|xap|cfm)$" ignoreCase="true" negate="true" />
</conditions>
<action type="Redirect" url="{ToLower:{URL}}" redirectType="Permanent" />
</rule>
…and this…
<rule name="Add trailing slash" stopProcessing="false">
<match url="(.*[^/])$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{URL}" pattern="^.*\.(css|js|jpg|jpeg|png|gif|pdf|csv|xml|ttf|eot|svg|woff|ico|woff2|json|html|cfm|swf|xap|cfc|map|scss)$" ignoreCase="true" negate="true" />
</conditions>
<action type="Redirect" url="{R:1}/" redirectType="Permanent" />
</rule>
bdw429s
06/21/2022, 3:33 PMbdw429s
06/21/2022, 3:33 PMdone
handler in CommandBox's Server Rules (Undertow's Predicate Language)richard.herbert
06/21/2022, 3:33 PMhtaccess
bdw429s
06/21/2022, 3:34 PMbdw429s
06/21/2022, 3:34 PMbdw429s
06/21/2022, 3:35 PMdone
around as your custom rewrites fire before CommandBox internal rules. This was done to give you more power in overriding the internal rules, but it also allows you to short circuit the lockdown rulesbdw429s
06/21/2022, 3:35 PMlucee/admin
and then uses the done
handler, CommandBox automatic CF-lockdown rules will be skipped.bdw429s
06/21/2022, 3:35 PMbdw429s
06/21/2022, 3:36 PMdone
handler listed here under common handlers. Perhaps we can add a note that it's the equiv of the L
or "last" flag
https://commandbox.ortusbooks.com/embedded-server/configuring-your-server/server-rules/rule-language#common-handlersrichard.herbert
06/21/2022, 3:37 PMbdw429s
06/21/2022, 3:37 PM"regex( pattern='\.jws$', case-sensitive=false ) -> { set-error( 404 ); done }"
bdw429s
06/21/2022, 3:38 PMregex( pattern='\.jws$', case-sensitive=false ) -> {
set-error( 404 );
done
}
richard.herbert
06/21/2022, 3:38 PMbdw429s
06/21/2022, 3:38 PMrichard.herbert
06/21/2022, 3:38 PMrichard.herbert
06/21/2022, 3:40 PMbdw429s
06/21/2022, 3:54 PM<rule name="redirect to vdp" enabled="true" stopProcessing="true">
<match url="^redirect/?$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{QUERY_STRING}" pattern="raId=(aeta[0-9]+)" />
<add input="{QUERY_STRING}" pattern="rvId=(aetv[0-9]+)" />
</conditions>
<action type="Rewrite" url="/pages/system/redirect.cfm?includeHeader=false&page=redirect" appendQueryString="true" />
</rule>
You're not needing to track the captures, so this could be accomplished with 3 checks like so: (untested)
regex( "^redirect/?$" )
and regex( value="%{QUERY_STRING}", pattern="raId=(aeta[0-9]+)" )
and regex( value="%{QUERY_STRING}", pattern="rvId=(aetv[0-9]+)" )
-> rewrite( "/pages/system/redirect.cfm?includeHeader=false&page=redirect" )
(The rewrite handler should automatically append the query string you provide to the existing one)bdw429s
06/21/2022, 3:57 PM<rule name="LowerCase Rule" stopProcessing="true">
<match url="[A-Z]" ignoreCase="false" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{URL}" pattern="^.*\.(css|js|jpg|jpeg|png|gif|pdf|csv|xml|ttf|eot|svg|woff|ico|woff2|json|swf|xap|cfm)$" ignoreCase="true" negate="true" />
</conditions>
<action type="Redirect" url="{ToLower:{URL}}" redirectType="Permanent" />
</rule>
It sounds like you're trying to clean up sloppy URLs that don't match the case of the files on a *nix file system. This rule wouldn't really be necessary if you're developing locally on Windows, but I would actually recommend you look at another feature of CommandBox which is forced case-insensitivity which is designed just for this.
https://commandbox.ortusbooks.com/embedded-server/configuring-your-server/experimental-features#forcing-case-insensitivity
server set runwar.args="--case-sensitive-web-server=false"
bdw429s
06/21/2022, 3:58 PM<rule name="Add trailing slash" stopProcessing="false">
<match url="(.*[^/])$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{URL}" pattern="^.*\.(css|js|jpg|jpeg|png|gif|pdf|csv|xml|ttf|eot|svg|woff|ico|woff2|json|html|cfm|swf|xap|cfc|map|scss)$" ignoreCase="true" negate="true" />
</conditions>
<action type="Redirect" url="{R:1}/" redirectType="Permanent" />
</rule>
I'm sort of curious what the purpose of this rule actually is. Undertow will automatically redirect for you if you hit a folder named foo
and your URL just says <http://site.com/foo|site.com/foo>
it will redirect you to <http://site.com/foo/|site.com/foo/>
so I'm not sure a rule like this is needed unless you're wanting it to kick in for requests that aren't to existing folders. 🤔richard.herbert
06/21/2022, 3:58 PMbdw429s
06/21/2022, 4:04 PMregex( "(.*[^/])$" )
and not regex( pattern="^.*\.(css|js|jpg|jpeg|png|gif|pdf|csv|xml|ttf|eot|svg|woff|ico|woff2|json|html|cfm|swf|xap|cfc|map|scss)$", case-sensitive=false )
-> redirect('%{REQUEST_URL}/')
Note, that will use a 302 until this ticket is completed
https://issues.redhat.com/browse/UNDERTOW-1734
So if you need a 301, you'd need to do this:
...
-> { redirect('%{REQUEST_URL}/'); response-code(301) }
bdw429s
06/21/2022, 4:11 PMJust to be clear, this is an inherited projectOf course 😉 But to convert the rules, we first must understand what they do! 🙂
richard.herbert
06/21/2022, 4:11 PM