Replace the jackrabbit-webdav dependency with the WebDAV requests actually used - #898
Conversation
MultiStatus was forked here so that responses would keep their document order, which getFileList depends on. Jackrabbit's own MultiStatus has since been changed to a LinkedHashMap, so the fork no longer differs from the class it shadows. Shadowing is the problem: the released jar carried org/apache/jackrabbit/webdav/MultiStatus.class, which also exists in jackrabbit-webdav, so which of the two won depended on classpath order. XmlRequestEntity is left over from Jackrabbit 2.14, which no longer ships or references it, and nothing in this module ever used it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This Wagon speaks a very small subset of WebDAV: MKCOL to create a collection, PROPFIND Depth:0 on resourcetype to tell a collection from a plain resource, and PROPFIND Depth:1 to list a collection. The Depth:1 request nominally asks for displayname but never reads it, deriving every entry from the response href instead. jackrabbit-webdav models all of WebDAV -- locking, observation, ordering, versioning, search, transactions -- so those three requests were pulling in a dependency whose scope far exceeds what is needed. The requests and the multistatus parsing now live in this module, in Wagon's own package rather than squatting Jackrabbit's. The parser keeps the behaviour the callers rely on: responses stay in document order, because getFileList expects the requested collection first per RFC 4918 section 9.1, and hrefs are deduplicated the way Jackrabbit's href-keyed map did. Only propstat elements reporting 200 are consulted for resourcetype. Since a multistatus body is remote input, the parser also refuses DOCTYPE declarations. Behaviour changes in two spots, both in the safe direction: a PROPFIND answering something other than 207 Multi-Status is no longer parsed for a body, and an empty multistatus no longer raises ArrayIndexOutOfBoundsException from isDirectory. The artifactId keeps the jackrabbit name so that consumers do not break. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Do not let parser hardening break the transport. disallow-doctype-decl is a Xerces feature and setFeature rejects features a parser does not know, so a JAXP implementation other than the platform one would have made every PROPFIND fail. It is now applied only if supported, falling back to refusing external entities, and a configuration failure is reported as such instead of being blamed on the response body. Install an ErrorHandler on the DocumentBuilder. Without one the parser writes its own diagnostics to stderr before throwing, so a server answering 207 with a broken body would have littered the build output. Fatal errors still surface as an exception. Keep a 207 carrying no body a transport failure. It was being read as "not a collection", which surfaced as ResourceDoesNotExistException and told the resolver the artifact was simply absent. Also correct the comment about repeated hrefs, which described dropping later duplicates when the last one in fact wins, and record why a propstat without a status is read as successful. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Pushed a third commit addressing review feedback. Four fixes, all in the new code: The parser could hard-break the transport. No A 207 with no body was downgraded to a missing resource. It was read as "not a collection", which surfaced as Comment corrected on repeated hrefs. It claimed later duplicates were dropped; Two deliberate semantic differences from the Jackrabbit version, now recorded in javadoc and covered by tests:
293 tests pass. |
The multistatus javadoc cited RFC 4918 section 9.1 as mandating that a server list the request URI first. It mandates no ordering at all. The assumption is an observed server behaviour and predates this class, which the comment it replaced described accurately; getFileList still skips the first entry as before, but the reason is now stated honestly. HttpStatus.SC_MULTI_STATUS does exist in HttpCore, so the local constant claiming otherwise is gone. Also drop the local-name fallback in isDavElement, which a namespace aware parser can never reach, and send the PROPFIND body as application/xml to match what Jackrabbit put on the wire. Tolerating an absent namespace is kept and now noted as a deliberate relaxation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
A second review pass turned up two things the new code asserted about itself that were simply untrue. Both corrected in the latest commit. The javadoc invented an RFC guarantee. It said Worth recording for whoever touches this next: against a server that does not list the request URI first, the parent collection stays in the listing and the first child collection is dropped. That is pre-existing behaviour, not something introduced here. The robust fix is to match hrefs against the request path instead of relying on position — out of scope for this PR.
Also in this commit: dropped the local-name fallback in Deliberate relaxations versus the Jackrabbit behaviourBoth are documented in javadoc and covered by tests, and both make this Wagon work against servers it previously failed on:
Three incidental robustness gains over the code being replaced, all from the old 293 tests pass, 0 checkstyle violations. |
Where disallow-doctype-decl is unavailable the parser falls back to refusing external entities, but those two calls were allowed to fail as quietly as the first. A parser supporting none of the three would then have read remote input with only secure processing in force, which bounds resource use and says nothing about what the document may reach. The fallback now insists on both entity features and reports a parser it cannot secure as a configuration error. Also deny the external DTD subset, which the entity features do not govern, tolerating parsers that do not recognise the property. The branch only runs on a JAXP implementation other than the platform one, so it cannot be reached from a test; it was exercised by configuring a factory the same way by hand, where a DOCTYPE parses, as it did under Jackrabbit, and an external entity yields empty text. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
One more commit, closing a hole in the XXE fallback added earlier. Where It also denies the external DTD subset via That branch only executes on a JAXP implementation other than the platform one, so it cannot be reached from a unit test. It was verified by configuring a factory the same way by hand: a DOCTYPE parses — as it did under Jackrabbit, which neutered entities with an 293 tests pass, 0 checkstyle violations. |
There was a problem hiding this comment.
Pull request overview
Replaces the broad Jackrabbit WebDAV dependency with focused request and response handling.
Changes:
- Adds MKCOL/PROPFIND request implementations and multistatus parsing.
- Updates
WebDavWagonto use the new implementation. - Removes Jackrabbit classes, dependency, and documentation references.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
DavMethods.java |
Implements WebDAV requests. |
MultiStatus.java |
Parses PROPFIND multistatus responses. |
WebDavWagon.java |
Uses the replacement implementation. |
MultiStatusTest.java |
Tests multistatus parsing. |
org/apache/jackrabbit/webdav/MultiStatus.java |
Removes vendored Jackrabbit class. |
XmlRequestEntity.java |
Removes unused legacy class. |
wagon-webdav-jackrabbit/pom.xml |
Removes Jackrabbit dependency. |
pom.xml |
Updates Javadoc package grouping. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
A DAV:response carrying no href was being skipped. That moves the next response into its place, and both callers read meaning into position: isDirectory inspects the first entry, and getFileList takes the first entry to be the collection it asked about. A server omitting an href could therefore have had a child directory silently dropped from a listing and another one classified from the wrong resource. Such a response is now a parse error, as it was before. Stop reading a propstat that carries no status as successful, too. RFC 4918 requires the element, so a propstat without one reports success for nothing, and treating it as 200 contradicted the rule stated on Response.isCollection that only propstats reporting 200 are consulted. It also went beyond porting the behaviour, on the strength of a lenient server nobody has actually met. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
wagon-webdav-jackrabbitspeaks a very small subset of WebDAV. Its entire use ofjackrabbit-webdavis three requests:Depth: 0onresourcetype— is this a collection? (isDirectory)Depth: 1— list a collection. (getFileList)The third is thinner than it looks: it nominally asks for
displaynamebut never reads it, deriving every entry from the responsehref.jackrabbit-webdavmodels all of WebDAV — locking, observation, ordering, versioning, search, transactions. Three requests were pulling in a dependency whose scope far exceeds what is needed. This moves the requests and the multistatus parsing into the module, in Wagon's own package rather than squatting Jackrabbit's.Commits
org/apache/jackrabbit/webdav/MultiStatus.class, which also exists injackrabbit-webdav— so which of the two won depended on classpath order. It was forked only to keep responses in document order, and Jackrabbit's ownMultiStatushas since become aLinkedHashMap, so the fork no longer differs from the class it shadows.XmlRequestEntityis left over from Jackrabbit 2.14, which no longer ships or references it, and nothing in this module used it. This commit stands alone — the full suite passes with the dependency still in place.DavMethods(99 lines) andMultiStatus(207 lines).Fidelity
The parser preserves what the callers rely on:
getFileListexpects the requested collection first, per RFC 4918 §9.1.propstatelements reporting 200 are consulted forresourcetype.DAV:namespace, tolerating servers that use a default namespace or a different prefix.Two behaviour changes, both in the safe direction: a PROPFIND answering something other than
207 Multi-Statusis no longer parsed for a body, and an empty multistatus no longer raisesArrayIndexOutOfBoundsExceptionfromisDirectory. Since a multistatus body is remote input, the parser also refuses DOCTYPE declarations.Verification
MultiStatusTestcases.org.apache.maven.wagon.providers.webdav, and no longer places anything in theorg.apache.jackrabbitnamespace.Notes
The
artifactIdkeeps thejackrabbitname so consumers do not break, even though the dependency is gone.This also unblocks a future move to HttpClient 5.
jackrabbit-webdavis onhttpclient 4.5.14in every release including the latest 2.22.4 and 2.23.x-beta, so it pinned this module to HttpClient 4 regardless of version. What remains here is two base classes (HttpRequestBase/HttpEntityEnclosingRequestBase), which becomeHttpUriRequestBasein HttpClient 5.mvn verifyto make sure basic checks pass.