diff --git a/http/itest/pom.xml b/http/itest/pom.xml index f8c675ca2e..786df7a264 100644 --- a/http/itest/pom.xml +++ b/http/itest/pom.xml @@ -33,7 +33,7 @@ 17 6.1.0 - 2.0.1-SNAPSHOT + 2.0.3-SNAPSHOT org.apache.felix.http.jetty12 4.13.3 2.6.14 @@ -45,7 +45,7 @@ 11 6.1.0 - 5.2.3-SNAPSHOT + 5.2.5-SNAPSHOT org.apache.felix.http.jetty diff --git a/http/jetty12/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java b/http/jetty12/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java index a94634133c..fbeca92efc 100644 --- a/http/jetty12/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java +++ b/http/jetty12/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java @@ -788,6 +788,11 @@ private void configureHttpConnectionFactory(HttpConnectionFactory connFactory) try { UriCompliance compliance = UriCompliance.valueOf(uriComplianceMode); config.setUriCompliance(compliance); + // Apply the same compliance to redirect URIs (Location header). Since Jetty 12.1 + // this defaults to UriCompliance.DEFAULT_REDIRECT, which - like the request URI + // default - rejects ambiguous encodings such as %2F. Differentiating the two makes + // no sense: if a deployment opts into a compliance mode it should apply end-to-end. + config.setRedirectUriCompliance(compliance); if (LEGACY.equals(compliance) || UNSAFE.equals(compliance) || UNAMBIGUOUS.equals(compliance)) { // See https://github.com/jetty/jetty.project/issues/11448#issuecomment-1969206031 diff --git a/http/jetty12/src/test/java/org/apache/felix/http/jetty/it/JettyUriComplianceModeDefaultIT.java b/http/jetty12/src/test/java/org/apache/felix/http/jetty/it/JettyUriComplianceModeDefaultIT.java index 5d90217097..e3c34e86fc 100644 --- a/http/jetty12/src/test/java/org/apache/felix/http/jetty/it/JettyUriComplianceModeDefaultIT.java +++ b/http/jetty12/src/test/java/org/apache/felix/http/jetty/it/JettyUriComplianceModeDefaultIT.java @@ -115,9 +115,32 @@ public void testUriCompliance() throws Exception { } } + @Test + public void testRedirectUriCompliance() throws Exception { + try (HttpClient httpClient = new HttpClient()) { + httpClient.setFollowRedirects(false); + httpClient.start(); + Object value = bundleContext.getServiceReference(HttpService.class).getProperty("org.osgi.service.http.port"); + int httpPort = Integer.parseInt((String) value); + + URI destUriRedirect = new URI(String.format("http://localhost:%d/endpoint/redirect", httpPort)); + + // The endpoint issues a redirect whose Location contains an ambiguous %2F. + // With the default redirect compliance (DEFAULT_REDIRECT) this is rejected, + // surfacing as an internal server error rather than a 302. + ContentResponse response = httpClient.GET(destUriRedirect); + assertEquals(500, response.getStatus()); + } + } + static final class UriComplianceEndpoint extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + if (req.getRequestURI().contains("redirect")) { + // Location deliberately contains an ambiguous encoded separator (%2F) + resp.sendRedirect("/endpoint/redirected%2Ftarget"); + return; + } resp.setStatus(200); resp.getWriter().write("OK"); } diff --git a/http/jetty12/src/test/java/org/apache/felix/http/jetty/it/JettyUriComplianceModeLegacyIT.java b/http/jetty12/src/test/java/org/apache/felix/http/jetty/it/JettyUriComplianceModeLegacyIT.java index 8b2944bc5d..31f9375530 100644 --- a/http/jetty12/src/test/java/org/apache/felix/http/jetty/it/JettyUriComplianceModeLegacyIT.java +++ b/http/jetty12/src/test/java/org/apache/felix/http/jetty/it/JettyUriComplianceModeLegacyIT.java @@ -64,4 +64,23 @@ public void testUriCompliance() throws Exception { assertEquals("OK", response2.getContentAsString()); } } + + @Test + @Override + public void testRedirectUriCompliance() throws Exception { + try (HttpClient httpClient = new HttpClient()) { + httpClient.setFollowRedirects(false); + httpClient.start(); + Object value = bundleContext.getServiceReference(HttpService.class).getProperty("org.osgi.service.http.port"); + int httpPort = Integer.parseInt((String) value); + + URI destUriRedirect = new URI(String.format("http://localhost:%d/endpoint/redirect", httpPort)); + + // With LEGACY compliance the ambiguous %2F in the Location header is allowed, + // so the redirect is emitted normally instead of being rejected. + ContentResponse response = httpClient.GET(destUriRedirect); + assertEquals(302, response.getStatus()); + assertEquals("/endpoint/redirected%2Ftarget", response.getHeaders().get("Location")); + } + } } \ No newline at end of file