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>