Repository navigation
Conversation
The Slide-based webdavclient4j client has failed with NoClassDefFoundError (org/jdom/input/DOMBuilder) on every PROPFIND since jdom 1 was replaced by jdom2 in 4.5.0, so WebDAV polling and writing did not work at all. Its listing was also broken before that: child paths were built as <dir>/<dir>/<name>, so size and last-modified came back as 0, directories were listed as files and listDirectories was empty. Talk WebDAV directly with httpclient 4: PROPFIND (Depth 0/1), MKCOL and MOVE request classes, a namespace-aware DOM parse of the multistatus with doctypes disallowed, and RFC 1123 dates via DateUtils. A listing is now built from a single Depth 1 PROPFIND. Failed responses are skipped, and the directory's own entry is still found behind a rewriting proxy. listDirectories returns paths that listFiles accepts, so recursive polling works. Basic, Digest and NTLM (DOMAIN\user) are negotiated through one shared context. Credentials are scoped to the configured host and port. The PUT body is buffered so it can be resent after an authentication challenge. MOVE keeps sending Overwrite: F, and failed PUT, DELETE and MOVE responses are still only logged, as before. The configured port and the connector timeout are now passed through. Before, the port was dropped and requests always went to 80/443. TLS hostname verification is now on. commons-httpclient 3 never checked the hostname, so servers whose certificate doesn't match the configured host now fail the handshake. The tests run against an embedded Jetty WebDAV servlet through FileSystemConnectionFactory. Signed-off-by: Nico Piel <nico.piel@hotmail.de>
WebDavConnection no longer uses it. Signed-off-by: Nico Piel <nico.piel@hotmail.de>
gibson9583
left a comment
There was a problem hiding this comment.
Every upload is now copied into additional full-file heap buffers before the PUT starts. FileDispatcher already holds the original payload, and BufferedHttpEntity copies it again through a growing byte buffer and then another complete byte array. The previous connector streamed the upload. Large binary messages or reattached attachments that previously fit in memory can now exhaust the shared engine heap, especially with concurrent sends. This happens even for anonymous or already-authenticated uploads. WebDavConnection.java:342.
|
Good catch, I'm also still testing this in the GUI |
BufferedHttpEntity copied every upload into extra full-size heap buffers before the PUT started, on top of the payload FileDispatcher already holds. Stream the body again and send Expect: 100-continue instead: an authentication challenge then arrives before any of the body is sent, so the PUT can still be retried after a 401. Signed-off-by: Nico Piel <nico.piel@hotmail.de>
Apache mod_dav answers a PROPFIND on a collection without its trailing slash with 301 to the slashed URL, and httpclient does not follow redirects for PROPFIND. Every directory check against Apache therefore failed, including the connection test. Signed-off-by: Nico Piel <nico.piel@hotmail.de>
|
Tested this in the Administrator against Apache mod_dav (
After that, polling (including subdirectories), filters, read, after-processing move, writer auto-MKCOL and PUT all worked end to end. Suggestion for a follow-up, deliberately not in this PR: failed PUT, DELETE and MOVE are still only logged, to keep parity with the old Slide-based connector. In practice that means:
I saw the first case during testing: with the move-to directory set to I'd make non-2xx responses to PUT, DELETE and MOVE throw, so the message errors or gets queued and the source file isn't reprocessed. The |
The CI container runs with a POSIX locale, where the JVM cannot create files with non-ASCII names, so pathEncoding failed with InvalidPathException before reaching the connector. The test server now stores names percent-encoded on disk and decodes them when listing. Signed-off-by: Nico Piel <nico.piel@hotmail.de>
|
@gibson9583 Good catch, thanks. Fixed in 0dd0a84: the PUT streams |
Test Results130 files ± 0 130 suites ±0 3m 3s ⏱️ -8s Results for commit 097e2e6. ± Comparison against base commit 4589238. This pull request removes 2 and adds 13 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
gibson9583
left a comment
There was a problem hiding this comment.
The extra upload buffering is fixed, but the replacement breaks authentication when reads are anonymous and writes require credentials behind nginx. With default request buffering, nginx sends 100 Continue and consumes the body before the upstream server returns 401. The InputStreamEntity has already been consumed, so HttpClient throws NonRepeatableRequestException instead of retrying with credentials. The first challenged upload fails; with Keep Connection Open disabled, this repeats on each attempt. Expect: 100-continue does not guarantee that the authentication challenge arrives before the body. WebDavConnection.java:341–344.
Expect: 100-continue does not guarantee that an authentication challenge arrives before the body. nginx with request buffering answers 100 Continue and reads the whole body before the upstream 401, so the streamed PUT could not be retried and failed with NonRepeatableRequestException. FileDispatcher passes a ByteArrayInputStream, so make that entity repeatable by resetting the stream before each send. It is still not copied. Other streams keep the Expect: 100-continue fallback. Signed-off-by: Nico Piel <nico.piel@hotmail.de>
|
@gibson9583 Right, 100-continue isn't a guarantee. Fixed in afaef4e: FileDispatcher hands the connector a 🤖 Addressed by Claude Code |
gibson9583
left a comment
There was a problem hiding this comment.
Both previously reported issues are resolved. Looks safe to merge.
mgaffigan
left a comment
There was a problem hiding this comment.
We should not be maintaining a WebDAV client. This needs to use some pre existing library.
If none exists, the functionality may need to be removed to a plugin.
Review asked not to maintain a WebDAV client in the engine. Sardine 5.10 now does the requests, multistatus parsing, PROPFIND redirects and authentication; WebDavConnection only maps its results onto the file connector. Sardine leaves lockdiscovery out of DavResource, so a small subclass issues the PROPFIND and keeps the raw responses. 5.10 is the last release on javax.xml.bind, which the engine already ships, so its httpclient and JAXB dependencies are left out. Also normalize listDirectories() paths, which came back as "//in" for the root. Signed-off-by: Nico Piel <nico.piel@hotmail.de>
|
@mgaffigan Agreed. 154b1f3 moves the connector onto Sardine 5.10 (Apache 2.0, built on httpclient 4.5). Sardine now handles the requests, the multistatus parsing, PROPFIND redirects and authentication.
🤖 Addressed by Claude Code |
|
Ok - that's not so bad, then. Can we drop the custom webdav server and extensions to sardine then? Presumably we do not need to check if we can write since it is inherently a TOCTOU. Ditto for the auth issue - is there a normal auth method implementation? |
Review asked to stop extending Sardine and to drop the embedded WebDAV server: - canWrite() no longer checks for write locks. Checking first is racy anyway, and a failed write is logged when it happens. - PUT uses Sardine's own streaming put with Expect: 100-continue, so an authentication challenge normally arrives before the body. Over TLS, Basic credentials are also sent preemptively, so the body never has to be resent after a Basic challenge. Plain HTTP keeps negotiating, so a Digest server never sees the password in cleartext. - The Jetty WebDAV test server is replaced by a unit test that mocks the Sardine interface, like the other file system tests. Signed-off-by: Nico Piel <nico.piel@hotmail.de>
|
@mgaffigan Done in 097e2e6:
🤖 Addressed by Claude Code |
What
Rewrites the File connector's
WebDavConnectionon Sardine 5.10, an Apache 2.0 WebDAV client built on httpclient 4.5. It also removes the vendoredwebdavclient4j-core-0.92.jar, a 2008 Jakarta Slide build on commons-httpclient 3.Why
webdavclient4j has been dead since 2008 and was the last real user of commons-httpclient 3.0.1. WebDAV has also been broken since 4.5.0: Slide needs jdom 1, which was replaced by jdom2.
Sardine 5.10 is the last release on
javax.xml.bind, which the engine already ships. 5.11 and later need Jakarta JAXB 4, and theirorg.glassfish.jaxb:jaxb-runtimewould clash with ours (2.4). Sardine is added withtransitive = false, so the only new jar issardine-5.10.jar, inextensions/file/lib.Reviewer notes
WebDavConnectionuses plain Sardine. Sardine handles the requests, multistatus parsing, PROPFIND redirects and authentication.WebDavConnectiononly maps its results ontoFileSystemConnection.Expect: 100-continue. Over HTTPS, Basic is also sent preemptively, as Slide did, so an upload never has to be resent.canWriteonly checks that the directory exists. It no longer checks for write locks: checking first is racy, and a failed write is logged when it happens.WebDavConnectionTestmocks theSardineinterface, like the SMB and FTP tests. List, read, write with MKCOL, move and delete were also checked by hand against Apache mod_dav.🤖 Generated with Claude Code