POP3: `TOP N 0` returns full message body instead of zero body lines
## Description
The POP3 `TOP <msg> <lines>` command does not respect the `lines` argument when `lines` is `0`. Per RFC 1939, `TOP N 0` should return only the message headers, the blank separator line, and the `.` terminator. Stalwart returns the **entire message body** instead.
This breaks header-peek behavior in clients (e.g., Apple Mail) that issue `TOP N 0` to populate the message list without downloading full bodies. For large messages, the client receives hundreds of KB where it expected a few KB, which can leave messages in a degraded state in the local index (observed: messages displayed with empty From/Subject in the inbox view despite valid envelope data on the server).
## Repro
Against any POP3 mailbox containing a multi-KB message:
```
TOP 1 0
```
Observed: server streams full headers + blank line + full body + `.\r\n`.
Expected: server streams headers + blank line + `.\r\n` (zero body lines).
Verified against Stalwart 0.16.3.
## Root cause
In `crates/pop3/src/protocol/response.rs`, the `Response::Message::serialize()` body-truncation loop is gated on `*lines > 0`:
```rust
if *lines > 0 && byte == b'\n' {
line_count += 1;
if line_count == *lines {
break;
}
}
```
When `lines == 0`, the truncation block is skipped entirely and the loop runs to end-of-message.
The deeper issue is in the type itself: `Response::Message { lines: u32, .. }` cannot distinguish "no limit" (RETR) from "zero body lines" (TOP N 0). At the call site in `crates/pop3/src/op/fetch.rs`, `lines.unwrap_or(0)` collapses both into `0`, so RETR and `TOP N 0` end up on the same code path.
## Suggested fix
Change the field to `Option<u32>`:
- `RETR` → `lines: None` (no truncation)
- `TOP N k` → `lines: Some(k)` (truncate to k body lines, including `k == 0`)
Truncation logic becomes:
```rust
if let Some(limit) = *lines {
if byte == b'\n' {
line_count += 1;
if line_count > limit {
break;
}
}
}
```
(Using `>` rather than `==` so that `Some(0)` breaks at the blank line separating headers from body, before any body bytes are emitted.)
Happy to send a PR if helpful.
关闭于 2026-05-06 1 条评论