Skip to content

ResourceUrlEncodingFilter throws StringIndexOutOfBoundsException in tests #29933

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
schosin opened this issue Feb 6, 2023 · 4 comments
Closed
Assignees
Labels
in: test Issues in the test module in: web Issues in web modules (web, webmvc, webflux, websocket) type: regression A bug that is also a regression
Milestone

Comments

@schosin
Copy link

schosin commented Feb 6, 2023

Affects: 6.0.4

After adding a FilterRegistrationBean into my project, I swapped from MockMvcBuilder to Spring Boots @AutoConfigureMockMvc to have that filter applied in tests. That project also uses Thymeleaf so a ResourceUrlEncodingFilter is added as well by Spring Boot.

A existing test started breaking. It tested a @RequestMapping("") controller, which caused ResourceUrlEncodingFilter to throw a LookupPathIndexException [1] because the behaviour changed from requestUri returing "" instead of "/".
When an ExceptionHandler also calls HttpServletResponse#encodeURL (rendering a HTML error page with @{...} from thymeleaf), indexLookupPath will already have the value of -1 and instead will throw a StringIndexOutOfBoundsException in resolveUrlPath [2].

Here's a project demonstrating the problem as well as the differences between MockMvcBuilder without ResourceUrlEncodingFilter, MockMvcBuilder with ResourceUrlEncodingFilter and @AutoConfigureMockMvc:

https://github.com/schosin/AutoConfigureMockMvcErrorApplication

To see the StringIndexOutOfBoundsException, enable the profile errorhandling in application.properties.

[1] LookupPathIndexException

Caused by: org.springframework.web.servlet.resource.ResourceUrlEncodingFilter$LookupPathIndexException: Failed to find lookupPath '/' within requestUri ''. This could be because the path has invalid encoded characters or isn't normalized.
	at org.springframework.web.servlet.resource.ResourceUrlEncodingFilter$ResourceUrlEncodingRequestWrapper.initLookupPath(ResourceUrlEncodingFilter.java:102)
	at org.springframework.web.servlet.resource.ResourceUrlEncodingFilter$ResourceUrlEncodingRequestWrapper.setAttribute(ResourceUrlEncodingFilter.java:89)
	at org.springframework.web.servlet.resource.ResourceUrlProviderExposingInterceptor.preHandle(ResourceUrlProviderExposingInterceptor.java:53)

[2] IndexOutOfBoundsException

Caused by: java.lang.StringIndexOutOfBoundsException: Range [-1, 13) out of bounds for length 13
	at java.base/jdk.internal.util.Preconditions$1.apply(Preconditions.java:55) ~[na:na]
	at java.base/jdk.internal.util.Preconditions$1.apply(Preconditions.java:52) ~[na:na]
	at java.base/jdk.internal.util.Preconditions$4.apply(Preconditions.java:213) ~[na:na]
	at java.base/jdk.internal.util.Preconditions$4.apply(Preconditions.java:210) ~[na:na]
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:98) ~[na:na]
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckFromToIndex(Preconditions.java:112) ~[na:na]
	at java.base/jdk.internal.util.Preconditions.checkFromToIndex(Preconditions.java:349) ~[na:na]
	at java.base/java.lang.String.checkBoundsBeginEnd(String.java:4602) ~[na:na]
	at java.base/java.lang.String.substring(String.java:2715) ~[na:na]
	at org.springframework.web.servlet.resource.ResourceUrlEncodingFilter$ResourceUrlEncodingRequestWrapper.resolveUrlPath(ResourceUrlEncodingFilter.java:125) ~[spring-webmvc-6.0.4.jar:6.0.4]
	at org.springframework.web.servlet.resource.ResourceUrlEncodingFilter$ResourceUrlEncodingResponseWrapper.encodeURL(ResourceUrlEncodingFilter.java:159) ~[spring-webmvc-6.0.4.jar:6.0.4]
	at org.thymeleaf.web.servlet.JakartaServletWebExchange.transformURL(JakartaServletWebExchange.java:124) ~[thymeleaf-3.1.1.RELEASE.jar:3.1.1.RELEASE]
	at org.thymeleaf.linkbuilder.StandardLinkBuilder.processLink(StandardLinkBuilder.java:547) ~[thymeleaf-3.1.1.RELEASE.jar:3.1.1.RELEASE]
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Feb 6, 2023
@wilkinsona
Copy link
Member

Gitter discussion.

@QuantumXiecao
Copy link

QuantumXiecao commented Feb 6, 2023

This difference between @AutoConfigureMockMvc and MockMvcBuilder is that: spring boot's SpringBootMockMvcBuilderCustomizer would add some filters including ResourceUrlEncodingFilter to MockMvcBuilder which would directly leads to the LookupPathIndexException.
You can set @AutoConfigureMockMvc addFilters=false to solve this. @schosin @wilkinsona

@schosin
Copy link
Author

schosin commented Feb 6, 2023

As stated in the gitter discussion, the point of swapping to @AutoConfigureMockMvc was to add a custom filter. While the application works just fine when running it, ResourceUrlEncodingFilter seems to break tests that call the url "" when HttpServletResponse#encodeURL is invoked, with the SIOOBE being thrown when that same method is called again in an error handler.

If calls to "" aren't allowed and are rewritten to the requestURI "/" when running the actual application, shouldn't the same be happening when using mockMvc? That difference seems to be the root cause for this issue.

@sbrannen sbrannen added in: test Issues in the test module in: web Issues in web modules (web, webmvc, webflux, websocket) labels Feb 7, 2023
@rstoyanchev rstoyanchev added type: regression A bug that is also a regression and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Feb 14, 2023
@rstoyanchev rstoyanchev self-assigned this Feb 14, 2023
@rstoyanchev rstoyanchev added this to the 6.0.5 milestone Feb 14, 2023
@rstoyanchev
Copy link
Contributor

Thanks for the sample.

In 5.2.4, paths without a leading slash were disallowed in MockMvc to avoid ambiguity (#24556). In 6.0.4, empty path was excluded (#28823), but it leads to issues in some places. The request path should have a leading "/", and rather than allowing or rejecting an empty path, we can use "/" instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test Issues in the test module in: web Issues in web modules (web, webmvc, webflux, websocket) type: regression A bug that is also a regression
Projects
None yet
Development

No branches or pull requests

6 participants