-
Feature Request
-
Resolution: Unresolved
-
Major
-
None
-
2.3.18.Final
-
None
Malformed requests fail during parsing within the io.undertow.server.protocol.http.HttpRequestParser class.
An example is when a query parameter contains an invalid percent-encoded value (e.g., % not followed by two valid hexadecimal characters), Undertow throws a UrlDecodeException, logs the error, and does not proceed to build the HttpServerExchange. As a result, the request never reaches the handler chain where an application would normally manage and log such errors.
Example: A request like
GET http://example.com?a=%2f&a=1&wrong=%n
results in the following log message:
10:33:01.044 [XNIO-1 I/O-1] DEBUG io.undertow.request.io - UT005014: Failed to parse request io.undertow.util.UrlDecodeException: UT000072: Failed to decode url a=%2f&a=1&wrong=%n to charset UTF-8 at io.undertow.util.URLUtils.decode(URLUtils.java:142) at io.undertow.server.protocol.http.HttpRequestParser.decode(HttpRequestParser.java:628)
In this case the HttpServerExchange is never created and there is no way to handle the error.
Proposed Feature:
Introduce a mechanism to handle such request parsing failures more effectively.
This feature would allow users to propagate parsing errors to custom logging systems and monitoring solutions, ensuring visibility into issues that currently fail silently (beyond the Undertow log).
A potential solutions could be to introduce a feature to configure a custom request parsing error handler in the Undertow.builder() API.
Given a possible RequestErrorHandler interface:
public interface RequestErrorHandler { void handleError(Exception ex, HttpServerExchange exchange); }
Extend the Undertow.builder() API to include a requestErrorHandler method:
public Undertow.Builder.requestErrorHandler(RequestErrorHandler handler);
This would enable users to configure error handling logic in a streamlined manner, for example:
public static void main(String[] args) { Undertow server = Undertow.builder() .addHttpListener(8080, "localhost") .requestErrorHandler((ex, exchange) -> { LOGGING.error("Failed to parse request", ex); exchange.setStatusCode(400); exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json"); exchange.getResponseSender().send("{\"error\": \"Invalid request format\"}"); }) .setHandler(exchange -> exchange.getResponseSender().send("Hello, world!")) .build(); server.start(); }