Local API: uploaded filenames keep "+" for spaces (Zotero 10.0.5)

When I upload a file through the Zotero 10 local API, any space in the filename is stored as a literal "+". A PDF uploaded as `Heitzig and Hiller - 2020 - Degrees.pdf` ends up in storage as `Heitzig+and+Hiller+-+2020+-+Degrees.pdf`, likewise in the attachment's filename field The same upload through the web API stores the name with spaces instead of pluses.

To reproduce, against `http://127.0.0.1:23119/api/users/0/` with a local API key:

1. Create an `imported_file` attachment item.
2. `POST items//file` with `Content-Type: application/x-www-form-urlencoded`, `If-None-Match: *`, and a body containing `filename=a+b.pdf` plus the usual `md5`, `filesize` and `mtime`.
3. Upload the file to the returned URL and register it with `upload=`.

The stored filename is `a+b.pdf`; I'd expect `a b.pdf`. In the form encoding implied by POST `+` stands for a space, and common clients encode spaces that way: pyzotero (via httpx), requests, and browsers.

Workaround: Sending `filename=a%20b.pdf` to the local API instead stores `a b.pdf`.

My trusty LLM diagnosed as follows:

>The cause looks like `Zotero.Server.decodeQueryString` in `chrome/content/zotero/xpcom/server/server.js` (around line 107 in 10.0.5, unchanged on main). It decodes each key and value with `decodeURIComponent` alone, which leaves `+` as `+`. The file endpoint then takes `params.filename` as given. The tag endpoint in `server_localAPI.js` already handles the same case with `replaceAll('+', '%20')`. Replacing `+` with a space before `decodeURIComponent`, or parsing the body with `URLSearchParams`, would fix it. Since `decodeQueryString` also handles other form-encoded requests, such as the connector's, it would be worth checking those, though form encoders always send a real `+` as `%2B`.

Zotero 10.0.5 on macOS 26.6.2, pyzotero 1.15.2.

Sign In or Register to comment.