[ 
https://issues.apache.org/jira/browse/FELIX-6849?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Paul Rütter updated FELIX-6849:
-------------------------------
    Description: 
Since Jetty 12.1, {{HttpConfiguration}} applies URI compliance checks to the 
{{Location}} header of HTTP redirects via 
{{{}setRedirectUriCompliance(UriCompliance){}}}, separately from the 
request-URI check ({{{}setUriCompliance{}}}):
 * Jetty 12.0.x: redirect default {{null}} → no check on redirect URIs (Jetty 
9.x-like).
 * Jetty 12.1.0–12.1.5: redirect default {{UriCompliance.DEFAULT}} → ambiguous 
URIs (e.g. encoded {{%2F}} / {{{}AMBIGUOUS_PATH_SEPARATOR{}}}) in the 
{{Location}} header are rejected.
 * Jetty 12.1.6+ 
([jetty/jetty.project#14264|https://github.com/jetty/jetty.project/issues/14264]):
 redirect default {{UriCompliance.DEFAULT_REDIRECT}} (= {{{}DEFAULT{}}}, 
additionally tolerating a URI fragment). Still rejects {{{}%2F{}}}.

*Problem*

Felix maps the {{org.eclipse.jetty.UriComplianceMode}} property to 
{{HttpConfiguration.setUriCompliance(...)}} only (see 
{{{}JettyService.getHttpConfiguration{}}}). It never calls 
{{{}setRedirectUriCompliance(...){}}}.

As a result, an application that sets 
{{org.eclipse.jetty.UriComplianceMode=LEGACY}} to preserve Jetty 9.x handling 
of ambiguous encodings (e.g. {{{}%2F{}}}) gets that behavior for incoming 
*request* URIs, but any redirect whose {{Location}} still contains {{%2F}} is 
rejected by Jetty's default {{{}DEFAULT_REDIRECT{}}}. There is no way to relax 
redirect compliance from Felix configuration, so the request-side relaxation is 
effectively undone on redirects.

*Proposal*

Reuse the existing {{org.eclipse.jetty.UriComplianceMode}} property to drive 
*both* setters. Differentiating request vs. redirect compliance adds 
configuration surface for no real benefit — if a deployment opts into a 
compliance mode, it should apply end-to-end.

In {{{}JettyService{}}}, within the existing {{if (uriComplianceMode != null)}} 
block, add:

 config.setRedirectUriCompliance(compliance);
 
alongside the current {{{}config.setUriCompliance(compliance){}}}.

Because this stays inside the {{!= null}} guard, behavior is unchanged when the 
property is unset: Jetty keeps its own defaults (request {{{}DEFAULT{}}}, 
redirect {{{}DEFAULT_REDIRECT{}}}). When the property is set to {{LEGACY}} (the 
common case for allowing {{{}%2F{}}}), both request and redirect URIs are 
relaxed consistently — and {{LEGACY}} is a strict superset of 
{{DEFAULT_REDIRECT}} (it also allows {{{}FRAGMENT{}}}), so nothing is lost.

_Minor note:_ for a deployment that explicitly sets the mode to 
{{{}DEFAULT{}}}, redirect URIs would become marginally stricter than Jetty's 
out-of-box {{DEFAULT_REDIRECT}} (a URI fragment in {{Location}} would no longer 
be tolerated). This is an acceptable and arguably expected consequence of 
applying a single explicit compliance mode uniformly.

*References*
 * 
[jetty/jetty.project#14264|https://github.com/jetty/jetty.project/issues/14264] 
— introduced {{{}UriCompliance.DEFAULT_REDIRECT{}}}, first released in Jetty 
12.1.6 (2026-01-27).

  was:
Since Jetty 12.1, {{HttpConfiguration}} applies URI compliance checks to the 
{{Location}} header of HTTP redirects via 
{{{}setRedirectUriCompliance(UriCompliance){}}}, separately from the 
request-URI check ({{{}setUriCompliance{}}}):
 * Jetty 12.0.x: redirect default {{null}} → no check on redirect URIs (Jetty 
9.x-like).
 * Jetty 12.1.0–12.1.5: redirect default {{UriCompliance.DEFAULT}} → ambiguous 
URIs (e.g. encoded {{%2F}} / {{{}AMBIGUOUS_PATH_SEPARATOR{}}}) in the 
{{Location}} header are rejected.
 * Jetty 12.1.6+ 
([jetty/jetty.project#14264|https://github.com/jetty/jetty.project/issues/14264]):
 redirect default {{UriCompliance.DEFAULT_REDIRECT}} (= {{{}DEFAULT{}}}, 
additionally tolerating a URI fragment). Still rejects {{{}%2F{}}}.

*Problem*

Felix maps the {{org.eclipse.jetty.UriComplianceMode}} property to 
{{HttpConfiguration.setUriCompliance(...)}} only (see 
{{{}JettyService.getHttpConfiguration{}}}). It never calls 
{{{}setRedirectUriCompliance(...){}}}.

As a result, an application that sets 
{{org.eclipse.jetty.UriComplianceMode=LEGACY}} to preserve Jetty 9.x handling 
of ambiguous encodings (e.g. {{{}%2F{}}}) gets that behavior for incoming 
*request* URIs, but any redirect whose {{Location}} still contains {{%2F}} is 
rejected by Jetty's default {{{}DEFAULT_REDIRECT{}}}. There is no way to relax 
redirect compliance from Felix configuration, so the request-side relaxation is 
effectively undone on redirects.

*Proposal*

Reuse the existing {{org.eclipse.jetty.UriComplianceMode}} property to drive 
*both* setters. Differentiating request vs. redirect compliance adds 
configuration surface for no real benefit — if a deployment opts into a 
compliance mode, it should apply end-to-end.

In {{{}JettyService{}}}, within the existing {{if (uriComplianceMode != null)}} 
block, add:


 
config.setRedirectUriCompliance(compliance);
 
alongside the current {{{}config.setUriCompliance(compliance){}}}.

Because this stays inside the {{!= null}} guard, behavior is unchanged when the 
property is unset: Jetty keeps its own defaults (request {{{}DEFAULT{}}}, 
redirect {{{}DEFAULT_REDIRECT{}}}). When the property is set to {{LEGACY}} (the 
common case for allowing {{{}%2F{}}}), both request and redirect URIs are 
relaxed consistently — and {{LEGACY}} is a strict superset of 
{{DEFAULT_REDIRECT}} (it also allows {{{}FRAGMENT{}}}), so nothing is lost.

_Minor note:_ for a deployment that explicitly sets the mode to 
{{{}DEFAULT{}}}, redirect URIs would become marginally stricter than Jetty's 
out-of-box {{DEFAULT_REDIRECT}} (a URI fragment in {{Location}} would no longer 
be tolerated). This is an acceptable and arguably expected consequence of 
applying a single explicit compliance mode uniformly.

*References*
 * 
[jetty/jetty.project#14264|https://github.com/jetty/jetty.project/issues/14264] 
— introduced {{{}UriCompliance.DEFAULT_REDIRECT{}}}, first released in Jetty 
12.1.6 (2026-01-27).


> Jetty 12.1.x uses `DEFAULT_REDIRECT` instead of null, not honoring the 
> `UriComplianceMode` setting in Felix
> -----------------------------------------------------------------------------------------------------------
>
>                 Key: FELIX-6849
>                 URL: https://issues.apache.org/jira/browse/FELIX-6849
>             Project: Felix
>          Issue Type: Bug
>          Components: HTTP Service
>            Reporter: Paul Rütter
>            Assignee: Paul Rütter
>            Priority: Major
>
> Since Jetty 12.1, {{HttpConfiguration}} applies URI compliance checks to the 
> {{Location}} header of HTTP redirects via 
> {{{}setRedirectUriCompliance(UriCompliance){}}}, separately from the 
> request-URI check ({{{}setUriCompliance{}}}):
>  * Jetty 12.0.x: redirect default {{null}} → no check on redirect URIs (Jetty 
> 9.x-like).
>  * Jetty 12.1.0–12.1.5: redirect default {{UriCompliance.DEFAULT}} → 
> ambiguous URIs (e.g. encoded {{%2F}} / {{{}AMBIGUOUS_PATH_SEPARATOR{}}}) in 
> the {{Location}} header are rejected.
>  * Jetty 12.1.6+ 
> ([jetty/jetty.project#14264|https://github.com/jetty/jetty.project/issues/14264]):
>  redirect default {{UriCompliance.DEFAULT_REDIRECT}} (= {{{}DEFAULT{}}}, 
> additionally tolerating a URI fragment). Still rejects {{{}%2F{}}}.
> *Problem*
> Felix maps the {{org.eclipse.jetty.UriComplianceMode}} property to 
> {{HttpConfiguration.setUriCompliance(...)}} only (see 
> {{{}JettyService.getHttpConfiguration{}}}). It never calls 
> {{{}setRedirectUriCompliance(...){}}}.
> As a result, an application that sets 
> {{org.eclipse.jetty.UriComplianceMode=LEGACY}} to preserve Jetty 9.x handling 
> of ambiguous encodings (e.g. {{{}%2F{}}}) gets that behavior for incoming 
> *request* URIs, but any redirect whose {{Location}} still contains {{%2F}} is 
> rejected by Jetty's default {{{}DEFAULT_REDIRECT{}}}. There is no way to 
> relax redirect compliance from Felix configuration, so the request-side 
> relaxation is effectively undone on redirects.
> *Proposal*
> Reuse the existing {{org.eclipse.jetty.UriComplianceMode}} property to drive 
> *both* setters. Differentiating request vs. redirect compliance adds 
> configuration surface for no real benefit — if a deployment opts into a 
> compliance mode, it should apply end-to-end.
> In {{{}JettyService{}}}, within the existing {{if (uriComplianceMode != 
> null)}} block, add:
>  config.setRedirectUriCompliance(compliance);
>  
> alongside the current {{{}config.setUriCompliance(compliance){}}}.
> Because this stays inside the {{!= null}} guard, behavior is unchanged when 
> the property is unset: Jetty keeps its own defaults (request {{{}DEFAULT{}}}, 
> redirect {{{}DEFAULT_REDIRECT{}}}). When the property is set to {{LEGACY}} 
> (the common case for allowing {{{}%2F{}}}), both request and redirect URIs 
> are relaxed consistently — and {{LEGACY}} is a strict superset of 
> {{DEFAULT_REDIRECT}} (it also allows {{{}FRAGMENT{}}}), so nothing is lost.
> _Minor note:_ for a deployment that explicitly sets the mode to 
> {{{}DEFAULT{}}}, redirect URIs would become marginally stricter than Jetty's 
> out-of-box {{DEFAULT_REDIRECT}} (a URI fragment in {{Location}} would no 
> longer be tolerated). This is an acceptable and arguably expected consequence 
> of applying a single explicit compliance mode uniformly.
> *References*
>  * 
> [jetty/jetty.project#14264|https://github.com/jetty/jetty.project/issues/14264]
>  — introduced {{{}UriCompliance.DEFAULT_REDIRECT{}}}, first released in Jetty 
> 12.1.6 (2026-01-27).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to