Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
After forward from SAM injected request returns wrong servlet path #927
If a SAM forwards to a Servlet that uses a CDI bean with an injected HttpServletRequest, then calling getServletPath on this HttpServletRequest returns the servlet path of the original servlet, not the forwarded servlet.
This can be reproduced by running the test case at https://github.com/javaee-samples/javaee7-samples/tree/master/jaspic/dispatching-jsf-cdi
Deploying the .war build by that module to Payara 126.96.36.199 and requesting http://localhost:8080/jaspic-dispatching-jsf-cdi/public/servlet the following is shown:
It should however be:
On WildFly 10.0.0 and Liberty 188.8.131.52 the above is indeed shown.
OK I've spent some time in this code investigating.
The problem arises from how Payara implements Servlet forwards and includes. Payara always creates a HttpServletRequestWrapper for an include or forward and this is passed to the servlet.
While it is pretty simple to correct the path issue by storing a special request attribute for the current path and returning that in response to getServletPath() to fix this issue (which I will do) the underlying issue remains.
I read the CDI spec but it's pretty silent on what happens if a ServletRequestWrapper is used somewhere in the processing pipeline and then the HttpServletRequest is subsequently injected into a request scoped bean. Should you receive the request wrapper or the original request?
added a commit
Sep 3, 2016
Good find! I'll try to add a test for this too in the Java EE 7 samples project.
I'd like to do a new report on a larger number of servers wrt to JASPIC tests from the EE 7 samples project soon, so then for a somewhat larger number of servers it will become clear how they behave here.
From what I understood, the CDI spec is not super clear on how the per request setup should actually be done. Weld provides the listener as a convenience for integrators. It does mention somewhere that if used it should be the first listener invoked (which may require some container specific code to guarantee this).
Also, "the start of request tracing" is not entirely clear either to everyone. Many vendors take it to be before authorization and authentication checks are done, but Liberty and Weblogic take it to be afterwards (see https://java.net/projects/servlet-spec/lists/users/archive/2015-03/message/1).
This means that on some servers the request has already been seen and can even be wrapped before the ServletRequestEvent is thrown :(
This is a very good observation, and in fact a short while ago I've been discussing exactly this point with Romain Manni-Bucau from TomEE. Long story short; it indeed wasn't clear which version of the wrapped request you would get.
Would also be good to check if other CDI build-in beans like the one for the injected Principal is capable of changing when mid-request logout and a new login takes place.
For now I will at least start a discussing for this on the CDI spec mailing list.
An interesting test would be to create a Servlet Filter which wraps the request and then see what request is received in Request Scoped Beans in other servers that utilise Weld. It could be that Liberty and WildFly don't wrap servlet requests during forwarding hence the difference in behaviour.
From the top of my head I think they will receive the original request, not the wrapped one, but certainly something to double check. Indeed, if Liberty and WildFly somehow make the original request instance aware of every forward and include, it would likely automatically work for request instances that were previously stored.
There's quite an amount of research that can be done here to find out what's exactly happening.