Repository: perry-mitchell/webdav-client
Pull request #384 (2024-08-27 17:20:49)

fix: Ensure that the `displayname` property is not parsed
If you have nodes with number-like names those values might be corrupted. While integer like names would be casted back to string, float-like names would be corrupted.
E.g. `2024.10` will be parsed to number `2024.1` thus loosing the trailing 0.

---

@perry-mitchell I think there might be even more places, especially with custom properties, where the parsing will lead to unexpected behavior. So maybe disable parsing in general and let users parse it?
Or at least expose the preprocessors, so users can decide which prop to parse.

But I think that would be a breaking change so not in 5.x. So this PR only fixes the displayname.


Patch:
diff --git a/source/tools/dav.ts b/source/tools/dav.ts
index 6291c50..77bf395 100644
--- a/source/tools/dav.ts
+++ b/source/tools/dav.ts
@@ -27,6 +27,13 @@ function getParser(): XMLParser {
         numberParseOptions: {
             hex: true,
             leadingZeros: false
+        },
+        tagValueProcessor(tagName, tagValue, jPath) {
+            if (jPath.endsWith("propstat.prop.displayname")) {
+                // Do not parse the display name, because this causes e.g. '2024.10' to result in number 2024.1
+                return;
+            }
+            return tagValue;
         }
         // We don't use the processors here as decoding is done manually
         // later on - decoding early would break some path checks.


Test patch:
diff --git a/test/node/tools/dav.spec.ts b/test/node/tools/dav.spec.ts
new file mode 100644
index 0000000..ef05ca9
--- /dev/null
+++ b/test/node/tools/dav.spec.ts
@@ -0,0 +1,15 @@
+import { expect } from "chai";
+import { readFile } from "fs/promises";
+import { parseXML } from "../../../source/index.js";
+
+describe("parseXML", function () {
+    it("keeps numeric-looking displaynames", async function () {
+        const data = await readFile(
+            new URL("../../responses/propfind-float-like-displayname.xml", import.meta.url)
+        );
+        const parsed = await parseXML(data.toString());
+        expect(parsed.multistatus.response).to.have.length(1);
+        // Ensure trailing zero is not lost
+        expect(parsed.multistatus.response[0].propstat.prop.displayname).to.equal("2024.10");
+    });
+});
diff --git a/test/responses/propfind-float-like-displayname.xml b/test/responses/propfind-float-like-displayname.xml
new file mode 100644
index 0000000..7dd51ad
--- /dev/null
+++ b/test/responses/propfind-float-like-displayname.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<d:multistatus
+	xmlns:d="DAV:">
+	<d:response>
+		<d:href>/remote.php/dav/files/admin/1/</d:href>
+		<d:propstat>
+			<d:prop>
+				<d:getetag>&quot;66a15a0171527&quot;</d:getetag>
+				<d:getlastmodified>Wed, 24 Jul 2024 19:46:09 GMT</d:getlastmodified>
+				<d:creationdate>1970-01-01T00:00:00+00:00</d:creationdate>
+				<d:displayname>2024.10</d:displayname>
+				<d:quota-available-bytes>-3</d:quota-available-bytes>
+				<d:resourcetype>
+					<d:collection/>
+				</d:resourcetype>
+			</d:prop>
+			<d:status>HTTP/1.1 200 OK</d:status>
+		</d:propstat>
+		<d:propstat>
+			<d:prop>
+				<d:getcontentlength/>
+				<d:getcontenttype/>
+			</d:prop>
+			<d:status>HTTP/1.1 404 Not Found</d:status>
+		</d:propstat>
+	</d:response>
+</d:multistatus>