Skip to content

Fix write hang, WebSocket dispatch, dead rockspec URLs - #373

Merged
kernelsauce merged 3 commits into
masterfrom
post-release-fixes
Aug 16, 2026
Merged

Fix write hang, WebSocket dispatch, dead rockspec URLs#373
kernelsauce merged 3 commits into
masterfrom
post-release-fixes

Conversation

@kernelsauce

Copy link
Copy Markdown
Owner

Summary

  • Zero-length writes (e.g. a 0-byte static file, or write("")) used to never complete: send()/SSL_write() legitimately return 0 for an empty buffer, and the write handlers treated any 0 return as "would block, retry" instead of checking completion first. For write_zero_copy() this spun the ioloop at ~100% CPU forever. Fixed in all four write handlers in iostream.lua.
  • WebSocketHandler:open() never received URL route captures, even though every other handler gets them via self._url_args. Fixed, with a nil guard for handlers not built through normal Application dispatch.
  • WebSocket big-endian support (_frame_len_16, _frame_len_64, _send_frame) was a set of empty stubs, a hard crash on ppc/s390x hosts rather than just a byte-order bug. Implemented (wire order already equals host order on BE, so no byte-swap needed). Not tested on real BE hardware, verified by code reading against RFC 6455 only.
  • All rockspecs pointed at git://github.com/..., which GitHub disabled in 2022, breaking luarocks install turbo entirely. Fixed for the non-frozen rockspecs (turbo-2.1-4, turbo-dev-1).
  • Added spec/websocket_spec.lua and a couple of regression tests to spec/iostream_spec.lua, and wired the websocket spec into the default CI run.

Closes #332, #328, #268, #340

Test plan

  • make docker-test (default suite): 72/0
  • make docker-test ARGS="spec/iostream_spec.lua": new tests pass, confirmed they fail with Sync wait operation timed out against the pre-fix code
  • make docker-test ARGS="spec/websocket_spec.lua": 3/3
  • Live check in Docker: curled a real 0-byte file through StaticFileHandler, 200 response in ~3ms, CPU idle afterward

send()/SSL_write() return 0 for an empty buffer, which the write
handlers mistook for EWOULDBLOCK and kept retrying instead of
completing. For write_zero_copy() this spun the ioloop at 100% CPU
forever (e.g. serving a zero-length static file); for the regular
write() path the callback just silently never fired. Complete an
empty buffer immediately in all four write handlers instead of
calling send()/SSL_write() with length 0.
_continue_ws called self:open() with no arguments, so route capture
groups never reached user handlers even though every other handler
gets them via self._url_args. Guard against a nil _url_args too, for
handlers not built through normal Application dispatch.

Also implement the big-endian frame length/send functions, which
were empty stubs and a hard crash on ppc/s390x hosts. On a BE host
wire order already equals host order, so these are the LE versions
minus the byte-swap calls.
GitHub disabled the unauthenticated git protocol in 2022, so
source.url in these rockspecs is unreachable. Switch to git+https
for the specs that aren't frozen historical releases. Also add the
new websocket spec to the default Docker test run, it's headless
and deterministic like the others already there.
@kernelsauce
kernelsauce merged commit 8fa2410 into master Aug 16, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Zero length static file request force near 100% CPU utilisation.

1 participant