fix(vp): stop uvloop from silently truncating VP FTP uploads (#1896)

Native (non-Docker) installs launched uvicorn without --loop asyncio, so
uvicorn[standard] auto-selected uvloop. uvloop's SSL layer drops
already-received but still-buffered data when the client closes the data
connection without a TLS close_notify while the reader is flow-control
paused on slow storage. cmd_STOR writes each chunk to disk inside the read
loop, so a slow consumer falls behind, the tail is lost, read() returns a
clean EOF, and the loop exits with no exception -- the server acked 226 for
a file it truncated itself, then archived, queued, and forwarded the corrupt
3MF to the real printer.

Fix in two independent layers:

1. Remove the trigger: add --loop asyncio to every native launch path,
   matching the Dockerfile -- deploy/bambuddy.service, install/install.sh
   (systemd + launchd), spoolbuddy/install/install.sh, the Windows NSSM
   service, README, CONTRIBUTING dev command.

2. Defense in depth (loop-independent): cmd_STOR now validates that a
   received .3mf opens as a ZIP (reads the central directory, no
   decompression) before replying 226. A truncated/corrupt file is dropped
   and answered with 426, and on_file_received never runs -- so a broken
   upload surfaces as an immediate slicer-side send error instead of being
   archived and pushed to the printer. Scoped to .3mf; other filetypes pass
   through unchanged.
This commit is contained in:
maziggy
2026-07-05 10:32:13 +02:00
parent 168d9d8f8e
commit 7d4dfd5a7d
10 changed files with 125 additions and 10 deletions
+5 -1
View File
@@ -548,7 +548,8 @@ Environment="DATA_DIR=$DATA_DIR"
Environment="LOG_DIR=$LOG_DIR"
Environment="TZ=$TIMEZONE"
ExecStart=$INSTALL_PATH/venv/bin/uvicorn backend.app.main:app --host $BIND_ADDRESS --port $PORT
# --loop asyncio required: uvloop can truncate VP FTP uploads (#1896)
ExecStart=$INSTALL_PATH/venv/bin/uvicorn backend.app.main:app --host $BIND_ADDRESS --port $PORT --loop asyncio
Restart=on-failure
RestartSec=5
StandardOutput=journal
@@ -613,6 +614,9 @@ create_launchd_service() {
<string>$BIND_ADDRESS</string>
<string>--port</string>
<string>$PORT</string>
<!-- the loop asyncio flag below is required: uvloop can truncate VP FTP uploads, #1896 -->
<string>--loop</string>
<string>asyncio</string>
</array>
<key>WorkingDirectory</key>
<string>$INSTALL_PATH</string>