Tomcats implementation of RequestDispatcher forward not handling a ServletRequestWrapper correctly when updating forward request params. Seems to modify the value of the javax.servlet.forward.request_uri request attribute incorrectly, according to servlet spec SRV.8.4.2. Here are some specifics, at least with version 5.0.28. Stepping through the Tomcat source in the debugger, it appears that the request's requestURI field gets stomped on in the forward method of the RequestDispatcher (ApplicationDispatcher.doForward()). I'm not sure Tomcat is handling a ServletRequestWrapper correctly. I gather the servlet spec says that users may wrap the request/response objects with their own implementation. Tomcat's ApplicationDispatcher gets the request from the outer request (the ServletRequestWrapper), trying to keep track of the previous wrapper and current wrapper (or request) as it loops through to get the real request. With a single wrapper, the value of "previous" is the same as the original outer request. Then Tomcat calls... ((ServletRequestWrapper) previous).setRequest(wrapper); which is the same as calling setRequest(wrapper) on the incoming request. Tomcat does not get and save the value of the original request URI. It calls setRequestURI(path) on the wrapper, effectively changing the request URI of the original incoming request to the path of the forward. Then Tomcat sets the javax.servlet.forward.request_uri attribute by calling getRequestURI() from the original request... but that just got modified. Implying the javax.servlet.forward.request_uri attribute is going to get the value of the path for the forward. You can test this on Tomcat by using a couple JSP to. Use a HttpServletRequestWrapper in one JSP for the forward. First create "result.jsp" to display the desired request attribute... <%@ page language="java" contentType="text/html;charset=UTF-8"%> <html> <head> <title>RequestDispatcher Test</title> </head> <body> <h1>Forward Request URI</h1> javax.servlet.forward.request_uri = <%= request.getAttribute("javax.servlet.forward.request_uri") %> </body> </html> Create a JSP to forward without using a wrapper, "forward.jsp"... <% javax.servlet.RequestDispatcher rd = request.getRequestDispatcher("result.jsp"); rd.forward(request, response); %> and a second forward using HttpServletRequestWrapper, "wrapperforward.jsp"... <% HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(request); javax.servlet.RequestDispatcher rd = wrapper.getRequestDispatcher("result.jsp"); rd.forward(wrapper, response); %> When you hit forward.jsp, the result page displays "/some-context/forward.jsp" for the javax.servlet.forward.request_uri request attribute. However, hit wrapperforward.jsp and the result page displays "/some-context/result.jsp". From looking at the spec, I'd expect this should be "/some-context/wrapperforward.jsp".
I was able to reproduce this same bug on Tomcat 5.5.9 as well. The javax.servlet.forward.request_uri attribute is definitely NOT being set correctly when forwarding with a wrapped request
I'm guessing that the root cause is the same, but it should also be noted that the javax.servlet.forward.servlet_path attribute is not being set correctly under these conditions either.
This is now fixed in the CVS head, and will appear in 5.5.10. It currently seems unlikely that there will be another release on the 5.0.x line, so the 5.5.x line is all that there is.
It looks like there is a 5.0.30 Tomcat version in the works, will this fix be included in that version as well?
Forgive my poor English, it is not my native language. I found following bugs since 5.5.x, may be early. 5.5.9, 5.5.10 have same bugs, too. org.apache.catalina.core.ApplicationDispatcher.doInclude //HTTP named dispatcher include //HTTP path based include invoke(outerRequest, outerResponse); // bug here --> invoke(wrequest, wresponse); // crect one org.apache.catalina.core.ApplicationDispatcher.processRequest //HTTP named dispatcher forward //HTTP path based forward invoke(outerRequest, response); // bug here --> invoke(wrequest, response); // crect 1) If you have n HttpServletRequestWrapper, then Original HttpServletRequest Dispatcher's HttpServletRequestWrapper <-- wrequest <-- suppose to invoke this one Your HttpServletRequestWrapper #1 Your HttpServletRequestWrapper #2 ... Your HttpServletRequestWrapper #n <-- outerRequest 2) If no HttpServletRequestWrapper, then Original HttpServletRequest Dispatcher's HttpServletRequestWrapper <-- wrequest==outerRequest <-- it works Topper Lu email: topper@tlk.com.tw
Ehhh, ok, I see the light now ;) Forgive me for not being friendly, it is not my native behavior. Please do not reopen the report.