From 71bbf492031dafc0086375240beb0d07c8edc6ba Mon Sep 17 00:00:00 2001 From: Andy McCright Date: Tue, 17 Nov 2020 14:43:31 -0600 Subject: [PATCH] [RESTEASY-2771] Decode RequestURL Signed-off-by: Andy McCright --- resteasy-core/pom.xml | 13 +++ .../plugins/server/servlet/ServletUtil.java | 45 ++++++-- .../server/servlet/ServletUtilTest.java | 107 ++++++++++++++++++ 3 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 resteasy-core/src/test/java/org/jboss/resteasy/plugins/server/servlet/ServletUtilTest.java diff --git a/resteasy-core/pom.xml b/resteasy-core/pom.xml index c54925b5bd6..0aa3293b6c6 100644 --- a/resteasy-core/pom.xml +++ b/resteasy-core/pom.xml @@ -61,6 +61,19 @@ test + + org.mockito + mockito-core + 1.9.5 + + + org.hamcrest + hamcrest-core + + + test + + org.apache.logging.log4j log4j-api diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/server/servlet/ServletUtil.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/server/servlet/ServletUtil.java index 77e010cbd97..23325d7edd7 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/server/servlet/ServletUtil.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/server/servlet/ServletUtil.java @@ -11,11 +11,16 @@ import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.ArrayList; +import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * @author Bill Burke @@ -29,16 +34,35 @@ public static ResteasyUriInfo extractUriInfo(HttpServletRequest request, String if (servletPrefix != null && servletPrefix.length() > 0 && !servletPrefix.equals("/")) { if (!contextPath.endsWith("/") && !servletPrefix.startsWith("/")) - contextPath += "/"; + contextPath += "/"; contextPath += servletPrefix; } String queryString = request.getQueryString(); String absolute; - if (queryString != null && queryString.length() > 0) { + if (queryString != null && queryString.length() > 0) + { absolute = request.getRequestURL().append('?').append(queryString).toString(); - } else { + } + else + { absolute = request.getRequestURL().toString(); } + if (!absolute.contains(contextPath)) + { + String encodedContextPath = Arrays.stream(contextPath.substring(1).split("/")) + .map(s -> { + try { + return URLEncoder.encode(s, "UTF-8"); + } catch (UnsupportedEncodingException ex) { + return s; + } + }) + .collect(Collectors.joining("/", "/", "")); + if (absolute.contains(encodedContextPath)) + { + absolute = absolute.replace(encodedContextPath, contextPath); + } + } return new ResteasyUriInfo(absolute, contextPath); } @@ -49,7 +73,8 @@ public static ResteasyHttpHeaders extractHttpHeaders(HttpServletRequest request) ResteasyHttpHeaders headers = new ResteasyHttpHeaders(requestHeaders); String contentType = request.getContentType(); - if (contentType != null) headers.getMutableHeaders().putSingle(HttpHeaders.CONTENT_TYPE, contentType); + if (contentType != null) + headers.getMutableHeaders().putSingle(HttpHeaders.CONTENT_TYPE, contentType); Map cookies = extractCookies(request); headers.setCookies(cookies); @@ -68,7 +93,8 @@ static Map extractCookies(HttpServletRequest request) { for (javax.servlet.http.Cookie cookie : request.getCookies()) { - cookies.put(cookie.getName(), new Cookie(cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getDomain(), cookie.getVersion())); + cookies.put(cookie.getName(), new Cookie(cookie.getName(), cookie.getValue(), cookie.getPath(), + cookie.getDomain(), cookie.getVersion())); } } @@ -79,7 +105,8 @@ public static List extractAccepts(MultivaluedMap requ { List acceptableMediaTypes = new ArrayList(); List accepts = requestHeaders.get(HttpHeaderNames.ACCEPT); - if (accepts == null) return acceptableMediaTypes; + if (accepts == null) + return acceptableMediaTypes; for (String accept : accepts) { @@ -92,12 +119,14 @@ public static List extractLanguages(MultivaluedMap reque { List acceptable = new ArrayList(); List accepts = requestHeaders.get(HttpHeaderNames.ACCEPT_LANGUAGE); - if (accepts == null) return acceptable; + if (accepts == null) + return acceptable; for (String accept : accepts) { String[] splits = accept.split(","); - for (String split : splits) acceptable.add(split.trim()); + for (String split : splits) + acceptable.add(split.trim()); } return acceptable; } diff --git a/resteasy-core/src/test/java/org/jboss/resteasy/plugins/server/servlet/ServletUtilTest.java b/resteasy-core/src/test/java/org/jboss/resteasy/plugins/server/servlet/ServletUtilTest.java new file mode 100644 index 00000000000..a1ef902fd49 --- /dev/null +++ b/resteasy-core/src/test/java/org/jboss/resteasy/plugins/server/servlet/ServletUtilTest.java @@ -0,0 +1,107 @@ +package org.jboss.resteasy.plugins.server.servlet; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import javax.servlet.http.HttpServletRequest; + +import org.jboss.resteasy.specimpl.ResteasyUriInfo; +import org.junit.Test; + +public class ServletUtilTest { + + @Test + public void extractUriInfo_simple() { + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getContextPath()).thenReturn(""); + when(request.getQueryString()).thenReturn(null); + when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8000/app/resource")); + ResteasyUriInfo rui = ServletUtil.extractUriInfo(request, null); + assertEquals("", rui.getContextPath()); + assertEquals("/app/resource", rui.getPath()); + } + + @Test + public void extractUriInfo_simpleWithContextRoot() { + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getContextPath()).thenReturn("/contextRoot"); + when(request.getQueryString()).thenReturn(null); + when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8000/contextRoot/app/resource")); + ResteasyUriInfo rui = ServletUtil.extractUriInfo(request, null); + assertEquals("/contextRoot", rui.getContextPath()); + assertEquals("/app/resource", rui.getPath()); + } + + @Test + public void extractUriInfo_encoded() + { + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getContextPath()).thenReturn(""); + when(request.getQueryString()).thenReturn(null); + when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8000/app/resource!")); + ResteasyUriInfo rui = ServletUtil.extractUriInfo(request, null); + assertEquals("", rui.getContextPath()); + assertEquals("/app/resource!", rui.getPath()); + + request = mock(HttpServletRequest.class); + when(request.getContextPath()).thenReturn(""); + when(request.getQueryString()).thenReturn(null); + when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8000/app/resource%21")); + rui = ServletUtil.extractUriInfo(request, null); + assertEquals("", rui.getContextPath()); + assertEquals("/app/resource!", rui.getPath()); + + request = mock(HttpServletRequest.class); + when(request.getContextPath()).thenReturn(""); + when(request.getQueryString()).thenReturn(null); + when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8000/app!/resource")); + rui = ServletUtil.extractUriInfo(request, null); + assertEquals("", rui.getContextPath()); + assertEquals("/app!/resource", rui.getPath()); + + request = mock(HttpServletRequest.class); + when(request.getContextPath()).thenReturn(""); + when(request.getQueryString()).thenReturn(null); + when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8000/app%21/resource")); + rui = ServletUtil.extractUriInfo(request, null); + assertEquals("", rui.getContextPath()); + assertEquals("/app!/resource", rui.getPath()); + } + + @Test + public void extractUriInfo_encodedWithContextRoot() + { + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getContextPath()).thenReturn("/contextRoot"); + when(request.getQueryString()).thenReturn(null); + when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8000/contextRoot/app/resource!")); + ResteasyUriInfo rui = ServletUtil.extractUriInfo(request, null); + assertEquals("/contextRoot", rui.getContextPath()); + assertEquals("/app/resource!", rui.getPath()); + + request = mock(HttpServletRequest.class); + when(request.getContextPath()).thenReturn("/contextRoot"); + when(request.getQueryString()).thenReturn(null); + when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8000/contextRoot/app/resource%21")); + rui = ServletUtil.extractUriInfo(request, null); + assertEquals("/contextRoot", rui.getContextPath()); + assertEquals("/app/resource!", rui.getPath()); + + request = mock(HttpServletRequest.class); + when(request.getContextPath()).thenReturn("/contextRoot"); + when(request.getQueryString()).thenReturn(null); + when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8000/contextRoot/app!/resource")); + rui = ServletUtil.extractUriInfo(request, null); + assertEquals("/contextRoot", rui.getContextPath()); + assertEquals("/app!/resource", rui.getPath()); + + request = mock(HttpServletRequest.class); + when(request.getContextPath()).thenReturn("/contextRoot"); + when(request.getQueryString()).thenReturn(null); + when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8000/contextRoot/app%21/resource")); + rui = ServletUtil.extractUriInfo(request, null); + assertEquals("/contextRoot", rui.getContextPath()); + assertEquals("/app!/resource", rui.getPath()); + } +}