How to rewrite path before request is parsed?

41 Views Asked by At

I need to match these GET requests /debug, /debug?page=xy and for compatibility /debug;page=xy as well. I can match the first two, but struggle to implement the third with matrix variables and after that still need to figure out how to combine the two, so I'm exploring other options. Since I expect at most one parameter, I think it would be neat to just be able to take the incoming request URL and just replace /debug; with /debug? before the parameters are parsed so page is always interpreted as a query parameter.

As I understand, I can simply write a filter in which I put the incoming request in a wrapper and pass on the wrapped request. so, following https://www.baeldung.com/spring-boot-3-url-matching I added

@Component
class SemicolonRedirectFilter: Filter {

    @Throws(IOException::class, ServletException::class)
    override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain)  {

        val httpRequest: HttpServletRequest = request as HttpServletRequest
        val path: String = httpRequest.requestURI

        if (httpRequest.method == "GET" && path.startsWith("/debug;")) {
            chain.doFilter(CustomHttpServletRequestWrapper(request), response)
        } else {
            chain.doFilter(request, response)
        }

    }


    private class CustomHttpServletRequestWrapper(request: HttpServletRequest) :
        HttpServletRequestWrapper(request) {

        private val newPath: String = request.requestURI.replaceFirst("/debug;", "/debug?")

        override fun getRequestURI(): String = newPath

        override fun getRequestURL(): StringBuffer {
            val url = StringBuffer()
            url.append(scheme).append("://").append(serverName).append(":").append(serverPort).append(newPath)
            return url
        }
    }

}

and

@Component
class WebConfig(@field:Autowired private val semicolonFilter: SemicolonRedirectFilter) {

    @Bean
    fun semicolonFilter(): FilterRegistrationBean<Filter> {
        val registrationBean: FilterRegistrationBean<Filter> = FilterRegistrationBean<Filter>()
        registrationBean.setFilter(semicolonFilter)
        registrationBean.addUrlPatterns("/*")
        return registrationBean
    }
}

But I think my filter is applied too late, because at the point where /debug?page=10 and /debug;page=10 enter my doFilter function /debug?page=10 is already partitioned into path = '/debug' and queryString = 'page=10'. I tried to solve it with the @Order annotation on my filter, but even with @Order(Ordered.HIGHEST_PRECEDENCE) or @Order(OrderedFilter.HIGHEST_PRECEDENCE) the URI is already truncated for /debug?page=10. Is there a way to get access to the request earlier in the call chain?

Update: I made it work by overriding getQueryString() and getParameterValues(name: String?) as well in my CustomHttpServletRequestWrapper, it feels hacky though...

0

There are 0 best solutions below