[undertow-dev] response-code handler bypasses configured error pages

Brad Wood bdw429s at gmail.com
Tue Jul 7 21:51:13 EDT 2020


Genius idea.  In all my tests I hadn't thought of setting the response code
in the predicate and then letting it continue to the servlet and caching it
there.  I just tested this and it does appear to work well.

I added this outer handler chain wrapper to my deployment info

        deploymentInfo.addOuterHandlerChainWrapper(next -> new
HttpHandler() {
            @Override
            public void handleRequest(HttpServerExchange exchange) throws
Exception {
                if( exchange.getStatusCode() > 399 &&
exchange.getResponseContentLength() == -1 ) {
                    ServletRequestContext src =
exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);

((HttpServletResponse)src.getServletResponse()).sendError(exchange.getStatusCode());
                } else {
                    next.handleRequest(exchange);
                }
            }
        });

(I don't know if the exchange.getResponseContentLength() check is needed or
the best way to do that)

And then I registered a custom handler I called *send-error-page* that has
this handleRequest method:

    public void handleRequest(final HttpServerExchange exchange) throws
Exception {
        exchange.setStatusCode(responseCode);
        next.handleRequest(exchange);
    }

Then this predicate rule

path(/box.json)->send-error-page(404)

serves up my servlet's custom error page for that request.

Thanks!

~Brad

*Developer Advocate*
*Ortus Solutions, Corp *

E-mail: brad at coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com



On Tue, Jul 7, 2020 at 6:39 PM Stuart Douglas <sdouglas at redhat.com> wrote:

