HADOOP-19972. Upgrade to Jetty 12 without changing the servlet namespace - #8704
Open
joseluisll wants to merge 23 commits into
Open
HADOOP-19972. Upgrade to Jetty 12 without changing the servlet namespace#8704joseluisll wants to merge 23 commits into
joseluisll wants to merge 23 commits into
Conversation
… module classpath
Several modules resolved more than one Jetty release, and more than one servlet
API, on a single classpath. Both combinations compile and then fail at run time,
on whichever code path reaches the wrong jar.
* Four modules used org.eclipse.jetty from their main sources while no pom in
their inheritance chain declared Jetty: hadoop-mapreduce-client-app,
hadoop-mapreduce-client-shuffle, hadoop-yarn-server-router and
hadoop-yarn-server-applicationhistoryservice. Each now declares the artifact
its main sources use, without a version, and jetty-http gains the
dependencyManagement entry it was missing. The Router declares jetty-webapp at
compile scope, since a test scope would override the compile-scoped copy it
inherits and take it off the Router's own runtime classpath.
* jersey-test-framework-provider-jetty carried jetty-continuation onto the test
classpath of around twenty modules at its own, older release. It is managed at
${jetty.version} rather than excluded, because Jersey needs the class:
Continuation is a final field on JettyHttpContainer's ResponseWriter,
initialised in the constructor.
* solr-core carried nine Jetty artifacts, and a servlet API, into
hadoop-yarn-applications-catalog-webapp's tests at a much older release. Those
tests reach Solr only through EmbeddedSolrServer, which runs no servlet
container, so none of it is needed. The exclusions are applied to
solr-test-framework as well, whose own path to solr-core would otherwise
reintroduce the same jars.
* hadoop-project excluded javax.servlet-api from jetty-server under the group
org.eclipse.jetty, which jetty-server has never used, so the exclusion matched
nothing and javax.servlet:javax.servlet-api stayed on the classpath beside the
managed jakarta.servlet:jakarta.servlet-api. Both publish the javax.servlet
packages, so which one a module compiled and ran against was decided by the
order of the jars, and 73 modules carried both. An exclusion naming the real
coordinates is added beside the existing one, and the same on
javax-websocket-server-impl, which reaches the API again through
websocket-servlet. hadoop-common now declares jakarta.servlet-api itself.
* hadoop-common declared jakarta.servlet.jsp-api, which reached some
eighty-five classpaths. Nothing in the tree uses JSP, so it and its managed
version are removed, together with the LICENSE-binary and NOTICE-binary
entries for the two artifacts that no longer ship.
One module keeps two servlet APIs, hadoop-yarn-server-timelineservice-hbase-tests,
where the second arrives with HBase's own test stack.
Co-Authored-By: Claude <noreply@anthropic.com>
jersey-test-framework-provider-jetty put jetty-continuation on the test classpath of around twenty modules at its own, older Jetty release. Managing that artifact pins the version but leaves Jersey's Jetty 9 container there. Switch to jersey-test-framework-provider-grizzly2 instead. It is the same Jersey release, it speaks real HTTP, and it puts no Jetty on a test classpath at all, so the jetty-continuation entry and its shade exclusion go with it. It brings no second servlet API: grizzly-http-servlet declares javax.servlet-api at provided scope, which is not transitive, and jersey-container-grizzly2-servlet declares the jakarta.servlet-api coordinate this tree already manages. LICENSE-binary gains the four Grizzly artifacts and the two jersey-container-grizzly2 ones, which reach hadoop-client-minicluster at compile scope. Co-Authored-By: Claude <noreply@anthropic.com>
…in javadoc. The import is unused: only a javadoc @link mentions the type. Spell that link out instead, and the class no longer references the servlet API at all. Co-Authored-By: Claude <noreply@anthropic.com>
…a PEM. CertificateUtil parses a PEM and has nothing to do with servlets. It used ServletException only to wrap the CertificateException it already catches. The new toRSAPublicKey reports that exception directly and names no servlet type. parseRSAPublicKey stays, deprecated, delegating to it and wrapping the exception back, so callers outside this tree keep compiling and keep seeing the same exception and message. It goes with the move to jakarta, where its signature has to change anyway. Co-Authored-By: Claude <noreply@anthropic.com>
…ider. SignerSecretProvider.init takes a ServletContext, so every implementation names a servlet type whether or not it uses one. Only ZKSignerSecretProvider really needs it, and what it needs is an attribute store, not a servlet: it shares a CuratorFramework as a context attribute. SecretProviderContext is that store, and initialize(Properties, SecretProviderContext, long) is the method providers should now override. The four providers here do, and none of them names a servlet type any more. Nothing breaks. init stays, deprecated, and stays the entry point callers use. It is now concrete: it adapts the ServletContext and calls initialize, so a provider overriding only initialize is initialized through it, while a provider overriding init is called directly, as before. Implementations live outside this tree - signer.secret.provider takes a classname - and keep compiling, linking and running untouched. The bridge dispatches virtually, so a provider extending RolloverSignerSecretProvider, overriding init and chaining to super still gets its rollover scheduler started. TestSignerSecretProviderCompatibility pins that and the rest of the contract. The adapter writes through to the real ServletContext, so the curator client is still a ServletContext attribute under the same name, as Configuration.md documents and as DelegationTokenAuthenticationFilter expects. A null ServletContext, which used to throw, now yields a store private to the provider. AuthenticationFilter and its tests are unchanged, which is the point. Co-Authored-By: Claude <noreply@anthropic.com>
It used org.eclipse.jetty.util.UrlEncoded to percent-encode a user name. java.net.URLEncoder does the same job from the JDK, so the class no longer needs Jetty. Co-Authored-By: Claude <noreply@anthropic.com>
ShuffleChannelHandler is a Netty handler. It imported org.eclipse.jetty.http.HttpHeader only to name the Connection and Keep-Alive headers. That was the module's last Jetty reference, so the jetty-http declaration HADOOP-19970 added to its pom goes too. The names are spelled as constants rather than taken from Netty's HttpHeaderNames and HttpHeaderValues, whose constants are lowercase AsciiStrings: using those would have sent "connection: keep-alive" where this handler has always sent "Connection: Keep-Alive". The shuffle response is read by other projects, so no byte of it changes here. Co-Authored-By: Claude <noreply@anthropic.com>
…ax.servlet. Jetty 9.4 is end of life and 12 is the supported line. Jetty 12 ships the servlet container as a pluggable EE environment; ee8 is the one that serves javax.servlet, so the tree moves to 12 without touching the namespace, Jersey 2, or any public signature. Dependency management moves to 12.0.37. The core artifacts keep their coordinates; the servlet container moves under org.eclipse.jetty.ee8, and the HTTP/2 artifacts the catalog webapp pins gain the jetty- prefix Jetty 12 gave them. jetty-servlet-tester goes: it does not exist on the 12.x line and no module declared it. The servlet API becomes org.eclipse.jetty.toolchain:jetty-servlet-api. It publishes the same javax.servlet packages as the jakarta.servlet-api it replaces, so the namespace and HADOOP-19970's one-API-per-classpath rule both hold, but it is the only one of the two that also carries the web.xml schemas, which ee8 resolves from whichever archive javax.servlet.Servlet came from. Grizzly's own jakarta.servlet-api is excluded for the same reason. HttpServer2, HttpServer2Metrics, the YARN WebApps builder, the WebSocket code and the remaining embedded servers are ported to the ee8 API. The shaded client artifacts and LICENSE-binary follow the new coordinates. Four things fall out of the move: * hadoop-client-minicluster excluded the servlet API from the Hadoop modules it pulls back in by naming jakarta.servlet:jakarta.servlet-api. Those exclusions stop matching, which puts the 85 javax.servlet classes in both shaded jars - caught by BanDuplicateClasses in hadoop-client-check-test-invariants. They name the new coordinate too. * Jetty 12's DefaultServlet defaults dirAllowed to true, where 9.4's init parameter had it off for this context. It is set explicitly, and asserted, so no directory listing is served from /static. * Jetty 9.4's WebSocketServlet bootstrapped itself from init(). Jetty 12's JettyWebSocketServlet expects the WebSocket components on the context already and throws otherwise, so the node manager's container shell endpoint answered 500 on upgrade. What installs them is a ServletContainerInitializer, discovered only by AnnotationConfiguration, which lives in jetty-ee8-annotations - excluded here because it drags in an asm the enforcer bans. Calling the initializer directly does the same work without the scan, and has to happen while the context is still stopped, so the WebApps builder gains a window between build and start. TestNMContainerWebSocket caught none of this because it wrapped the exchange in catch (Throwable) and logged; it now asserts the upgrade produced a session. * hadoop-common's exclusion of javax.servlet-api from jetty-util matches no edge, because Jetty 12's jetty-util depends on nothing but slf4j, and the Router pom's comment described jetty-servlet and jakarta.servlet-api, neither of which this tree has any more. Co-Authored-By: Claude <noreply@anthropic.com>
…that embed it. HBase, Hive, Spark, Ozone and Knox compile against hadoop-auth's filters and HttpServer2. Moving to Jetty 12 must not change what they see: the servlet types on that surface stay javax.servlet, and nothing on it may name a jakarta.servlet type. A test asserts it rather than leaving it to review. It fails the day the jakarta rename reaches this surface, which is the point - that day belongs to a major release, not to this change. Co-Authored-By: Claude <noreply@anthropic.com>
Jetty 9.4's ServerConnector.close() released the accept channel, so a listener could re-bind. Jetty 12's does not, and a connector that has been closed cannot be started again. Hand it a fresh channel instead. Found by pjfanning on PR apache#8653. Co-Authored-By: Claude <noreply@anthropic.com>
|
💔 -1 overall
This message was automatically generated. |
WebHDFS answers a bad path with its own JSON RemoteException, and its
clients parse that body. On Jetty 12 they were getting a bare 400 with no
body at all, because the connector rejects the URI before any servlet
runs: //tmp//file trips UriCompliance.Violation.AMBIGUOUS_EMPTY_SEGMENT,
which DEFAULT does not allow and Jetty 9.4 did.
Reproduced against 12.0.37 with a servlet that answers 400 with a JSON
body, driven over a raw socket so the path is sent as written:
PUT /webhdfs/v1/tmp/file -> 400 len=-1 application/json {"RemoteException"...
PUT /webhdfs/v1//tmp//file -> 400 len=0 ctype=null (empty)
The second never reached the servlet, which is why
WebHdfsFileSystem.jsonParse returns null - it returns null exactly when
Content-Length is 0 - and TestRouterWebHdfsMethods then dies on a
NullPointerException rather than reading the exception it asked for.
Only that one violation is allowed back. The ambiguities that let a
request read as one path to a filter and another to a servlet stay
rejected, and the same probe confirms it: with the violation allowed,
tmp%2Ffile is still refused and a/../../etc still never reaches the
servlet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018SkhAkvYzV8Qwb3NtGZPbW
Reporting the renew failure through HttpExceptionUtils rather than
throwing it changed what the caller receives, and these four cases were
still asserting the old shape.
The client gets the server's own exception back now - an
AccessControlException carrying "bar tries to renew a token ... with
non-matching renewer foo" - because the JSON error envelope reaches it
and HttpExceptionUtils.validateResponse rebuilds the named type. Before,
the body was not parseable, so validateResponse fell back to a generic
IOException quoting the status line, and assertTrue(msg.contains("403"))
was pinning that fallback. The detail the caller actually wanted was
being discarded, and the assertion passed anyway.
Asserting the type and the reason is the stronger check: the status code
only ever appeared in the message that meant the round trip had failed.
Verified against trunk, where these four pass on Jetty 9.4, so the
old assertions were not wrong then - they were describing a worse
response.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018SkhAkvYzV8Qwb3NtGZPbW
A file whose name contains a '%' is written on the wire as %25, and that trips UriCompliance.Violation.AMBIGUOUS_PATH_ENCODING, which DEFAULT does not allow. Names like that are ordinary in HDFS, and YARN routes carry them: TestWebApp#testEncodedUrl asks for "@;%$", which encodes to %40%3B%25%24 and came back 400 with no body. Isolated by adding one violation at a time to DEFAULT and re-running the same two requests. The encoded semicolon is not the problem - it is the encoded percent: + AMBIGUOUS_PATH_PARAMETER @;%$ -> 400 %2F -> 400 + AMBIGUOUS_PATH_SEGMENT @;%$ -> 400 %2F -> 400 + AMBIGUOUS_PATH_ENCODING @;%$ -> ok %2F -> 400 + SUSPICIOUS_PATH_CHARACTERS @;%$ -> 400 %2F -> 400 Allowing it does not widen anything else. With both violations set, a%2Fb and a%2E%2E%2Fb are still refused, .. still cannot climb out of the context, and a%252Fb still decodes once, to the literal a%2Fb, rather than to a separator. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SkhAkvYzV8Qwb3NtGZPbW
TestWebHdfsUrl creates files whose names contain the characters HDFS
allows and a URL does not, and two of those tests came back 400 with no
body: "Unexpected HTTP response: code=400 != 307, op=CREATE, message=Bad
Request". The name is percent-encoded on the wire, so the connector was
refusing an escape sequence rather than a character.
Which one was measured rather than guessed. Sending each character of
that filename on its own, percent-encoded, against the setting this
branch already had, exactly one is refused:
specialFile ?"\()[]_-=&+;,{}#%'`~!@$^*|<>.
^
%5C
Jetty flags an encoded backslash as suspicious because it separates paths
on Windows. On HDFS it is a character in a name like any other, and 9.4
passed it through, so SUSPICIOUS_PATH_CHARACTERS joins the two violations
already allowed.
Re-checked with all three set: a%2Fb and a%2E%2E%2Fb are still refused,
.. still cannot climb out of the context, and a%252Fb still decodes once,
to the literal a%2Fb rather than to a separator.
TestWebHdfsUrl 11/11, TestHttpServer 34/34.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018SkhAkvYzV8Qwb3NtGZPbW
TestWebHdfsWithRestCsrfPreventionFilter passes 32/32 on trunk and fails six times here, all on the same assertion: the exception the client raises no longer contains "Missing Required Header". The filter refuses with sendError(400, message). That message used to reach the caller in the reason phrase. Jetty 12 does not send one, and what stands in its place is the container's HTML error page - which WebHdfsFileSystem.jsonParse refuses on its content type, so validateResponse falls back to quoting the status line and the caller is told only "Bad Request". Reported as the JSON envelope HttpExceptionUtils writes instead, which is how the rest of Hadoop's HTTP surface answers a refusal and what its clients already parse. Same move this branch made for the delegation token renewal path, for the same reason. Only the servlet side changes. HttpInteraction has four implementations; the two Netty ones serving the DataNode build their own responses and never went through a reason phrase, so they are left alone. TestRestCsrfPreventionFilter verified that sendError had been called, which pins the mechanism rather than the result - and would have gone on passing while the caller learned nothing. It now asserts the status and that the message is in what the caller can read. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SkhAkvYzV8Qwb3NtGZPbW
The previous commit stubbed getWriter() only on the two mock responses whose tests read the body back. Three others reach the same refusal path and assert nothing about the response, so they went unstubbed and the filter's write landed on a null writer: testMissingHeaderWithCustomHeaderConfigBadRequest IllegalArgument argument "w" is null testMissingHeaderNoMethodsToIgnoreConfigBadRequest IllegalArgument argument "w" is null testMissingHeaderMultipleIgnoreMethodsConfigBadRequest IllegalArgument argument "w" is null Mine, and pushed before the run that would have caught it had finished. All ten mock responses now come from one factory that always supplies a writer, so a test added later cannot land in the same hole by saying nothing about the body. TestWebHdfsWithRestCsrfPreventionFilter, which the previous commit was for, is 32/32. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SkhAkvYzV8Qwb3NtGZPbW
ImageServlet reported why it turned a transfer down through sendError, and the detail reached the caller in the HTTP reason phrase. Jetty 12 does not send a reason phrase, so the detail now lives only in the error page the container renders - and this servlet closes its output stream on the way out of every request, committing an empty response before that page is ever produced. The secondary namenode was left with a bare status code. The servlet now writes the reason into the body itself, which does not depend on how the container renders errors, and the three clients that read a failed transfer - Util#doGetUrl, TransferFsImage's upload, and EditLogFileInputStream - read the body before falling back to the phrase. TestCheckpoint's short-send case expects a different message now. Jetty 12 fails the servlet's own write as soon as it delivers fewer bytes than the Content-Length it announced, so the namenode reports the shortfall rather than putting a truncated body on the wire for the secondary to notice. The checkpoint still fails without corrupting the namenode, which is what the test guards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SkhAkvYzV8Qwb3NtGZPbW
Every server HttpServer2 builds runs QuotingInputFilter, which sets text/plain; charset=utf-8 before a request reaches its resource, so a JAX-RS resource that picks its own content type clears that first. Fourteen of them did it with setContentType(null). That is no longer enough. Jetty 12 drops the charset but remembers that one had been set explicitly, and appends the memory to the next content type - literally ";charset=null" for a type that carries no charset of its own. WebHDFS answered SETPERMISSION with "application/octet-stream;charset=null"; application/xml is affected the same way, while types that assume a charset, application/json among them, escape it. Clearing the character encoding as well resets that state. The idiom moves to JettyUtils#clearContentType so all fourteen call sites get it, and TestHttpServer asserts the header a resource that clears and re-sets its content type actually sends. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SkhAkvYzV8Qwb3NtGZPbW
… read. An audit of every sendError, two-argument setStatus and getResponseMessage call in the tree turned up two more clients that still read the detail from the HTTP reason phrase, which Jetty 12 no longer sends: WebHdfsFileSystem, on a 401, threw AccessControlException carrying only the phrase - now always "Unauthorized" rather than what the server said. AuthenticatedURL reported an authentication failure the same way, so an operator saw "message: Forbidden" instead of the reason. Both peers already put the reason in the body: AuthenticationFilter reports through sendError, which this branch changed it to. The body reader moves from Util to HttpExceptionUtils, next to the JSON envelope reader it complements, so hadoop-hdfs and hadoop-hdfs-client share one copy. hadoop-auth sits below hadoop-common and cannot reach it, so AuthenticatedURL keeps a small private one. Two findings from the same audit are deliberately left alone. NetworkTopologyServlet loses its reason the same way, but a probe against both containers shows Jetty 9.4 losing it identically - a failed topology dump answers 200 there too - so it is not this migration's regression and belongs in its own change. KMSClientProvider matches the phrase against two literals; the match is dead now, but its retry still works through the arm that does not read the phrase. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SkhAkvYzV8Qwb3NtGZPbW
NetworkTopologyServlet rendered the topology straight to the response stream. Closing that stream commits the response, so by the time the catch block ran the status line was already on the wire and sendError had nothing left to set: a dump that failed half way through went out as 200 OK with a truncated body, and one that failed before writing anything went out as 200 with no body. Rendering now happens into a buffer, and the response is not touched until the whole dump is in hand. The router's subclass had the same shape copied into it, so both now go through one sendTopology. This is not a Jetty 12 regression - a probe against Jetty 9.4.58 loses the failure identically - but it sits in the code this change is already working through, and a silent 200 on failure is worth closing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SkhAkvYzV8Qwb3NtGZPbW
…ainst. TestAppCatalogSolrClient failed with NoClassDefFoundError on org.eclipse.jetty.client.api.Request$BeginListener. That package is Jetty 9.4; Jetty 12 moved the class to org.eclipse.jetty.client. Solr 8.11.2 is compiled against Jetty 9.4, and it needs the client even here: EmbeddedSolrServer's own constructor loads HttpShardHandlerFactory, which reaches for that class. The premise this module was migrated on - that EmbeddedSolrServer runs no container so Solr's Jetty is dead weight - does not hold, and excluding Solr's Jetty left it calling a Jetty 12 that has no such API. The two lines cannot share a classpath: they share jetty-http, jetty-io and jetty-util. So this module follows Solr rather than Hadoop. A local dependencyManagement block overrides the inherited pin for the five artifacts hadoop-project manages, the http2 dependencies go back to their 9.4 coordinates at the same version, and the exclusions added on solr-core and solr-solrj are gone. Hadoop's own Jetty 12 still arrives here through hadoop-common's ee8 artifacts, which the war never uses. That is worth a look in review: excluding it from hadoop-common alone does not remove it, because three other Hadoop dependencies carry it too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SkhAkvYzV8Qwb3NtGZPbW
The previous commit put this module on the Jetty 9.4 that Solr calls, but Hadoop's Jetty 12 still arrived through its ee8 artifacts, leaving two Jetty lines in the war with Jetty 12's ee8 classes sitting on top of Jetty 9.4's jetty-http, jetty-io and jetty-util. Nothing here touches them - the module is packaged as a war and served by someone else's container, so it never starts an HttpServer2 - but that holds only for as long as nothing does. Excluded from all four Hadoop dependencies that carry them. One is not enough: hadoop-common, hadoop-yarn-common, hadoop-yarn-services-core and hadoop-yarn-services-api each bring their own copy, so excluding on any one of them changes nothing. The module now resolves a single Jetty release, which is what HADOOP-19970 set out to give every module - here it is Solr's release rather than Hadoop's. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SkhAkvYzV8Qwb3NtGZPbW
Brings the branch level with trunk so the patch is computed against current trunk. HADOOP-19951's vendored JSON.java, which RAT flagged as an ASF licence warning, carries Jetty's EPL header rather than an ASF one - replacing it would misattribute the copyright. It is not new work: the same commit is in trunk, and the file only read as added because the branch's merge base predated it landing.
|
💔 -1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description of PR
Stacked on #8699 (HADOOP-19970) and the HADOOP-19971 PR. The first seven commits belong to those — review the last three.
Hadoop's web server is Jetty 9.4, which is end of life and no longer receives security fixes. Getting off it is normally described as one large change, because Jetty 10 and everything after it require the
jakarta.servletnamespace. That framing makes a security fix wait on an API break: HBase, Hive, Spark, Ozone and Knox would all have to move on the same day.Jetty 12 makes the two separable. It ships the servlet container as a pluggable environment, and one of those environments, ee8, still serves
javax.servlet. This takes that route — a supported Jetty now, in an ordinary minor release, with nothing for downstream projects to do.Nothing downstream changes. No published method changes shape or disappears. The five
@InterfaceAudience.Publicclasses that expose servlet types in their signatures expose exactly the same ones as before — verified by comparing against trunk, not asserted. Projects that embed Hadoop's web stack need change nothing and need not rebuild. No configuration setting changes. Across the tree, 126 files namejavax.servletand none namesjakarta.servlet, unchanged from trunk.Jetty 12 does behave differently from 9.4 in a few places, and those are handled rather than passed on: a static file directory that would have started listing its contents, a web socket upgrade that would have failed, and a listener that could not be restarted once stopped.
Inside: Jetty moves from 9.4.58 to 12.0.37 on ee8. The servlet container artifacts move under
org.eclipse.jetty.ee8, and the servlet API arrives asorg.eclipse.jetty.toolchain:jetty-servlet-api, which publishes the samejavax.servletpackages as the one it replaces.HttpServer2and its metrics, the YARN web application builder, the web socket code and the remaining embedded servers — KMS, HttpFS, the scheduler simulator and the YARN services API — are ported. The shaded client artifacts andLICENSE-binaryfollow.Deliberately out of scope: no move to
jakarta.servlet, no Jersey upgrade, no ee9/ee10/ee11.ee8 is a staging post, not a destination. It preserves the namespace, but the Jetty API port still had to happen, and ee8 carries a compatibility layer that adapts every request. Unlike Jetty 10 and 11 it has a supported vendor behind it, which is what makes it a reasonable place to stand for a release or two.
This is not an alternative to HADOOP-19912 and does not replace it. That change still lands the namespace move, in a major release, judged on its own merits and with downstream projects warned. What this does is stop that decision from being a precondition for fixing the security problem.
How was this patch tested?
A new test states the contract this change promises: the servlet types Hadoop offers to the projects that embed it stay
javax, and none may becomejakarta. It fails the day that stops being true.hadoop-auth: 54 tests, 0 failures.
TestDownstreamServletCompatibility: 5 tests, 0 failures. hadoop-common builds clean.Still to do before this should merge: TLS configuration, SPNEGO, WebHDFS, the YARN UI, KMS and HttpFS need exercising against a running server rather than assumed. HADOOP-19876 was an SSL configuration regression on the current line and HADOOP-19848 a
NoSuchMethodErrorfrom a patch-level bump, so that is where the risk sits.For code changes:
declared according to the connector-specific documentation? Note: Automated CI
testing doesn't cover all cases so manual testing with cloud storage is still
required.
LICENSE,LICENSE-binary,NOTICE-binaryfiles?AI Tooling
Contains content generated by Claude.
where is the name of the AI tool used.
https://www.apache.org/legal/generative-tooling.html