Affects: 5.3.1
In UrlPathHelper.skipServletPathDetermination()
the servlet mapping from the request is used. But if the request is processing an include then the mapping in the request is for the original path. The servlet mapping for the include is in the request attribute RequestDispatcher.INCLUDE_MAPPING
("javax.servlet.include.mapping").
So that method uses the wrong servlet mapping and therefore in some cases return the wrong result. And I'm guessing the same goes for when there's a forward, but that I haven't verified. Then the servlet mapping is in RequestDispatcher.FORWARD_MAPPING
.
Or is this an issue with the container? In my case I use tomcat 9.0.39.
Comment From: rstoyanchev
Mainly we check it isn't a PATH mapping (e.g. "/path/*"
). That's the more problematic case where the Servlet path prefix needs to be determined and stripped. Presumably on a given server, mapping by path prefix is either used or not. Can you provide more details for a more specific case?
Comment From: bergander
Let me give you some more background on the issue.
If you have a jsp page with an include tag which includes the result of a spring controller method, then it will fail when using spring-framework 5.3.1. In 5.2.10.RELEASE it works just fine.
And the reason for the failure is that when processing the include it's still in the context of the request for the jsp file. So the servlet mapping of the request will contain the servlet mapping for the jsp which usually is EXTENSION (*.jsp). But the include path might be of type PATH and then the UrlPathHelper.skipServletPathDetermination()
will return the wrong result for the include and therefore generate a NoHandlerFoundException
.
I've attached a sample war project which demonstrates the problem: spring-example.zip. In index.jsp there's an include tag which includes the result of a spring controller (/spring/example). But that include fails with a NoHandlerFoundException
. But if I go directly to that url I'll get the result without any NoHandlerFoundException
.
To solve this issue the correct servlet mapping must be used in UrlPathHelper.skipServletPathDetermination(
). And the servlet mapping for the include is in the request attribute javax.servlet.include.mapping according to Servlet 4 spec (chapter 9.3.1).
And the same problem might affect forwards, but I haven't investigated that. But then then servlet mapping is in javax.servlet.forward.mapping.
Comment From: rstoyanchev
Thanks for the sample and extra detail. So in your case, the request starts with a JSP page that includes a request to a Servlet mapped by prefix, and on an include the Servlet container returns original request details by default. For forward it's the other way around, with the Servlet container returning current request details by default. Hence I think only include is affected.
Comment From: bergander
@rstoyanchev A big thanks for the quick response and fix! I can confirm that it resolves my issue.