Enable percent encoding servlet context path and servlet path Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java index 9a91ec9..522ba33 100644 --- a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java +++ b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -288,16 +288,8 @@ * We need to work around this and not use getPathInfo * for the decodedPath. */ - final String decodedBasePath = request.getContextPath() + servletPath + "/"; - - final String encodedBasePath = UriComponent.encode(decodedBasePath, - UriComponent.Type.PATH); - - if (!decodedBasePath.equals(encodedBasePath)) { - setResponseForInvalidUri(response, new ProcessingException("The servlet context path and/or the " - + "servlet path contain characters that are percent encoded")); - return; - } + final String encodedBasePath = UriComponent.contextualEncode( + request.getContextPath() + servletPath, UriComponent.Type.PATH) + "/"; final URI baseUri; final URI requestUri;
diff --git a/containers/jersey-servlet-core/src/test/java/org/glassfish/jersey/servlet/internal/ContextPathEncodingTest.java b/containers/jersey-servlet-core/src/test/java/org/glassfish/jersey/servlet/internal/ContextPathEncodingTest.java new file mode 100644 index 0000000..9ab2e92 --- /dev/null +++ b/containers/jersey-servlet-core/src/test/java/org/glassfish/jersey/servlet/internal/ContextPathEncodingTest.java
@@ -0,0 +1,155 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.servlet.internal; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.glassfish.jersey.internal.util.collection.Value; +import org.glassfish.jersey.internal.util.collection.Values; +import org.glassfish.jersey.servlet.ServletContainer; +import org.junit.Assert; +import org.junit.Test; + +import java.io.IOException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.URI; + +/** + * Context encoding test. See Jersey-4949. + */ +public class ContextPathEncodingTest { + private static final String PATH = "A%20B"; + private static final String CONTEXT = "c%20ntext"; + + @Test + public void contextEncodingTest() throws ServletException, IOException { + // In jetty maven plugin, context is set by + //<configuration> + // <scan>10</scan> + // <webApp> + // <contextPath>/c ntext</contextPath> + // </webApp> + //</configuration> + + //Servlet path is not encoded, context is encoded + final ServletRequestValues servletRequestValues = new ServletRequestValues( + "/" + CONTEXT, + "", + "/" + CONTEXT + "/" + PATH + ); + final EncodingTestServletContainer testServletContainer = new EncodingTestServletContainer( + "/" + CONTEXT + "/", + "/" + CONTEXT + "/" + PATH + ); + EncodingTestData testData = new EncodingTestData(servletRequestValues, testServletContainer); + + testData.test(); + } + + @Test + public void servletPathEncodingTest() throws ServletException, IOException { + //Servlet path is not encoded, context is encoded + final ServletRequestValues servletRequestValues = new ServletRequestValues( + "/", + "A B", + "/" + PATH + "/" + PATH + ); + final EncodingTestServletContainer testServletContainer = new EncodingTestServletContainer( + "/" + PATH + "/", + "/" + PATH + "/" + PATH + ); + EncodingTestData testData = new EncodingTestData(servletRequestValues, testServletContainer); + + testData.test(); + } + + static class EncodingTestData { + final ServletRequestValues servletRequestValues; + final EncodingTestServletContainer encodingTestServletContainer; + final HttpServletRequest httpServletRequest; + + EncodingTestData(ServletRequestValues servletRequestValues, EncodingTestServletContainer encodingTestServletContainer) { + this.servletRequestValues = servletRequestValues; + this.encodingTestServletContainer = encodingTestServletContainer; + this.httpServletRequest = (HttpServletRequest) Proxy.newProxyInstance(getClass().getClassLoader(), + new Class[]{HttpServletRequest.class}, new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + return servletRequestValues.handle(method.getName()); + } + }); + } + + public void test() throws ServletException, IOException { + encodingTestServletContainer.service(httpServletRequest, (HttpServletResponse) null); + } + + } + + static class ServletRequestValues { + final String servletPath; + final String requestUri; + final String contextPath; + + ServletRequestValues(String contextPath, String servletPath, String requestUri) { + this.servletPath = servletPath; + this.requestUri = requestUri; + this.contextPath = contextPath; + } + + Object handle(String name) { + switch (name) { + case "getServletPath": + return servletPath; + case "getRequestURI": + return requestUri; + case "getRequestURL": + return new StringBuffer(requestUri); + case "getContextPath": + return contextPath; + default: + return null; + } + } + } + + static class EncodingTestServletContainer extends ServletContainer { + final String baseUri; + final String requestUri; + + EncodingTestServletContainer(String baseUri, String requestUri) { + this.baseUri = baseUri; + this.requestUri = requestUri; + } + + @Override + public Value<Integer> service(URI baseUri, URI requestUri, HttpServletRequest request, HttpServletResponse response) { + Assert.assertEquals(this.baseUri, baseUri.toASCIIString()); + Assert.assertEquals(this.requestUri, requestUri.toASCIIString()); + return Values.of(0); + } + + //Update visibility + public void service(final HttpServletRequest request, final HttpServletResponse response) + throws ServletException, IOException { + super.service(request, response); + } + }; +}
diff --git a/tests/integration/jersey-4949/pom.xml b/tests/integration/jersey-4949/pom.xml new file mode 100644 index 0000000..02cca4d --- /dev/null +++ b/tests/integration/jersey-4949/pom.xml
@@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License v. 2.0, which is available at + http://www.eclipse.org/legal/epl-2.0. + + This Source Code may also be made available under the following Secondary + Licenses when the conditions for such availability set forth in the + Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + version 2 with the GNU Classpath Exception, which is available at + https://www.gnu.org/software/classpath/license.html. + + SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.glassfish.jersey.tests.integration</groupId> + <artifactId>project</artifactId> + <version>2.36-SNAPSHOT</version> + </parent> + + <artifactId>jersey-4949</artifactId> + <packaging>war</packaging> + <name>jersey-tests-integration-jersey-4949</name> + + <description>Servlet integration test - JERSEY-4949 - Encoded Jetty Path</description> + + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-servlet-core</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.test-framework.providers</groupId> + <artifactId>jersey-test-framework-provider-external</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.test-framework.providers</groupId> + <artifactId>jersey-test-framework-provider-grizzly2</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-failsafe-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-maven-plugin</artifactId> + <configuration> + <scan>10</scan> + <webApp> + <contextPath>/c ntext</contextPath> + </webApp> + </configuration> + </plugin> + </plugins> + </build> + +</project>
diff --git a/tests/integration/jersey-4949/src/main/java/org/glassfish/jersey/tests/integration/jersey4949/Issue4949Resource.java b/tests/integration/jersey-4949/src/main/java/org/glassfish/jersey/tests/integration/jersey4949/Issue4949Resource.java new file mode 100644 index 0000000..b6d34a7 --- /dev/null +++ b/tests/integration/jersey-4949/src/main/java/org/glassfish/jersey/tests/integration/jersey4949/Issue4949Resource.java
@@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.integration.jersey4949; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.UriInfo; + +/** + * Test resource. + */ +@Path("/") +public class Issue4949Resource { + public static final String PATH = "0.0.2%20-%20Market%20Data%20Import"; + @GET + @Path(PATH) + public String get(@Context UriInfo uriInfo) { + return uriInfo.getRequestUri().toASCIIString(); + } + + @GET + @Path("echo") + public String echo(@Context UriInfo uriInfo) { + return uriInfo.getRequestUri().toASCIIString(); + } +}
diff --git a/tests/integration/jersey-4949/src/main/java/org/glassfish/jersey/tests/integration/jersey4949/Jersey4949.java b/tests/integration/jersey-4949/src/main/java/org/glassfish/jersey/tests/integration/jersey4949/Jersey4949.java new file mode 100644 index 0000000..6c625fc --- /dev/null +++ b/tests/integration/jersey-4949/src/main/java/org/glassfish/jersey/tests/integration/jersey4949/Jersey4949.java
@@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.integration.jersey4949; + +import org.glassfish.jersey.server.ResourceConfig; + +/** + * JAX-RS application for the JERSEY-4949 reproducer test. + */ +public class Jersey4949 extends ResourceConfig { + + public Jersey4949() { + register(Issue4949Resource.class); + } +}
diff --git a/tests/integration/jersey-4949/src/main/webapp/WEB-INF/web.xml b/tests/integration/jersey-4949/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..b337657 --- /dev/null +++ b/tests/integration/jersey-4949/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License v. 2.0, which is available at + http://www.eclipse.org/legal/epl-2.0. + + This Source Code may also be made available under the following Secondary + Licenses when the conditions for such availability set forth in the + Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + version 2 with the GNU Classpath Exception, which is available at + https://www.gnu.org/software/classpath/license.html. + + SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + +--> + +<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> + <servlet> + <servlet-name>jersey4949Servlet</servlet-name> + <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> + <init-param> + <param-name>javax.ws.rs.Application</param-name> + <param-value>org.glassfish.jersey.tests.integration.jersey4949.Jersey4949</param-value> + </init-param> + <load-on-startup>1</load-on-startup> + </servlet> + <servlet-mapping> + <servlet-name>jersey4949Servlet</servlet-name> + <url-pattern>/A B/*</url-pattern> + </servlet-mapping> +</web-app>
diff --git a/tests/integration/jersey-4949/src/test/java/org/glassfish/jersey/tests/integration/jersey4949/Jersey4949ITCase.java b/tests/integration/jersey-4949/src/test/java/org/glassfish/jersey/tests/integration/jersey4949/Jersey4949ITCase.java new file mode 100644 index 0000000..9ddaa1e --- /dev/null +++ b/tests/integration/jersey-4949/src/test/java/org/glassfish/jersey/tests/integration/jersey4949/Jersey4949ITCase.java
@@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.integration.jersey4949; + +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Response; + +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.external.ExternalTestContainerFactory; +import org.glassfish.jersey.test.spi.TestContainerException; +import org.glassfish.jersey.test.spi.TestContainerFactory; + +import org.junit.Assert; +import org.junit.Test; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Reproducer tests for JERSEY-4949. + */ +public class Jersey4949ITCase extends JerseyTest { + + private static final String CONTEXT_PATH = "c%20ntext"; + private static final String SERVLET_PATH = "A%20B"; + + @Override + protected Application configure() { + return new Jersey4949(); + } + + @Override + protected TestContainerFactory getTestContainerFactory() throws TestContainerException { + //return new org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory(); + return new ExternalTestContainerFactory(); + } + + /** + * Reproducer method for JERSEY-4949. + */ + @Test + public void testJersey4949Fix() { + try (Response response = target(CONTEXT_PATH).path(SERVLET_PATH).path(Issue4949Resource.PATH).request().get()) { + assertThat(response.getStatus(), is(200)); + + String entity = response.readEntity(String.class); + Assert.assertTrue(entity.contains(CONTEXT_PATH)); + Assert.assertTrue(entity.contains(SERVLET_PATH)); + Assert.assertTrue(entity.contains(Issue4949Resource.PATH)); + } + } +}
diff --git a/tests/integration/pom.xml b/tests/integration/pom.xml index e44118d..385ee00 100644 --- a/tests/integration/pom.xml +++ b/tests/integration/pom.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved. Copyright (c) 2018 Payara Foundation and/or its affiliates. All rights reserved. This program and the accompanying materials are made available under the @@ -91,6 +91,7 @@ <module>jersey-4542</module> <module>jersey-4697</module> <module>jersey-4722</module> + <module>jersey-4949</module> <module>jetty-response-close</module> <module>microprofile</module> <module>portability-jersey-1</module>