Listeners represent the entry point of an Undertow application. All incoming requests will come through a listener, and a listener is responsible for translating a request into an instance of the HttpServerExchange object, and then turning the result into a response that can be sent back to the client.

Undertow provides 4 built in listener types, HTTP/1.1, AJP, SPDY and HTTP/2. HTTPS is provided by using the HTTP listener with an SSL enabled connection.

Note that it is expected that now that HTTP/2 is out it is expected that SPDY will be deprecated and eventually removed.


Undertow listeners can be configured through the use of the org.xnio.Option class. In general options for XNIO that control connection and worker level behaviour are are listed in org.xnio.Options. Undertow specific options that control connector level behaviour are listed in io.undertow.UndertowOptions.

XNIO workers

All listeners are tied to an XNIO Worker instance. Usually there will only be a single worker instance that is shared between listeners, however it is possible to create a new worker for each listener.

The worker instance manages the listeners IO threads, and also the default blocking task thread pool. There are several main XNIO worker options that affect listener behaviour. These option can either be specified on the Undertow builder as worker options, or at worker creating time if you are bootstrapping a server manually. These options all reside on the org.xnio.Options class.


The number of IO threads to create. IO threads perform non blocking tasks, and should never perform blocking operations because they are responsible for multiple connections, so while the operation is blocking other connections will essentially hang. Two IO threads per CPU core is a reasonable default.


The number of threads in the workers blocking task thread pool. When performing blocking operations such as Servlet requests threads from this pool will be used. In general it is hard to give a reasonable default for this, as it depends on the server workload. Generally this should be reasonably high, around 10 per CPU core.

Buffer Pool

All listeners have a buffer pool, which is used to allocate pooled NIO ByteBuffer instances. These buffers are used for IO operations, and the buffer size has a big impact on application performance. For servers the ideal size is generally 16k, as this is usually the maximum amount of data that can be written out via a write() operation (depending on the network setting of the operating system). Smaller systems may want to use smaller buffers to save memory.

In some situations with blocking IO the buffer size will determine if a response is sent using chunked encoding or has a fixed content length. If a response fits completely in the buffer and flush() is not called then a content length can be set automatically.

Common Listener Options

In addition to the worker options the listeners take some other options that control server behaviour. These are all part of the io.undertow.UndertowOptions class. Some of of these only make sense for specific protocols. You can set options with the Undertow.Builder.setServerOption:


The maximum size of a HTTP header block, in bytes. If a client sends more data that this as part of the request header then the connection will be closed. Defaults to 50k.


The default maximum size of a request entity. If entity body is larger than this limit then a will be thrown at some point when reading the request (on the first read for fixed length requests, when too much data has been read for chunked requests). This value is only the default size, it is possible for a handler to override this for an individual request by calling io.undertow.server.HttpServerExchange.setMaxEntitySize(long size). Defaults to unlimited.


The default max entity size when using the Multipart parser. This will generally be larger than MAX_ENTITY_SIZE. Having a seperate setting for this allows for large files to be uploaded, while limiting the size of other requests.


The maximum number of query parameters that are permitted in a request. If a client sends more than this number the connection will be closed. This limit is necessary to protect against hash based denial of service attacks. Defaults to 1000.


The maximum number of headers that are permitted in a request. If a client sends more than this number the connection will be closed. This limit is necessary to protect against hash based denial of service attacks. Defaults to 200.


The maximum number of cookies that are permitted in a request. If a client sends more than this number the connection will be closed. This limit is necessary to protect against hash based denial of service attacks. Defaults to 200.


The charset to use to decode the URL and query parameters. Defaults to UTF-8.


Determines if the listener will decode the URL and query parameters, or simply pass it through to the handler chain as is. If this is set url encoded characters will be decoded to the charset specified in URL_CHARSET. Defaults to true.


