Expand description
One bounded, \n-terminated read, shared by the line-oriented text protocols.
tokio::io::AsyncBufReadExt::read_line grows its String until it finds a newline and
caps nothing. A peer that connects and streams printable bytes without ever sending \n
therefore makes the server allocate without bound — a one-connection out-of-memory, from an
unauthenticated socket, before any model call. That defect was found in ftp, irc and
smtp and fixed three separate times, then found again in imap, nntp and pop3.
Three copies of a fill_buf/consume loop is how the control-character filters ended up
with six different semantics before utils::sanitize existed, so this is one
implementation rather than a sixth. Each protocol still owns its own MAX_* constant and
its own refusal wording — the bound is a protocol decision, the reading is not.
The cap is on what is buffered, not on what is consumed. A line longer than the cap is
reported as BoundedLine::TooLong with the offending bytes left unconsumed, because there
is no resynchronisation point: the peer is mid-line and the next byte is not the start of a
command. Every caller answers in its own vocabulary and closes.
Decoding is lossy. read_line returns ErrorKind::InvalidData for any non-UTF-8 byte and
kills the session on it, which is wrong for protocols that advertise 8-bit transports
(smtp’s 8BITMIME, imap’s literals). These bytes become an event payload and a log
line; nothing here is re-emitted on the wire, so a lossy decode loses nothing a peer can
observe.
Enums§
- Bounded
Line - The outcome of one bounded line read.
Functions§
- read_
bounded_ delimited - Read one complete byte-delimited frame, preserving binary payloads and enforcing
the cap before allocation. EOF with a fragment is an error. Keep this future alive
across unrelated commands: like
read_until, cancellation discards its partial frame. - read_
bounded_ line - Read one
\n-terminated line, buffering at mostmax_lenbytes.