воскресенье, 24 июня 2018 г.

Spring MVC @PathVariable with encoded slashes, REST c прямыми слэшами в URL в значении переменной

Use case:
@RequestMapping("/path/{variableAbleCaptureSlashes:.+}
public ResponseEntity<String> method(@PathVariable("variableAbleCaptureSlashes") var) {
    // var must accept values like "/a/b/"
             // нужно, чтобы в var  могли падать значения с прямыми слэшами

}

Решение:
  • разрешить слэши в пути
    System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
  • отключить в UrlPathHelper url-декодирование 
    @Override    public void configurePathMatch(PathMatchConfigurer configurer) {
            UrlPathHelper urlPathHelper = new UrlPathHelperNonDecoding();        urlPathHelper.setUrlDecode(false);        configurer.setUrlPathHelper(urlPathHelper);    }
  • подставить кастомную имплементацию UrlPathHelper (https://jira.spring.io/browse/SPR-11101)
  • разрешить любые символы в значении pathvariable: @RequestMapping("/path/{variableAbleCaptureSlashes:.+}


@SpringBootApplication
@EnableErrorHandlingpublic class Application extends WebMvcConfigurerAdapter {
    public static void main(String[] args) {
        System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");        SpringApplication.run(Application.class, args);    }

    @Override    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelperNonDecoding();        urlPathHelper.setUrlDecode(false);        configurer.setUrlPathHelper(urlPathHelper);    }

    public class UrlPathHelperNonDecoding extends UrlPathHelper {

        public UrlPathHelperNonDecoding() {
            super.setUrlDecode(false);        }

        @Override        public void setUrlDecode(boolean urlDecode) {
            if (urlDecode) {
                throw new IllegalArgumentException("Handler does not support URL decoding.");            }
        }

        @Override        public String getServletPath(HttpServletRequest request) {
            String servletPath = getOriginatingServletPath(request);            return servletPath;        }


        @Override        public String getOriginatingServletPath(HttpServletRequest request) {
            String servletPath = request.getRequestURI().substring(request.getContextPath().length());            return servletPath;        }
    }
}