From d733f102f05aa481aae6a0c2497a1e7bed4f4f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20R=C3=BCtter?= Date: Tue, 21 Jul 2026 13:04:14 +0200 Subject: [PATCH 1/3] FELIX-6849 : Apply org.eclipse.jetty.UriComplianceMode to redirect URIs Felix jetty12 mapped the org.eclipse.jetty.UriComplianceMode property to HttpConfiguration.setUriCompliance() only, leaving redirect URI compliance at Jetty's default. Since Jetty 12.1 that default rejects ambiguous encodings (e.g. %2F) in the Location header, so a deployment relaxing request URI compliance (e.g. LEGACY) still had its redirects rejected. Apply the configured compliance to setRedirectUriCompliance() as well, so the mode takes effect end-to-end. Behavior is unchanged when the property is unset (Jetty defaults still apply). Added redirect URI compliance coverage to the default and LEGACY integration tests. Co-Authored-By: Claude Opus 4.8 --- .../http/jetty/internal/JettyService.java | 5 ++++ .../it/JettyUriComplianceModeDefaultIT.java | 23 +++++++++++++++++++ .../it/JettyUriComplianceModeLegacyIT.java | 19 +++++++++++++++ 3 files changed, 47 insertions(+) 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 b14504bab5..fd156328d8 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 @@ -784,6 +784,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 From 249f29de249e51b9b30bb78076bae791a6d2a6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20R=C3=BCtter?= Date: Tue, 21 Jul 2026 13:17:07 +0200 Subject: [PATCH 2/3] FELIX-6849 : Fix itest http.jetty.version to match current jetty12 module The itest default http.jetty.version was still 2.0.1-SNAPSHOT, while the jetty12 module is now 2.0.3-SNAPSHOT. The stale reference transitively pulled in org.apache.felix.http.base:6.0.0-SNAPSHOT, which no longer exists (base is now 6.0.1-SNAPSHOT), breaking dependency resolution in CI. Bump the property to 2.0.3-SNAPSHOT so the current in-reactor jetty12 (and http.base 6.0.1-SNAPSHOT) is used. Co-Authored-By: Claude Opus 4.8 --- http/itest/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http/itest/pom.xml b/http/itest/pom.xml index f8c675ca2e..a700867c3f 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 From 670a92d3b9c8148b6caa8cde0f1a51c3c8412496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20R=C3=BCtter?= Date: Tue, 21 Jul 2026 13:19:34 +0200 Subject: [PATCH 3/3] FELIX-6849 : Bump itest jetty11 profile to current jetty9 module version The jetty11 profile still pinned http.jetty.version=5.2.3-SNAPSHOT, while the jetty (jetty9) module is now 5.2.5-SNAPSHOT. Align it so that profile resolves the current in-reactor module (and http.base 6.0.1-SNAPSHOT) instead of a stale, non-existent snapshot. Co-Authored-By: Claude Opus 4.8 --- http/itest/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http/itest/pom.xml b/http/itest/pom.xml index a700867c3f..786df7a264 100644 --- a/http/itest/pom.xml +++ b/http/itest/pom.xml @@ -45,7 +45,7 @@ 11 6.1.0 - 5.2.3-SNAPSHOT + 5.2.5-SNAPSHOT org.apache.felix.http.jetty