yandrey321 opened a new pull request, #11424:
URL: https://github.com/apache/ozone/pull/11424

   ## What changes were proposed in this pull request?
   
   This upgrades Jetty from `12.0.38` to `12.1.14`, moving Ozone onto the Jetty 
12.1 line.
   
   Ozone stays on the EE8 environment: `servlet-api.version` remains `4.0.9` 
and no module migrates to
   EE10 or EE11. Jetty publishes EE8 artifacts for every `12.1.x` release, so 
there is no version floor to
   clear. The property `12.0.38` occurred exactly once in the repository, so 
the upgrade itself is a
   one-line change to the root `pom.xml`. The three remaining changes are 
fallout the upgrade produces,
   each described below.
   
   ### 1. Dist license files — Jetty 12.1 splits the `jetty-ee` module
   
   Jetty 12.1 splits `jetty-ee`, so the jar set under `share/ozone/lib` changes 
even though Ozone declares
   no new dependency:
   
   | 12.0.38 | 12.1.14 |
   |---|---|
   | `org.eclipse.jetty:jetty-ee` | `org.eclipse.jetty:jetty-annotations` |
   | | `org.eclipse.jetty.ee:jetty-ee-webapp` |
   
   `jetty-ee-webapp` carries a *new* groupId, `org.eclipse.jetty.ee`, which did 
not exist in `12.0.38`.
   Neither BOM that Ozone imports manages it — `jetty-ee8-bom` contains no 
`org.eclipse.jetty.ee` entry at
   all. It arrives transitively because `jetty-ee8-webapp` declares it without 
a version, so it follows
   `jetty.version` through the pinned `jetty-ee8-webapp` pom. It resolves to a 
single version, `12.1.14`,
   with no conflict.
   
   Two license files therefore need updating, which is what `dependency.sh` 
exists to force:
   
   - `hadoop-ozone/dist/src/main/license/jar-report.txt` — one entry becomes 
two.
   - `hadoop-ozone/dist/src/main/license/bin/LICENSE.txt` — `jetty-ee` becomes 
`jetty-annotations`, and
     `org.eclipse.jetty.ee:jetty-ee-webapp` is inserted between the 
`org.eclipse.jetty` and
     `org.eclipse.jetty.ee8` blocks, following that file's existing ordering by 
groupId *segment* rather
     than byte order.
   
   Both new artifacts are `Apache-2.0`/`EPL-2.0`, so `license.sh` stays clean 
and no new license category
   is introduced.
   
   A caution for anyone re-checking this: a `dependency:tree -Dincludes=...` 
filter built from the *old*
   coordinates is structurally blind to a groupId the upgrade introduces. 
Enumerating the jars the build
   actually ships (`find <dist> -name '*.jar'`) and diffing that is what 
surfaced it.
   
   ### 2. `UriCompliance.Violation.FRAGMENT` — the one behavior change that 
reaches Ozone
   
   The `UriCompliance` API delta is otherwise purely additive 
(`Violation.FRAGMENT` and
   `UriCompliance.DEFAULT_REDIRECT`), and `UriCompliance.DEFAULT.getAllowed()` 
is empty in both versions.
   The one measured behavior change is an improvement:
   
   | request target | 12.0.38 | 12.1.14 |
   |---|---|---|
   | `/bucket/my#key` | 200, key silently truncated to `my` | 400 |
   | `/bucket/my%23key` | 200, key `my#key` | 200, key `my#key` |
   | `/bucket//key` | unchanged | unchanged |
   
   Before `FRAGMENT` existed, Jetty split such a target and handed the servlet 
only the part before the
   `#`, so an S3 request for the key `my#key` silently operated on `my` 
instead. Rejecting the malformed
   target is the safer behavior, so Ozone's relaxed compliance modes 
deliberately do **not** allow
   `FRAGMENT`; relaxing it was tried and reproduces the truncation. 
`TestHttpServer2` gains a test pinning
   this, with a raw-socket helper because `java.net.URL` treats `#` as a 
client-side fragment and never
   puts it on the wire.
   
   Six other 12.1 default flips were checked and cannot affect Ozone: 
`maxResponseHeaderSize`,
   `relativeRedirectAllowed`, `renegotiationAllowed`, `flushOnResponseCommit`, 
`setCompactPath` and
   `ForwardedRequestCustomizer` have zero references repository-wide. Ozone's 
entire Jetty surface is
   `UriCompliance`, `SecureRequestCustomizer` and `ee8.nested.SessionHandler`. 
A query-string compliance
   concern was also checked and found not to exist — `%FF`, `%ZZ` and a 
truncated `a%2` are accepted by
   both versions.
   
   ### 3. `ProxyServer` — Jetty 12.1's proxy rewrites quoted response headers
   
   On the upgrade, `TestS3SDK` fails exactly one assertion:
   `StandardObjectHeaderTests.testObjectWriteContentLanguageAndDisposition` 
expects
   `attachment; filename="test.txt"` and receives 
`attachment;filename=test.txt`. An A/B on the single
   `jetty.version` property, same tree and same command, confirms causation — 
