Repository navigation
Keep XML references from truncating WebDAV file paths - #765
Conversation
Signed-off-by: dada-yan <BinjunYann@gmail.com>
WaylandYang
left a comment
There was a problem hiding this comment.
The bug is real and the tests are good. With the three hunks reverted and your tests kept:
---- webdav::tests::xml_text_fragments_keep_the_complete_href_and_properties stdout ----
assertion `left == right` failed: /docs/A&B.txt
left: "B.txt"
right: "/docs/A&B.txt"
---- webdav::tests::an_xml_escaped_filename_is_fetched_from_its_full_path stdout ----
assertion `left == right` failed: the escaped href must not be silently skipped
left: 0
right: 1
The second one is the right test to have written: it shows the consequence, which is that the file leaves the sync entirely.
I would not merge this yet, because it drops files through a different door
Flushing on every End whose name matches the open field writes an empty string over a good value when a property is spelled twice. Nextcloud, ownCloud and SabreDAV routinely answer with two propstat blocks, a 200 carrying values and a 404 listing the properties they could not find. I ran the same document against both branches:
PROBE 成对写法 len=0 ← this branch
PROBE 自闭合写法 len=5 ← this branch, <getcontentlength/>
PROBE dev 成对写法 len=5 ← origin/dev
with
<propstat><prop><getcontentlength>5</getcontentlength></prop>
<status>HTTP/1.1 200 OK</status></propstat>
<propstat><prop><getcontentlength></getcontentlength></prop>
<status>HTTP/1.1 404 Not Found</status></propstat>fetch does if e.len == 0 || e.len > MAX_FILE_BYTES { continue; }, so a clobbered length silently drops the file. That is the symptom this pull request exists to prevent, arriving through the other spelling. The self-closing form is safe, because quick-xml gives it as Event::Empty and the field is never opened, so whether a server is hit depends on its serializer.
The fix looks like one line: flush only when the accumulated text is not empty, or track whether a text event was seen for this field. Either keeps your accumulation and stops an empty re-declaration from overwriting.
Two more, smaller
unescape(...)?propagates, so one unrecognized entity anywhere aborts the whole listing:PROBE unknown-entity ERR: at 1..5: unrecognized entity 'nbsp', wheredevreturns the other entries and mangles only that one. Failing loudly may be right, but it is a blast-radius change past the title and no test covers it. Worth a decision either way.fieldis only assigned in theother =>arm, soresponseandcollectionStart events leave the previous field and its buffer open. I could not build a failure from it, but the state is not a stack and reads as though it were.
Dropping trim_text(true) is a bigger change than the title suggests, and correctness now rests on the three .trim() calls at flush time. I found no behaviour difference, so this is a note.
Comments in this repo are Chinese; the new ones are English.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
|
I pushed the two fixes to your branch rather than asking you to do them, since I had the probe in front of me. Please read the commit and say if you disagree.
Your two original tests still pass, along with the other five in the module: 9 green. fmt and clippy clean. |
Problem
A WebDAV file named
A&B.txtcan be silently skipped during synchronization. A valid PROPFIND response represents its path as/docs/A&B.txt. quick-xml emits text, a reference, and more text separately, but the parser overwriteshrefon every text event and ignores references. The resulting path is onlyB.txt; the subsequent GET targets/B.txtand a 404 is treated as an unreadable file.Change
Accumulate text, character/entity references, and CDATA until the field closes, then interpret href, content length, and last-modified values. Percent decoding runs after the full href is assembled. Whitespace is trimmed at field boundaries rather than between XML fragments. Unknown properties remain ignored; no new dependency or API/schema change.
Reproduction and validation
Base:
816d4a39255b68849d9eecaf273ec32b3f7d793d(dev).&, decimal/hex character references, CDATA, and mixed text/CDATA. On baseline the href isB.txtinstead of/docs/A&B.txt.fetchagainst a local HTTP fixture: the original implementation returns zero files; the fixed implementation downloads the expected file and retains its filename, bytes, and external key.cargo +1.98.1 test -p utopia-server --locked webdav::tests:: -- --skip it_reads_from_a_real_webdav_servercargo fmt --all --checkandcargo clippy --workspace --all-targets --locked -- -D warnings: passed.git diff --check: passed.The optional externally configured WebDAV server test was explicitly excluded; the local HTTP integration test did run. No existing deployment, credentials, or database were used. Full workspace runtime tests were not repeated for this patch.