From d1d37534bf1f4de34f3c46ec37ea249aa3e76800 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Wed, 7 Oct 2020 11:31:52 +0100 Subject: [PATCH] Reinstate removal of jsessionid from lookup path Closes gh-25864 --- .../web/util/UrlPathHelper.java | 27 ++++++++++++++++-- .../web/util/UrlPathHelperTests.java | 2 +- ...questResponseBodyMethodProcessorTests.java | 9 +++--- ...nnotationControllerHandlerMethodTests.java | 28 ++++++++++++++++++- 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java b/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java index 14a20c7e080..260986bfa36 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java +++ b/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java @@ -521,7 +521,8 @@ public class UrlPathHelper { * @return the updated URI string */ public String removeSemicolonContent(String requestUri) { - return (this.removeSemicolonContent ? removeSemicolonContentInternal(requestUri) : requestUri); + return (this.removeSemicolonContent ? + removeSemicolonContentInternal(requestUri) : removeJsessionid(requestUri)); } private String removeSemicolonContentInternal(String requestUri) { @@ -535,6 +536,22 @@ public class UrlPathHelper { return requestUri; } + private String removeJsessionid(String requestUri) { + String key = ";jsessionid="; + int index = requestUri.toLowerCase().indexOf(key); + if (index == -1) { + return requestUri; + } + String start = requestUri.substring(0, index); + for (int i = key.length(); i < requestUri.length(); i++) { + char c = requestUri.charAt(i); + if (c == ';' || c == '/') { + return start + requestUri.substring(i); + } + } + return start; + } + /** * Decode the given URI path variables via {@link #decodeRequestString} unless * {@link #setUrlDecode} is set to {@code true} in which case it is assumed @@ -639,7 +656,13 @@ public class UrlPathHelper { *
  • {@code defaultEncoding=}{@link WebUtils#DEFAULT_CHARACTER_ENCODING} * */ - public static final UrlPathHelper rawPathInstance = new UrlPathHelper(); + public static final UrlPathHelper rawPathInstance = new UrlPathHelper() { + + @Override + public String removeSemicolonContent(String requestUri) { + return requestUri; + } + }; static { rawPathInstance.setAlwaysUseFullPath(true); diff --git a/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java b/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java index 361972f56ab..35f6c93b199 100644 --- a/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java @@ -133,7 +133,7 @@ public class UrlPathHelperTests { assertEquals("/foo;a=b;c=d", helper.getRequestUri(request)); request.setRequestURI("/foo;jsessionid=c0o7fszeb1"); - assertEquals("/foo;jsessionid=c0o7fszeb1", helper.getRequestUri(request)); + assertEquals("/foo", helper.getRequestUri(request)); } @Test diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorTests.java index 9f220860dfa..0999b040eff 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorTests.java @@ -380,15 +380,16 @@ public class RequestResponseBodyMethodProcessorTests { Collections.singletonList(new StringHttpMessageConverter()), factory.getObject()); - assertContentDisposition(processor, false, "/hello.json", "whitelisted extension"); + assertContentDisposition(processor, false, "/hello.json", "safe extension"); assertContentDisposition(processor, false, "/hello.pdf", "registered extension"); assertContentDisposition(processor, true, "/hello.dataless", "uknown extension"); // path parameters assertContentDisposition(processor, false, "/hello.json;a=b", "path param shouldn't cause issue"); - assertContentDisposition(processor, true, "/hello.json;a=b;setup.dataless", "uknown ext in path params"); - assertContentDisposition(processor, true, "/hello.dataless;a=b;setup.json", "uknown ext in filename"); - assertContentDisposition(processor, false, "/hello.json;a=b;setup.json", "whitelisted extensions"); + assertContentDisposition(processor, true, "/hello.json;a=b;setup.dataless", "unknown ext in path params"); + assertContentDisposition(processor, true, "/hello.dataless;a=b;setup.json", "unknown ext in filename"); + assertContentDisposition(processor, false, "/hello.json;a=b;setup.json", "safe extensions"); + assertContentDisposition(processor, true, "/hello.json;jsessionid=foo.bar", "jsessionid shouldn't cause issue"); // encoded dot assertContentDisposition(processor, true, "/hello%2Edataless;a=b;setup.json", "encoded dot in filename"); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServletAnnotationControllerHandlerMethodTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServletAnnotationControllerHandlerMethodTests.java index 28e15ed3c8d..e3e4d674715 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServletAnnotationControllerHandlerMethodTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServletAnnotationControllerHandlerMethodTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -86,6 +86,28 @@ public class UriTemplateServletAnnotationControllerHandlerMethodTests extends Ab assertEquals("test-42-7", response.getContentAsString()); } + @Test // gh-25864 + public void literalMappingWithPathParams() throws Exception { + initServletWithControllers(MultipleUriTemplateController.class); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/data"); + MockHttpServletResponse response = new MockHttpServletResponse(); + getServlet().service(request, response); + assertEquals(200, response.getStatus()); + assertEquals("test", response.getContentAsString()); + + request = new MockHttpServletRequest("GET", "/data;foo=bar"); + response = new MockHttpServletResponse(); + getServlet().service(request, response); + assertEquals(404, response.getStatus()); + + request = new MockHttpServletRequest("GET", "/data;jsessionid=123"); + response = new MockHttpServletResponse(); + getServlet().service(request, response); + assertEquals(200, response.getStatus()); + assertEquals("test", response.getContentAsString()); + } + @Test public void multiple() throws Exception { initServletWithControllers(MultipleUriTemplateController.class); @@ -405,6 +427,10 @@ public class UriTemplateServletAnnotationControllerHandlerMethodTests extends Ab writer.write("test-" + hotel + "-q" + qHotel + "-" + booking + "-" + other + "-q" + qOther); } + @RequestMapping("/data") + void handleWithLiteralMapping(Writer writer) throws IOException { + writer.write("test"); + } } @Controller