> Basically I think the only way you can solve this is to attach the error
> code to the exchange somehow, then have a handler that reads the error code
> and calls sendError later.Basically write a new response-code handler that
> sets the code then calls the next handler (so the request gets to Servlet),
> then add a handler to the Servlet deployment that calls sendError if the
> exchange status code is > 400.
>
> We could actually add this to Undertow very simply, just add a 'continue'
> param to the response code handler, then always call sendError in servlet
> if the incoming request response is >400.
>
> Can you try this out, and if it works I can look at getting it into
> Undertow.
>
> Stuart
>
> On Wed, 8 Jul 2020 at 02:35, Brad Wood <bdw429s at gmail.com> wrote:
>
>> Stuart, any further suggestions or answers to my outstanding questions?
>> So far, everything you've suggested doesn't work for various reasons I've
>> shared here.  I also have a number of outstanding questions such as how I
>> could access the deployment information for the servlet's error pages from
>> inside an HTTPHandler running in the initial handler chain that fires in
>> the XNIO worker.
>>
>> Thanks!
>>
>> ~Brad
>>
>> *Developer Advocate*
>> *Ortus Solutions, Corp *
>>
>> E-mail: brad at coldbox.org
>> ColdBox Platform: http://www.coldbox.org
>> Blog: http://www.codersrevolution.com
>>
>>
>>
>> On Fri, Jul 3, 2020 at 3:55 PM Brad Wood <bdw429s at gmail.com> wrote:
>>
>>> After a few hours of experimenting, I was able to answer a few of my own
>>> questions, but not all of them.
>>>
>>>    - Yes, it is possible to contribute a custom handler to the
>>>    predicate language-- this is actually pretty sweet.  I didn't realize just
>>>    how generic the parser was.
>>>    - In order to get "picked up", the builder class must be listed in
>>>    the
>>>    *META-INF/services/io.undertow.server.handlers.builder.HandlerBuilder*
>>>    file
>>>    - That custom handler suggested by Stuart in the previous message
>>>    ONLY works if the predicate chain is wrapped "inside" the servlet initial
>>>    handler. Otherwise, the servletcontext classes are missing.  This
>>>    unfortunately, makes it a no-go for me to be able to use.
>>>
>>> The rest of my questions still stand however in so far as how I can
>>> accomplish what I need.
>>>
>>> During my experiments today, I also played with the error-file handler,
>>> but it also is of no use.  Since the response-code handler ends the
>>> exchange, any error pages declared in the error file handler are never
>>> used!
>>>
>>> error-file( response-codes={404},
>>> file="C:\sandbox\predicatetest\custom404.html" )
>>> path('/box.json') -> response-code(404)
>>>
>>> I even tried creating a custom handler that sets the status code but
>>> continues the exchange, but then that just serves the original file anyway,
>>> which causes the error-file handler to do nothing since the response stream
>>> is already started.
>>>
>>> Thanks!
>>>
>>> ~Brad
>>>
>>> *Developer Advocate*
>>> *Ortus Solutions, Corp *
>>>
>>> E-mail: brad at coldbox.org
>>> ColdBox Platform: http://www.coldbox.org
>>> Blog: http://www.codersrevolution.com
>>>
>>>
>>>
>>> On Fri, Jul 3, 2020 at 12:02 PM Brad Wood <bdw429s at gmail.com> wrote:
>>>
>>>> You probably need to write a custom one that looks like this (plus the
>>>>> relevant predicate languge bits):
>>>>
>>>>
>>>> Stuart, if I can branch the conversation here back to your idea of a
>>>> custom handler for a bit...
>>>>
>>>> I'm still toying with this, and while the handleRequest() code you have
>>>> makes perfect sense, I think I'm missing a lot of context on how you were
>>>> suggesting this would work.
>>>>
>>>>    - The code you put in your message-- were you suggesting that
>>>>    should be added to the Undertow core as a built in handler or just a custom
>>>>    class I would put in my project?
>>>>    - Would this handler require the predicates be processed downstream
>>>>    of the servlet initial handler in order to work?  Because if so, that
>>>>    appears to be a no-go since handlers like the rewrite only appear to work
>>>>    upstream of the servlet
>>>>    - Is it possible to register custom handlers of my own creation
>>>>    with the predicate language or were you suggesting a handler that could
>>>>    only be manually configured?  I'm familiar with the handler builder pattern
>>>>    that the built in handlers use, but I'm unclear on how builders get
>>>>    registered with the predicate handler parser.
>>>>    - Actually, I just reviewed the code again now and I see
>>>>    the loadHandlerBuilders() method in the PredicatedhandlersParser class
>>>>    appears to be scanning the classpath for builders.  Interesting....  Does
>>>>    Undertow need to be loaded by the same class loader that loaded my custom
>>>>    handlers for this to work?  I'm not super familiar with the ServiceLoader
>>>>    stuff
>>>>    - I'm not against building a custom handler that I ship alongside
>>>>    Undertow that provides what I'm looking for, but I'm still interested in
>>>>    having the conversation of how we can improve undertow's core offering.
>>>>
>>>> Thanks!
>>>>
>>>> ~Brad
>>>>
>>>> *Developer Advocate*
>>>> *Ortus Solutions, Corp *
>>>>
>>>> E-mail: brad at coldbox.org
>>>> ColdBox Platform: http://www.coldbox.org
>>>> Blog: http://www.codersrevolution.com
>>>>
>>>>
>>>>
>>>> On Thu, Jul 2, 2020 at 7:01 PM Stuart Douglas <sdouglas at redhat.com>
>>>> wrote:
>>>>
>>>>> Hmm, this is because the servlet status code is only triggered by a
>>>>> sendError method, not by just setting the code.
>>>>>
>>>>> You probably need to write a custom one that looks like this (plus the
>>>>> relevant predicate languge bits):
>>>>>
>>>>> public class SendErrorHandler implements HttpHandler {
>>>>>
>>>>>     private final int code;
>>>>>
>>>>>     public SendErrorHandler(int code) {
>>>>>         this.code = code;
>>>>>     }
>>>>>
>>>>>     @Override
>>>>>     public void handleRequest(HttpServerExchange exchange) throws
>>>>> Exception {
>>>>>         ServletRequestContext src =
>>>>> exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
>>>>>
>>>>> ((HttpServletResponse)src.getServletResponse()).sendError(code);
>>>>>     }
>>>>> }
>>>>>
>>>>> Stuart
>>>>>
>>>>>
>>>>>
>>>>> On Fri, 3 Jul 2020 at 09:40, Brad Wood <bdw429s at gmail.com> wrote:
>>>>>
>>>>>> Thanks for the reply Stuart.  I've tried this with no success, but
>>>>>> perhaps I'm doing it wrong.
>>>>>>
>>>>>> List<PredicatedHandler> ph =
>>>>>> PredicatedHandlersParser.parse(predicatesLines, _classLoader);
>>>>>> servletBuilder.addOuterHandlerChainWrapper(next ->
>>>>>> Handlers.predicates(ph,next));
>>>>>>
>>>>>> When the response-code handler fires, I still get no response body.
>>>>>>
>>>>>> On a related note, when I move the predicates into an outer handler
>>>>>> chain wrapper, my default response listener also doesn't fire at all.
>>>>>>
>>>>>> On an unrelated train of thought, I've been trying to see if I can
>>>>>> get the default response listener to automatically dispatch the correct
>>>>>> error page, but that hasn't been going well either.  If I don't use the
>>>>>> outer handler chain idea, but try to capture the empty response in a
>>>>>> default response listener, I can return a static message using the Sender
>>>>>> class
>>>>>>
>>>>>> Sender sender = exchange.getResponseSender();
>>>>>> sender.send(errorHTMLString);
>>>>>>
>>>>>> But if I try to run something this in my default response listener to
>>>>>> invoke my error pages
>>>>>>
>>>>>> ServletRequestContext src =
>>>>>> exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
>>>>>> HttpServletResponseImpl response = src.getOriginalResponse();
>>>>>> response.doErrorDispatch( exchange.getStatusCode(),
>>>>>> exchange.getReasonPhrase() );
>>>>>>
>>>>>> Then it's as though nothing happens and I still get an empty response.
>>>>>>
>>>>>> Thanks!
>>>>>>
>>>>>> ~Brad
>>>>>>
>>>>>> *Developer Advocate*
>>>>>> *Ortus Solutions, Corp *
>>>>>>
>>>>>> E-mail: brad at coldbox.org
>>>>>> ColdBox Platform: http://www.coldbox.org
>>>>>> Blog: http://www.codersrevolution.com
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Thu, Jul 2, 2020 at 6:17 PM Stuart Douglas <sdouglas at redhat.com>
>>>>>> wrote:
>>>>>>
>>>>>>> The predicate languages are executed before the Servler handlers, so
>>>>>>> they won't be handled by Servlet error pages.
>>>>>>>
>>>>>>> If you are setting this all up programmatically you could use
>>>>>>> io.undertow.servlet.api.DeploymentInfo#addOuterHandlerChainWrapper to setup
>>>>>>> the predicate handler after the initial servlet one, which should mean that
>>>>>>> the servlet error handling will handle the response code.
>>>>>>>
>>>>>>> Stuart
>>>>>>>
>>>>>>> On Fri, 3 Jul 2020 at 08:25, Brad Wood <bdw429s at gmail.com> wrote:
>>>>>>>
>>>>>>>> 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 at coldbox.org
>>>>>>>> ColdBox Platform: http://www.coldbox.org
>>>>>>>> Blog: http://www.codersrevolution.com
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> undertow-dev mailing list
>>>>>>>> undertow-dev at lists.jboss.org
>>>>>>>> https://lists.jboss.org/mailman/listinfo/undertow-dev
>>>>>>>
>>>>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20200707/1f2b4ce3/attachment-0001.html 


More information about the undertow-dev mailing list