0

version info:

Server version: Apache Tomcat/9.0.17
Server built: Mar 13 2019 15:55:27 UTC
Server number: 9.0.17.0
OS Name: Windows 8.1
OS Version: 6.3
Architecture: amd64
JVM Version: 1.8.0_40-b25

spring-boot-2.1.4
spring-core-5.1.6

I have a html page like this: localhost/example/37%.html
(sorry I can not start url with http// because the edit page will auto-change it to link and will add 25 after %)
when I access this url,I got an error:HTTP Status 400.
It should be, because the % is a escape char.
so I changed the url to: localhost/example/37%25.html.
this time,I got a new error:

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Sep 03 09:25:13 CST 2020
There was an unexpected error (type=Internal Server Error, status=500).
URLDecoder: Illegal hex characters in escape (%) pattern - For input string: ".h"

I checked tomcat console,it outputs error message:

2020-09-03 09:25:12 [http-nio-8080-exec-3] ERROR 
o.s.b.w.s.support.ErrorPageFilter - Forwarding to error page from request [/37%.html] due to exception [URLDecoder: Illegal hex characters in escape (%) pattern - For input string: ".h"]
java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape(%) pattern - For input string: ".h" 
at java.net.URLDecoder.decode(URLDecoder.java:194)  
at org.springframework.web.servlet.resource.PathResourceResolver.isInvalidEncodedPath(PathResourceResolver.java:285)
at org.springframework.web.servlet.resource.PathResourceResolver.isResourceUnderLocation(PathResourceResolver.java:254)

It seems like tomcat(or browser) has been decode %25 to %,but springboot still to decode % again (PathResourceResolver.java)

I don't know whether this is an bug issue or this is a right way that springboot do not allow % in url

1 Answers1

0

I found something interesting.

now I have two webpages, one named 37%.html,other named 37%25.html

Follow the logic of springboot that it will decode % twice, I accessed this url:

localhost/example/37%2525.html

and it will show me the 37%.html, BUT, it show me the 37%25.html.

so,how many times or how to the springboot decode % ???

then I found two class file in springboot:
ResourceHttpRequestHandler.java
PathResourceResolver.java

they all have a function named: isInvalidEncodedPath()

code is here:

ResourceHttpRequestHandler.isInvalidEncodedPath(path)

private boolean isInvalidEncodedPath(String path) {
    if(path.contains("%")) {
        try {
            String decodedPath = URLDecoder.decode(path, "UTF-8");
            if(this.isInvalidPath(decodedPath)) {
                return true;
            }

            decodedPath = this.processPath(decodedPath);
            if(this.isInvalidPath(decodedPath)) {
                return true;
            }
        } catch (UnsupportedEncodingException | IllegalArgumentException var3) {
            ;
        }
    }

    return false;
}

PathResourceResolver.isInvalidEncodedPath(resourcePath)

private boolean isInvalidEncodedPath(String resourcePath) {
    if(resourcePath.contains("%")) {
        try {
            String decodedPath = URLDecoder.decode(resourcePath, "UTF-8");
            if(decodedPath.contains("../") || decodedPath.contains("..\\")) {
                this.logger.warn("Resolved resource path contains encoded \"../\" or \"..\\\": " + resourcePath);
                return true;
            }
        } catch (UnsupportedEncodingException var3) {
            ;
        }
    }

    return false;
}   

see something different?? they both do URLDecoder.decode(resourcePath, "UTF-8"),but catch different exceptions.

when you access url,springboot will call the funcion at this order:

1 ResourceHttpRequestHandler.isInvalidEncodedPath(path)
2 PathResourceResolver.isInvalidEncodedPath(resourcePath)

so when hit the /37%25.html, in ResourceHttpRequestHandler.isInvalidEncodedPath(path),it gets /37%.html,because tomcat(or browser) decode %25 to %. then URLDecoder.decode("/37%.html", "UTF-8"), trigger IllegalArgumentException, be catched, but do nothing, return false. In PathResourceResolver.isInvalidEncodedPath(resourcePath),URLDecoder.decode("/37%.html", "UTF-8"),trigger IllegalArgumentException, no catced, throw the exception.

when hit the /37%2525.html, in ResourceHttpRequestHandler.isInvalidEncodedPath(path),it gets /37%25.html, URLDecoder.decode("/37%25.html", "UTF-8"),no problem. In PathResourceResolver.isInvalidEncodedPath(resourcePath),URLDecoder.decode("/37%25.html", "UTF-8"),also no problem.then display the 37%25.html

If you just type /37%.html,u will get 400 error, Invalid URI: isHexDigit.

so,unfortunately, the url which has % char, can not be accessed correctly.

  • O,an other interesting. If you are using jrebel for debug in IDEA, and you will not see the error.every page is good! because PathResourceResolver.isInvalidEncodedPath(resourcePath) will not be called. I don't know WHY .... (jrebel version 2018.1.6) – steven01997 Sep 07 '20 at 06:28