Hi everyone,
I recently added support for rewrites and redirects, and I would like some feedback on the
syntax / implementation. It is actually quite a general mechanism that can be used for
lots of things. There are actually a few parts to it that I will explain below.
Exchange attributes
Exchange attributes provide a general way of referencing some information from the
exchange. Some examples:
%U or %{REQUEST_URL} - The request URL
%m or %{METHOD} - The request method
%{o,Content-Type} - The outgoing (response) content type header
%{i,Content-Type} - The incoming (request) header
These are intended to be re-usable in any place that requires dynamic specification of
attributes (e.g. in the access log you can use exchange attributes to specify the log
format). They are also extensible, you can add additional attributes via a service loader
approach.
Predicates
Predicates provide a simple way of making a true/false decision based on an exchange.
Many handlers have a requirement that they be applied conditionally, and predicates
provide a general way to specify a condition. Predicates can be created programatically
(they are just java classes that implement the Predicate interface), however there is also
a simple language for specifying a predicate. I will give some examples below:
regex['/resources/*.\.css'] - regular expression match of the relative URL
regex[pattern='text/.*', value='%{i,Content-Type}, full-match=true] - Matches
requests with a text/.* content type
equals[{'%{i,Content-Type}', 'text/xml'}] - Matches if the content type
header is text/xml
contains[search='MSIE', value='%{i,User-Agent}'] and
path-suffix['.js'] - User agent contains MSIE and request URL ends with .js
regex['/resources/(*.)\.css'] and equals[{'$1', 'myCssFile'}] -
regex match, with a reference to match group 1 later in the expression
These predicates are also extensible, and they use the exchange attributes mentioned above
meaning that they can be used to reference any part of the exchange. These should give
users enough flexibility to match requests based on any criteria they can think up.
Handler builders
We also support a way of specifying handlers, using similar language to predicates. Some
examples:
rewrite['/myfile.html'] - performs a rewrite
set['%{o,Content-Type}', 'text/xhtml'] - sets a header (this can be used
to set any exchange attribute)
redirect[/myfile.html] - performs a redirect
Now that we have all the pieces the actual config goes in a file called
undertow-handlers.conf. Its basic syntax is predicate -> handler. An example file could
look like below:
regex['(.*).css'] -> rewrite['${1}.xcss']
path-template['/foo/{bar}'] -> set[attribute='%{q,SomeHeader}',
value='${bar}']
basically the rules are matched in order, and if it matches the handler on the right is
executed. The handler on the right can also use context information from the match, such
as regex match groups or path template segments.
I think this should be sufficient in order to enable arbitrarily complex configs. The use
of attributes and predicates should also mean that this config is consistent across
everything we provide, even in other areas (e.g. the access log handler uses exchange
attributes, so the basic syntax is the same).
Does anyone have any thoughts on this config?
Stuart
Show replies by date