`12.0.38` gives 232/232,
   `12.1.14` gives 232 run with 1 failure.
   
   The S3 Gateway is not involved. The endpoint those tests talk to is not a 
gateway: `OzoneS3SDKTests`
   builds its cluster with `MultiS3GatewayService(5)`, which hides the five 
gateways behind the test-only
   `ProxyServer`, an `org.eclipse.jetty.ee8.proxy.ProxyServlet`. The gateway's 
own response is verbatim on
   `12.1.14`, measured at three layers — the value `ObjectEndpoint` reads back 
from key metadata and the
   value it writes out, the value Jersey hands `addHeader`, and the container's 
own `HttpFields` after the
   filter chain returns. A standalone `HttpServer2` plus servlet is verbatim 
too, on both GET and HEAD.
   Only the hop through the proxy rewrites the value:
   
   | Jetty | origin servlet | through the proxy |
   |---|---|---|
   | `12.0.38` | `attachment; filename="test.txt"` | `attachment; 
filename="test.txt"` |
   | `12.1.14` | `attachment; filename="test.txt"` | 
`attachment;filename=test.txt` |
   
   The mechanism is in `AbstractProxyServlet.onServerResponseHeaders`. 
`12.0.38` copies each header with
   `field.getValue()`. `12.1.14` adds a `filterServerResponseHeader(.., 
HttpField)` overload and forwards
   `field.getValueList()` joined with `","`. `HttpField.getValueList()` is a 
QuotedCSV parse, which drops
   optional whitespace and quoting while keeping `;param=value` — exactly the 
observed transformation. It
   is lossy for any non-CSV header carrying a quoted-string, so 
`Content-Disposition`,
   `WWW-Authenticate` and `Link` are all affected. This appears to be an 
upstream Jetty defect and is
   worth reporting there separately.
   
   The change here is scoped to the harness: `ProxyServer.ProxyHandler` 
overrides
   `onServerResponseHeaders` to copy with `field.getValue()`, restoring the 
`12.0.38` copy so the proxy
   stops rewriting values the S3 Gateway already returns correctly. This keeps 
the assertion meaningful
   rather than relaxing it.
   
   ### Scope
   
   Included: the version upgrade, the dist license fallout it causes, a test 
pinning the `FRAGMENT`
   behavior, and the harness fix needed to keep `TestS3SDK` honest.
   
   Out of scope, each its own Jira: migrating off EE8 to EE10 or EE11, and 
adopting any new 12.1 feature
   (`CompressionHandler`, the new deployer, `MultiAuthenticator`).
   
   Generated-by: Claude Code (claude-opus)
   
   ## What is the link to the Apache JIRA
   
   https://issues.apache.org/jira/browse/HDDS-16683
   
   ## How was this patch tested?
   
   CI:
   
   Existing suites plus one new unit test; no new test class or cluster 
lifecycle was introduced.
   
   - Full `mvn clean install` from a clean `~/.m2`.
   - `dependency:tree` across every `org.eclipse.jetty*` groupId, including the 
new
     `org.eclipse.jetty.ee`: all 29 Jetty artifacts resolve to `12.1.14`, 
`jetty-servlet-api` stays at
     `4.0.9`, and there are zero `ee9`/`ee10`/`ee11` artifacts. The only 
outliers are the pre-existing
     test-scope 
`org.eclipse.jetty.websocket:websocket-{api,client,common}:9.4.57.v20241219` 
pulled in by
     `hadoop-yarn-client`, which `jetty-bom` does not manage and which this 
change does not touch.
   - `dependency:tree -Dincludes=javax.servlet:*,jakarta.servlet:*` — unchanged.
   - Build run **without** `-Dmdep.analyze.skip`, so `analyze-only` executes at 
`verify`: 58 goals clean,
     no "Used undeclared dependencies".
   - Unit suites for `hdds-server-framework`, `s3gateway` and `httpfs`, 
including the new
     `TestHttpServer2.testUnencodedFragmentRejectedRatherThanTruncatingKey`.
   - `checkstyle.sh` and `rat.sh` — both clean.
   - `mvn -Pdist -DskipTests package`, then `dependency.sh` and `license.sh`: 
the jar-report diff
     `dependency.sh` reports is applied in this PR, and `license.sh` is clean.
   - `TestS3SDK` — **232 run, 0 failures, 0 errors**. Without the `ProxyServer` 
fix the same suite is
     232 run with 1 failure.
   - Compose smoketest, `ozone` suite — `rc=0`, zero failures.
   - The proxy regression was isolated with a throwaway probe that stands a 
plain origin servlet behind
     `ProxyServer` and reads both legs on a raw socket, run on `12.0.38` and 
`12.1.14`; the mechanism was
     then confirmed from `javap -c` of 
`AbstractProxyServlet.onServerResponseHeaders` in both versions.
     Neither probe is part of this patch.
   
   Not run locally, left to CI: the `ozonesecure` compose suite, which 
exercises the HTTPS
   `SecureRequestCustomizer` path, and the httpfs compose suite.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to