Expand description
#1667: a framing pump in front of tower-lsp’s transport.
tower-lsp 0.20 reads stdin through a FramedRead, and a framed stream
ends at its first decode error. So one message whose body isn’t valid JSON
stopped the whole server, with exit 0 and nothing on stderr. The trigger
is reachable from a well-behaved client: JSON.stringify writes a lone
UTF-16 surrogate in a string as \udcff, which serde_json rejects.
pump reads the client’s frames itself and forwards to the server only
bodies that parse, so a bad one can’t end the stream:
- a body that parses is forwarded unchanged;
- a body whose only fault is a lone surrogate escape is repaired (each
lone
\uD800–\uDFFFbecomes\uFFFD) and forwarded. U+FFFD is one UTF-16 code unit, like the surrogate it replaces, so the client’s positions into the text stay aligned with the server’s; - any other body is logged and skipped. Its
idcan’t be recovered from unparseable JSON, so no error response is possible.
A header block without Content-Length, or a stream that ends mid-frame
(a truncated body), leaves nothing to resynchronise on: the pump stops,
with the reason logged, and the server sees end of input.
#2239: the pump also stops once it has forwarded exit. tower-lsp 0.20
handles a message that arrives after exit by leaving its read loop early,
without the clean-up it does at end of input, so Server::serve never
returned and the process never exited. Ending the server’s input after
exit means it only ever sees end of input next, whatever the client sends.
Enums§
Constants§
- MAX_
BODY - #1771 review: the largest body
pumpaccepts. AContent-Lengthis otherwise trusted and allocated in full before the body arrives, so one corrupted digit could abort the process. A frame over this is unrecoverable framing, like a missingContent-Length. 128 MiB is far above any real message (adidOpencarries one file’s text). - MAX_
HEADER_ LINE - The longest header line
pumpreads, so a client that never sends a newline can’t grow the line without limit.
Functions§
- classify
- Decide what to do with one frame’s body.
- is_exit
- Whether
bodyis theexitnotification, after which the server reads nothing more. - pump
- Read framed messages from
inputand write the usable ones, re-framed, tooutput. Returns wheninputends or loses its framing, or onceexitis forwarded (#2239). Droppingoutputthen ends the server’s input.