Skip to content

Commit 99138d2

Browse files
joewizclaude
andcommitted
[bugfix] Preserve a literal "+" in resource names on decode
db:to-display decoded names with xmldb:decode-uri, which form-decodes "+" to a space (the x-www-form-urlencoded convention; eXist-db/exist#1824). But a "+" in a stored name is always a literal "+" -- spaces are stored as %20 -- and db:to-stored (fn:iri-to-uri) leaves "+" untouched on the encode side, so a name like "naïve+test.xml" stored correctly but read back as "naïve test.xml". Protect a literal "+" as %2B before xmldb:decode-uri so it decodes back to "+", restoring symmetry with the encode side. This mirrors what URIUtils.decodeForURI (the core fix in eXist-db/exist#6451) does, applied at the API layer so it is correct independent of the core build, and forward-compatible once #6451 lands. Spaces (%20) are unaffected. Verified end-to-end against a live instance: "naïve+test.xml" stores as na%C3%AFve+test.xml on disk, lists and reads back as naïve+test.xml. Adds the "+" case to the Cypress awkward-name coverage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 261bc73 commit 99138d2

2 files changed

Lines changed: 13 additions & 2 deletions

File tree

modules/db.xqm

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,16 @@ declare %private function db:to-display($path as xs:string?) as xs:string? {
5757
if (empty($path)) then $path
5858
else string-join(
5959
for $segment in tokenize($path, "/")
60-
return if ($segment eq "") then "" else xmldb:decode-uri(xs:anyURI($segment)),
60+
return
61+
if ($segment eq "") then ""
62+
(: xmldb:decode-uri form-decodes "+" to a space (the x-www-form-urlencoded
63+
: convention; eXist-db/exist#1824), but a "+" in a STORED name is always a
64+
: literal "+" -- spaces are stored as %20. Protect literal "+" as %2B so it
65+
: decodes back to "+", staying symmetric with db:to-stored / fn:iri-to-uri,
66+
: which leaves "+" untouched on the encode side. This mirrors what
67+
: URIUtils.decodeForURI (the core fix in eXist-db/exist#6451) does, applied
68+
: at the API layer so it is correct independent of the core build. :)
69+
else xmldb:decode-uri(xs:anyURI(replace($segment, "\+", "%2B"))),
6170
"/"
6271
)
6372
};

src/test/cypress/e2e/db.cy.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,9 @@ describe('/api/db', () => {
817817
// "café déjà.xml", never "caf%C3%A9...". eXist stores names percent-encoded,
818818
// so db.xqm encodes on input and decodes on output. The other db tests use
819819
// ASCII names and so don't exercise this boundary.
820-
const NAMES = ['café déjà.xml', "o'brien.xml"]; // non-ASCII + space; sub-delim apostrophe (xmldb:store leaves it literal)
820+
// non-ASCII + space; sub-delim apostrophe (xmldb:store leaves it literal); literal "+"
821+
// (must survive: stored as a literal "+", decoded back to "+", NOT form-decoded to a space)
822+
const NAMES = ['café déjà.xml', "o'brien.xml", 'naïve+test.xml'];
821823

822824
before(() => {
823825
cy.request({

0 commit comments

Comments
 (0)