If a request comes in with encoded / characters (i.e. %2F), will these be decoded. This can cause security problems (link: if a front end proxy does not perform the same decoding, and as a result this is disabled by default.


If this is true then Undertow will allow non-escaped equals characters in unquoted cookie values. Unquoted cookie values may not contain equals characters. If present the value ends before the equals sign. The remainder of the cookie value will be dropped. Defaults to false.


If the server should add a HTTP Date header to all response entities which do not already have one. The server sets the header right before writing the response, if none was set by a handler before. Unlike the DateHandler it will not overwrite the header. The current date string is cached, and is updated every second. Defaults to true.


If a HTTP Connection: keep-alive header should always be set, even for HTTP/1.1 requests that are persistent by default. Even though the spec does not require this header to always be sent it seems safer to always send it. If you are writing some kind of super high performance application and are worried about the extra data being sent over the wire this option allows you to turn it off. Defaults to true.


The maximum size of a request that can be saved in bytes. Requests are buffered in a few situations, the main ones being SSL renegotiation and saving post data when using FORM based auth. Defaults to 16,384 bytes.


If the server should record the start time of a HTTP request. This is necessary if you wish to log or otherwise use the total request time, however has a slight performance impact, as it means that System.nanoTime() must be called for each request. Defaults to false.


The amount of time a connection can be idle for before it is timed out. An idle connection is a connection that has had no data transfer in the idle timeout period. Note that this is a fairly coarse grained approach, and small values will cause problems for requests with a long processing time.


How long a request can spend in the parsing phase before it is timed out. This timer is started when the first bytes of a request are read, and finishes once all the headers have been parsed.


The amount of time a connection can sit idle without processing a request, before it is closed by the server.


If this is true then the connector will record statistics such as requests processed and bytes sent/received. This has a performance impact, although it should not be noticeable in most cases.



Note that the HTTP2 and SPDY connectors require the use of ALPN. Unfortunatly java does not provide a standard way of performing ALPN at this time, so it is necessary to run java with a 3rd party ALPN library on the boot class path. For more information see the Jetty ALPN documentation.

SPDY and HTTP2 should use the ALPN open listener to handle the ALPN protocol negotiation.

HTTP Listener


The HTTP listener is the most commonly used listener type, and deals with HTTP/1.0 and HTTP/1.1. It only takes one additional option.


If this is true then the connection can be processed as a HTTP/2 'prior knowledge' connection. If a HTTP/2 client connects directly to the listener with a HTTP/2 connection preface then the HTTP/2 protocol will be used instead of HTTP/1.1.

AJP Listener


The AJP listener allows the use of the AJP protocol, as used by the apache modules mod_jk and mod_proxy_ajp. It is a binary protocol that is slightly more efficient protocol than HTTP, as some common strings are replaced by integers. If the front end load balancer supports it then it is recommended to use HTTP2 instead, as it is both a standard protocol and more efficient.

This listener has one specific option:


Controls the maximum size of an AJP packet. This setting must match on both the load balancer and backend server.

HTTP2 Listener

HTTP/2 support is implemented on top of HTTP/1.1 (it is not possible to have a HTTP/2 server that does not also support HTTP/1). There are three different ways a HTTP/2 connection can be established:


This is the most common way (and the only way many browsers currently support). It requires HTTPS, and uses the application layer protocol negotiation SSL extension to negotiate that connection will use HTTP/2.

Prior Knowledge

This involves the client simply sending a HTTP/2 connection preface and assuming the server will support it. This is not generally used on the open internet, but it useful for things like load balancers when you know the backend server will support HTTP/2.

HTTP Upgrade

This involves the client sending an Upgrade: h2c header in the initial request. If this upgrade is accepted then the server will initiate a HTTP/2 connection, and send back the response to the initial request using HTTP/2.

Depending on the way HTTP/2 is being used the setup for the listeners is slightly different.

If you are using the Undertow builder all that is required is to call setServerOption(ENABLE_HTTP2, true), and HTTP/2 support will be automatically added for all HTTP and HTTPS listeners.

JDK8 does not currently support ALPN. To use HTTP/2 over HTTPS it is necessary to use the Jetty ALPN extension on the boot class path. Instructions for Jetty ALPN can be found at

The following options are supported:


The size of the header table that is used for compression. Increasing this will use more memory per connection, but potentially decrease the amount of data that is sent over the wire. Defaults to 4096.


If server push is enabled for this connection.


The maximum number of streams a client is allowed to have open at any one time.


The initial flow control window size.


The maximum frame size.


The maximum size of the headers that this server is prepared to accept.

SPDY Listener


The SPDY protocol is an experimental protocol designed by Google, that formed the basis of HTTP2. Now that HTTP2 has been adopted by browser vendors it should be used instead.