Configuring Predicates and Exchange with Undertow

Predicates and Exchange attributes are an Undertow component which allow you to manipulate your HTTP request and even make complex decisions on it, without hardcoding this into an Undertow Handler.

You can configure Predicates and Exchange attributes through a set of expression filters. The expressions you can use can also be combined with boolean operators which make them quite powerful. Let’s see some examples:

The most basic example expression we will learn is the RequestDumping which allows you to dump your HTTP request. To configure a RequestDumping handler as an expression filter, you need at first create a new expression filter. The following CLI command will do it:

/subsystem=undertow/configuration=filter/expression-filter=requestDump:add(expression="dump-request")

Next, you can enable the expression Filter in the Undertow Web Server:

/subsystem=undertow/server=default-server/host=default-host/filter-ref=requestDump:add

The result of it, will be a trace of the Request/Response in your server logs:

HTTP Request ---------------------------------------------
 URI=/api/v1/pods
 characterEncoding=null
     contentLength=-1
       contentType=null
            header=Accept-Encoding=gzip
            header=User-Agent=kube-scheduler/v1.0.6 (linux/amd64) kubernetes/388061f
            header=Host=127.0.0.1:8080
            locale=[]
            method=GET
         parameter=fieldSelector=spec.nodeName!=
          protocol=HTTP/1.1
       queryString=fieldSelector=spec.nodeName%21%3D
        remoteAddr=localhost/127.0.0.1:45674
        remoteHost=localhost
            scheme=http
              host=127.0.0.1:8080
        serverPort=8080     
HTTP Response ---------------------------------------------
            contentLength=74
            contentType=text/html
            header=Connection=keep-alive
            header=X-Powered-By=Undertow/1
            header=Server=WildFly/10
            header=Content-Length=74
            header=Content-Type=text/html
            header=Date=Sat, 01 Oct 2016 07:05:43 GMT

Quite powerful, however most of the times you would be interested to apply a filter at application level. This will limit the scope of the handler to only that specific application. In order to do that, you just need to add your filters into a file WEB-INF/undertow-handlers.conf.

To configure the RequestDumping handler in WEB-INF/undertow-handlers.conf to log all requests and corresponding responses for this application, add the following expression to WEB-INF/undertow-handlers.conf:

Let’s try it: start from a default Undertow configuration and create a simple Web application which contains into the file WEB-INF/undertow-handlers.conf the following content:

dump-request

When you try to access your application, you will see that you have achieved the same result in the server logs.

Advanced filters

The list of available filter expression is well described in the Undertow docs at: http://undertow.io/undertow-docs/undertow-docs-1.3.0/predicates-attributes-handlers.html

Let’s see another example: how to set an attribute in your HTTP Header:

header(header=a, value='x')

The above will set the value “x” in the header field named “a”.

undertow-handlers.conf

Another example: how to perform an URL rewrite to another location: from page1.jsp to page2.jsp

path(/page1.jsp) -> rewrite(/page2.jsp)

Use the reverse proxy to send all requests to /context1 to a different backend server:

path-prefix('/context1') -> reverse-proxy({'http://backupserver.com'})

How to define an ACL so that requests to 127.0.0.1 are allowed whilst requests to 192.168.10.1 are denied:

ip-access-control[default-allow=true, acl={'127.0.0.1 allow', '192.168.10.1 deny'}]

To make more powerful your filters, predicates can be combined using the boolean operators ‘and’, ‘or’ and not. For example:

not method(GET)

Even in a more complex way:

method(POST) and path-prefix("/path1")

You can as well check path templates against an expression:

path-template(value="/user/{username}/*") and equals(%u, ${username})

And even Regular expression to verify the Request

regex(pattern="/user/(.*?)./.*", value=%U, full-match=true) and equals(%u, ${1})
Found the article helpful? if so please follow us on Socials