Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- **Title:** WebDAV PROPFIND `<D:href>` is not percent-encoded for FileNode objects created via JMAP, breaking WebDAV clients (spec violation of RFC 3986)
- ## Summary
- When a file/folder (`FileNode`) is created through the **JMAP** API (`FileNode/set`), the resulting object's `<D:href>` in subsequent WebDAV `PROPFIND` responses contains the **raw, unencoded name** (including literal spaces and raw UTF-8 bytes for non-ASCII characters) instead of a properly percent-encoded path segment.
- Objects created directly via **WebDAV** (`MKCOL`/`PUT`) are, by contrast, always correctly percent-encoded in their `href`.
- This produces a `PROPFIND` response containing an invalid URI (per RFC 3986, spaces and non-ASCII bytes in a URI path must be percent-encoded), which appears to cause spec-compliant WebDAV clients to silently fail to display or access the affected resource.
- ## Reproduction steps
- 1. Authenticate to a Stalwart account with JMAP access
- 2. Create a folder via JMAP `FileNode/set`, e.g.:
- ```json
- {
- "using": [
- "urn:ietf:params:jmap:core",
- "urn:ietf:params:jmap:filenode",
- "urn:ietf:params:jmap:principals:owner"
- ],
- "methodCalls": [[
- "FileNode/set",
- {
- "accountId": "f",
- "create": { "dir0": { "name": "builtin fest folder" } }
- },
- "fns0"
- ]]
- }
- ```
- 3. Server responds with success and a real object id:
- ```json
- {
- "methodResponses": [[
- "FileNode/set",
- {
- "accountId": "f",
- "oldState": "s0ewq",
- "newState": "s0iwq",
- "created": { "dir0": { "id": "b7z" } }
- },
- "fns0"
- ]]
- }
- ```
- 4. Immediately after, query the same account's file storage via WebDAV:
- ```bash
- curl -u "[email protected]:password" -X PROPFIND \
- "https://mail.example.com/dav/file/[email protected]/" \
- -H "Depth: 1"
- ```
- 5. The response includes the newly created folder with an **unencoded space** in the href:
- ```xml
- <D:href>/dav/file/user%40domain.com/builtin fest folder/</D:href>
- ```
- Note the account name itself is correctly encoded (`%40` for `@`), but the folder name segment is not (`builtin fest folder` should be `builtin%20fest%20folder`).
- ## Second reproduction (non-ASCII characters)
- The same behavior was independently reproduced with a folder created with an Arabic name via the same JMAP flow:
- ```xml
- <D:href>/dav/file/user%40domain.com/فثسف يسنتا سنتاي/</D:href>
- ```
- Here, the raw UTF-8 bytes are embedded directly in the href rather than being percent-encoded (expected: `%D9%81%D8%AB%D8%B3%D9%81...` etc., consistent with how every WebDAV-created resource with non-ASCII characters is correctly encoded elsewhere in the same account).
- ## Control: WebDAV-created objects in the same account are correctly encoded
- For comparison, a folder created via a standard WebDAV `MKCOL` request in the same account:
- ```bash
- curl -u "[email protected]:password" -X MKCOL \
- "https://mail.example.com/dav/file/[email protected]/test-folder-curl/"
- ```
- returns a properly encoded href on subsequent PROPFIND:
- ```xml
- <D:href>/dav/file/user%40domain.com/test-folder-curl/</D:href>
- ```
- And every one of ~1,800 files/folders migrated into this same account via a third-party WebDAV client (rclone) — including many with spaces and Arabic names — are all correctly percent-encoded, e.g.:
- ```xml
- <D:href>/dav/file/user%40domain.com/eSpare%20Catalog/</D:href>
- <D:href>/dav/file/user%40domain.com/%D8%AC%D8%AF%D9%88%D9%84%20%D9%85%D8%AA%D8%A7%D8%A8%D8%B9%D8%A9%20%D8%B9%D9%85%D9%84%D8%A7%D8%A1.xlsx</D:href>
- ```
- This confirms the encoding logic differs specifically based on the **creation path** (JMAP vs. WebDAV), not on the presence of special characters generally.
- ## Downstream impact observed
- 1. **`Depth: infinity` PROPFIND traversal appears to break** at or around the malformed href — a recursive listing that should include the JMAP-created folder does not surface it, while a `Depth: 1` listing on the immediate parent does include it (with the malformed href).
- 2. **WinSCP** (tested as a standards-compliant WebDAV client control) does not display the JMAP-created folder in its listing at all, while it correctly displays every WebDAV-created resource in the same directory, including ones with spaces and Arabic names.
- 3. This is suspected to be the underlying cause of a related issue observed in a JMAP-based webmail client (Bulwark Webmail): objects created via JMAP `FileNode/set` return a successful response with a real object id and an advanced `state`, but the client's subsequent listing/refresh (which appears to rely on WebDAV `PROPFIND`, or shares the same href-serialization code path) never displays the newly created object, even after manual refresh, navigation, or a full page reload.
- ## Suggested fix
- When serializing a `FileNode`'s path into a WebDAV `<D:href>`, the server should percent-encode each path segment consistently, regardless of whether the underlying object was created via the JMAP or WebDAV API. The encoding logic used for WebDAV-created resources (which is correct) should be applied uniformly to all resources when generating `PROPFIND`/other WebDAV responses.
- ## Environment
- - Stalwart Mail Server version: **v0.16.18** (also reproduced on v0.16.11 prior to upgrading, ruling out a version-specific regression)
- - Deployment: Docker (`stalwartlabs/stalwart:v0.16`)
- - Storage backend: default (RocksDB)
- - File access path tested: `/dav/file/{account}`
- - Client used for JMAP creation: Bulwark Webmail v1.8.1 (browser DevTools Network tab used to capture the exact JMAP request/response shown above)
- - Client used for WebDAV verification: `curl` (raw PROPFIND) and WinSCP (independent GUI WebDAV client)
Advertisement
Add Comment
Please, Sign In to add comment