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(a)coldbox.org
ColdBox Platform:
On Tue, Jul 7, 2020 at 6:39 PM Stuart Douglas <sdouglas(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)coldbox.org
>>>>>>> ColdBox Platform:
http://www.coldbox.org
>>>>>>> Blog:
http://www.codersrevolution.com
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> undertow-dev mailing list
>>>>>>> undertow-dev(a)lists.jboss.org
>>>>>>>
https://lists.jboss.org/mailman/listinfo/undertow-dev
>>>>>>
>>>>>>