From 8f379db15e3592beeb3272c14a338cf758c25114 Mon Sep 17 00:00:00 2001 From: saphid <4596216+saphid@users.noreply.github.com> Date: Sat, 26 Sep 2026 23:16:57 +1000 Subject: [PATCH] Skip the stalled-download quit tests on Windows, and say why Waking a recv blocked in another thread needs the handle closed on Windows, which isn't safe under a TLS read (the previous commit, reverted after review). A stalled download there holds the quit for the 4 s grace period; its partial file is swept on the next start. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/web-install.md | 8 ++++++++ tests/test_webinstall.py | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/docs/web-install.md b/docs/web-install.md index f078a74..d77dfd7 100644 --- a/docs/web-install.md +++ b/docs/web-install.md @@ -148,3 +148,11 @@ The manifest's file URL must then be `http://localhost:8000/…` or `frame_webinstall.dispatch()` and deletes the folder. - The app registers the scheme each time it starts, so the last Frame Control started (e.g. a development checkout) handles the links. + +**Quitting during a stalled download.** On macOS and Linux, quitting stops a +download at once (`shutdown()` on its socket wakes the blocked read). On +Windows that doesn't wake a read in another thread, and closing the handle +under a TLS read isn't safe, so a download that has stalled holds the quit for +the 4-second grace period until the app stops the server; the partial file is +removed on the next start. Downloads that are still moving stop at their next +read either way. diff --git a/tests/test_webinstall.py b/tests/test_webinstall.py index 53917b7..1858297 100644 --- a/tests/test_webinstall.py +++ b/tests/test_webinstall.py @@ -328,6 +328,10 @@ class ServerJobs(unittest.TestCase): self.assertEqual((job["phase"], job["message"]), ("done", "ok")) def stall_then_shutdown(self, scheme, reply): + if os.name == "nt": + # shutdown() from another thread doesn't wake a blocked recv on Windows, and + # closing the handle under a TLS read isn't safe; see web-install.md. + self.skipTest("Windows: a stalled download is only dropped when the app stops the server") """Start a download from a server that stalls after sending reply; shutdown must stop it quickly.""" stall = socket.socket() stall.bind(("127.0.0.1", 0))