You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pa...@apache.org on 2026/07/21 11:05:14 UTC

(felix-dev) 01/01: FELIX-6849 : Apply org.eclipse.jetty.UriComplianceMode to redirect URIs

This is an automated email from the ASF dual-hosted git repository.

paulrutter pushed a commit to branch FELIX-6849-redirect-uri-compliance
in repository https://gitbox.apache.org/repos/asf/felix-dev.git

commit d733f102f05aa481aae6a0c2497a1e7bed4f4f04
Author: Paul Rütter <pa...@blueconic.com>
AuthorDate: Tue Jul 21 13:04:14 2026 +0200

    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 <no...@anthropic.com>
---
 .../felix/http/jetty/internal/JettyService.java    |  5 +++++
 .../jetty/it/JettyUriComplianceModeDefaultIT.java  | 23 ++++++++++++++++++++++
 .../jetty/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 @@ public final class JettyService
             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 class JettyUriComplianceModeDefaultIT extends AbstractJettyTestSupport {
         }
     }
 
+    @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 class JettyUriComplianceModeLegacyIT extends JettyUriComplianceModeDefaul
             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