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

Brad Wood bdw429s at gmail.com
Wed Jul 8 04:13:16 EDT 2020


Ok, here is a JIRA ticket:

https://issues.redhat.com/browse/UNDERTOW-1747

And here is a pull request with my best stab at it:

https://github.com/undertow-io/undertow/pull/908

In my pull, I went with a predicate textual name of

set-error( 404 )

mostly because I used the Send Error Page handler name for the servlet
handler that actually looks for the status code.

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 8:55 PM Brad Wood <bdw429s at gmail.com> wrote:

> Forgot to reply to this:
>
>  add a 'continue' param to the response code handler,
>
>
> I'm not against adding this, however I would be unlikely to use
>
> responseCode( value=404, continue=true )
>
> as I'd want to have a cleaner predicate language.  I'd rather a new
> handler be introduced like the custom
>
> send-error-page( 404 )
>
> one I've been testing with that is readable and clear what it does.
>
> 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 8:51 PM Brad Wood <bdw429s at gmail.com> wrote:
>
>> 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/20200708/cef09c7d/attachment-0001.html 


More information about the undertow-dev mailing list