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 3 built in listener types, HTTP/1.1, AJP and HTTP/2. HTTPS is provided by using the HTTP listener with an SSL enabled connection.
Undertow also supports version 1 of the proxy protocol, which can be combined with any of the above listener types by
useProxyProtocol to true on the listener builder.
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 listed in
org.xnio.Options. Undertow specific options that control
connector level behaviour are listed in
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 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.
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
(depending on the network setting of the operating system). Smaller systems may want to use smaller buffers to save
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.
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
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
java.io.IOExceptionwill 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:http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-0450) 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
Dateheader 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
DateHandlerit will not overwrite the header. The current date string is cached, and is updated every second. Defaults to true.
If a HTTP
Connection: keep-aliveheader 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.
The HTTP/2 connector requires the use of ALPN when running over SSL.
As of Java 9 the JDK supports ALPN nativly, however on previous JDKs different approaches need to be used.
If you are using OpenJDK/Oracle JDK then Undertow contains a workaround that should allow ALPN to work out of the box.
Alternativly you can use the Wildfly OpenSSL project to provide ALPN, which should also perform better than the JDK SSL implementation.
Another option is to use Jetty ALPN, however it is not recommended as it is no longer tested as part of the Undertow test suite. For more information see the Jetty ALPN documentation.
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.
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.
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: h2cheader 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.
If JDK8 is in use then Undertow will use a reflection based implementation of ALPN that should work with OpenJDK/Oracle JDK. If JDK9+ is in use then Undertow will use the ALPN implementation provided by the JDK.
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.