Undertow Request Lifecycle
by Brad Wood
I hate asking generic questions, but I'm looking for a little understanding
or clarification on request lifecycles. If you haven't noticed, I've had
several recent threads that touch on this. Before anyone asks,
- Yes, I have read all the docs I can find on this Ex
http://undertow.io/undertow-docs/undertow-docs-2.0.0/undertow-request-lif...
http://undertow.io/undertow-docs/undertow-docs-2.0.0/#listeners-2
http://undertow.io/undertow-docs/undertow-docs-2.0.0/servlet-using-non-bl...
- Yes, I have Google and read 3rd party docs and guides on Undertow. Ex:
https://www.oreilly.com/library/view/jboss-developers-guide/9781788296199...
- Yes, I have spent hours reviewing the code and experimenting
I've learned a lot, but there's a couple elusive things that all the docs
and guides I see don't quite seem to satisfactorily explain for me.
I'm trying to get some clarification on exactly what part of the request
happens inside the xnio worker thread and which part runs inside the
ThreadPoolExecutor. My server bootstrap wraps a number of various
HttpHandlers around the handler that I set into the server builder and I
had originally assumed that those handlers were part of the same handler
chain that invoked the servlet. This appears to not be the case. The
handler chain I pass to the server builder appears to execute as part of
the org.xnio.nio.WorkerThread.run() thread, while my servlet code executes
inside a thread pool executor.
Both stack traces show that there is a chain of handler.handleRequest()
calls, but this duality causes some confusion and troubles for me. It also
seems to explain to an extent why Stuart's previous messages treated the
"servlet" as a concept so far removed from the initial handler chain.
Even docs like the last link I provided above that contain this image...
[image: image.png]
make it sound like there is a single "root handler". However,
*executeRootHandler* appears in the stack traces of both the XNIO worker as
well as during the servlet chain in the thread pool executor.
at
> io.undertow.server.handlers.SSLHeaderHandler.handleRequest(SSLHeaderHandler.java:105)
> *at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)*
> at
> io.undertow.server.protocol.http.HttpReadListener.handleEventWithNoRunningRequest(HttpReadListener.java:255)
at
> io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
> *at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)*
> at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
This has proved to create difficulty in trying to accomplish seemingly very
simple tasks with Undertow. For example, an example I gave in a previous
thread was a simple task of logging every HTTP request that returned a
non-successful status code. Seems easy enough, right? However...
- I can't use an exchange complete listener because it doesn't fire with
handlers like *response-code* that end the exchange
- I can't wrap the servlet handler chain because that chain is never
invoked if the exchange is ended first by my predicates
- I can't wrap the handler chain being run in the XNIO listener because
it doesn't wrap the servlet chain so my "before" and "after" code all runs
before the servlet chain starts.
I would love any help and insight both on my general question for
documentation regarding the two separate handler chains as well as my more
specific question above about implementing something as simple as a
handler/listener that always runs at the end of an exchange.
Thanks!
~Brad
*Developer Advocate*
*Ortus Solutions, Corp *
E-mail: brad(a)coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com
5 years, 10 months
response-code handler bypasses configured error pages
by Brad Wood
When I configure an error page similar to this:
servletBuilder.addErrorPage( new ErrorPage( "404.html", 404));
This works great when I hit a path in my browser that doesn't exist. The
contents of the *404.html* file is served with a response code of *404*.
However, if I also use the predicate language to define something like:
path(/box.json)->response-code(404)
and then I hit *localhost/box.json* in my browser, I get a *404* status
code but with no response body.
- The docs say the response-code handler ends the exchange, but
should it still respect the error pages?
- How can I modify my use of Undertow to respect the error pages
when using the response-code handler?
- I've seen in the docs the ability to have a
*addDefaultResponseListener()* but I'm not sure if it is the correct
solution for this, nor how I would access the error page configuration
dynamically as to not need to duplicate my work.
Thanks!
~Brad
*Developer Advocate*
*Ortus Solutions, Corp *
E-mail: brad(a)coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com
5 years, 10 months
Max and Min content size predicates are implemented backwards
by Brad Wood
These two predicates from undertow are named/implemented backwards. The
"max" should be ensuring the provided value is at least *as small or
smaller* and the "min" should be ensuring the provided value is at least *as
big or bigger*. But here are the descriptions of each one.
*MinContentSizePredicate*
> Predicate that returns true if the Content-Size of a request is below a
> given value.
*MaxContentSizePredicate*
> Predicate that returns true if the Content-Size of a request is above a
> given value.
So to spell it out, if someone uses the following predicate:
max-content-size(5)
That means they are saying the maximum content size is 5 bytes. So, here's
a quick truth table:
- If content length is *4 bytes *-> should return *true *(under the max)
- if content length is *5 bytes *-> should return *true *(at the max,
but not over)
- if content length is *6 bytes *-> should return *false *(over the max)
But this is the exact opposite of how these predicates have been
implemented. The javadoc matches the behavior, but not the name.
Can I get a quick confirmation this is, in fact, backwards before I enter a
ticket and/or pull request. Note, this will be a breaking change to fix.
Thanks!
~Brad
*Developer Advocate*
*Ortus Solutions, Corp *
E-mail: brad(a)coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com
5 years, 10 months
swagger in undertow
by David Robinson
Is there a way to add Swagger into an undertow based server? Here is how I
start my server now - standard stuff:
------
RoutingHandler rh0 = new RoutingHandler()
.post("/bb/{cohort}/{topictype}", new
UniversalPostHttpHandler(kep, kvemp))
.get("/bb/{cohort}/{topictype}/schema", new UniversalGetHttpHandler())
.get("/admin/healthcheck", new
UniversalHealthCheckHttpHandler())
.get("/admin/metrics", new
UndertowGetMetricHttpHelperHandler())
Undertow server = Undertow.builder().setIoThreads(undertowIoThreads
).addHttpListener(ipPort, ipAddress).setHandler(rh0).build();
------
Ideally, swagger could just be added as another handler of sorts.
I ran across this post, which is over a year old, which is unanswered:
https://stackoverflow.com/questions/54685819/swagger-undertow
Appreciate any advice on how to do this.
Thanks,
5 years, 10 months
Exchange complete listener doesn't fire if exchange is ended
by Brad Wood
I have a basic exchange listener configured for testing that simply logs at
the end of each request something like
exchange.addExchangeCompleteListener((httpServerExchange, nextListener) -> {
if (httpServerExchange.getStatusCode() > 399) {
CONTEXT_LOG.warnf("responded: Status Code %s (%s)",
httpServerExchange.getStatusCode(), fullExchangePath(httpServerExchange));
}
nextListener.proceed();
});
This works great, but if the exchange is ended-- for example using the
response-code handler-- then the exchange complete listener never fires.
Is this working as designed?
Thanks!
~Brad
*Developer Advocate*
*Ortus Solutions, Corp *
E-mail: brad(a)coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com
5 years, 10 months