@@ -573,6 +573,56 @@ initialization parameters (`init-param` elements) to the Servlet declaration in
573
573
574
574
575
575
576
+ [[mvc-handlermapping-path]]
577
+ === Path Matching
578
+
579
+ The Servlet API exposes the full request path as `requestURI` and further sub-divides it
580
+ into `contextPath`, `servletPath`, and `pathInfo` whose values vary depending on how a
581
+ Servlet is mapped. From these inputs, Spring MVC needs to determine the lookup path to
582
+ use for handler mapping, which is the path within the mapping of the `DispatcherServlet`
583
+ itself, excluding the `contextPath` and any `servletMapping` prefix, if present.
584
+
585
+ The `servletPath` and `pathInfo` are decoded and that makes them impossible to compare
586
+ directly to the full `requestURI` in order to derive the lookupPath and that makes it
587
+ necessary to decode the `requestUri`. However this introduces its own issues because the
588
+ path may contain encoded reserved characters such as `"/"` or `";"` that can in turn
589
+ alter the structure of the path after they are decoded which can also lead to security
590
+ issues. In addition, Servlet containers may normalize the `servletPath` to varying
591
+ degrees which makes it further impossible to perform `startsWith` comparisons against
592
+ the `requestUri`.
593
+
594
+ This is why it is best to avoid reliance on the `servletPath` which comes with the
595
+ prefix-based `servletPath` mapping type. If the `DispatcherServlet` is mapped as the
596
+ default Servlet with `"/"` or otherwise without a prefix with `"/*"` and the Servlet
597
+ container is 4.0+ then Spring MVC is able to detect the Servlet mapping type and avoid
598
+ use of the `servletPath` and `pathInfo` altogether. On a 3.1 Servlet container,
599
+ assuming the same Servlet mapping types, the equivalent can be achieved by providing
600
+ a `UrlPathHelper` with `alwaysUseFullPath=true` via <<mvc-config-path-matching>> in
601
+ the MVC config.
602
+
603
+ Fortunately the default Servlet mapping `"/"` is a good choice. However, there is still
604
+ an issue in that the `requestUri` needs to be decoded to make it possible to compare to
605
+ controller mappings. This is again undesirable because of the potential to decode
606
+ reserved characters that alter the path structure. If such characters are not expected,
607
+ then you can reject them (like the Spring Security HTTP firewall), or you can configure
608
+ `UrlPathHelper` with `urlDecode=false` but controller mappings will need to match to the
609
+ encoded path which may not always work well. Furthermore, sometimes the
610
+ `DispatcherServlet` needs to share the URL space with another Servlet and may need to
611
+ be mapped by prefix.
612
+
613
+ The above issues can be addressed more comprehensively by switching from `PathMatcher` to
614
+ the parsed `PathPattern` available in 5.3 or higher, see
615
+ <<mvc-ann-requestmapping-pattern-comparison>>. Unlike `AntPathMatcher` which needs
616
+ either the lookup path decoded or the controller mapping encoded, a parsed `PathPattern`
617
+ matches to a parsed representation of the path called `RequestPath`, one path segment
618
+ at a time. This allows decoding and sanitizing path segment values individually without
619
+ the risk of altering the structure of the path. Parsed `PathPattern` also supports
620
+ the use of `servletPath` prefix mapping as long as the prefix is kept simple and does
621
+ not have any characters that need to be encoded.
622
+
623
+
624
+
625
+
576
626
[[mvc-handlermapping-interceptor]]
577
627
=== Interception
578
628
@@ -1650,7 +1700,7 @@ configuration.
1650
1700
[.small]#<<web-reactive.adoc#webflux-ann-requestmapping-pattern-comparison, WebFlux>>#
1651
1701
1652
1702
When multiple patterns match a URL, the best match must be selected. This is done with
1653
- one of the following depending on whether parsed `PathPattern`'s are enabled for use or not:
1703
+ one of the following depending on whether use of parsed `PathPattern` is enabled for use or not:
1654
1704
1655
1705
* {api-spring-framework}/web/util/pattern/PathPattern.html#SPECIFICITY_COMPARATOR[`PathPattern.SPECIFICITY_COMPARATOR`]
1656
1706
* {api-spring-framework}/util/AntPathMatcher.html#getPatternComparator-java.lang.String-[`AntPathMatcher.getPatternComparator(String path)`]
0 commit comments