From 14eb982db531554d557064ef10c180485e402a23 Mon Sep 17 00:00:00 2001 From: reverse Date: Wed, 19 Aug 2026 01:13:39 +0000 Subject: [PATCH] =?UTF-8?q?multiline:=20reject=20an=20over-limit=20batch?= =?UTF-8?q?=20with=20a=20FAIL=20instead=20of=20silently=20dropping=20the?= =?UTF-8?q?=20overflowing=20lines=20=E2=80=94=20accumulate()=20dropped=20a?= =?UTF-8?q?=20line=20that=20exceeded=20multiline=5Fmaxbytes/maxlines=20but?= =?UTF-8?q?=20still=20returned=20buffered=3Dtrue,=20so=20the=20client=20be?= =?UTF-8?q?lieved=20a=20truncated=20message=20was=20sent=20whole;=20now=20?= =?UTF-8?q?overflow=20flags=20the=20batch=20and=20close()=20drops=20it=20w?= =?UTF-8?q?ith=20a=20standard=20FAIL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/multiline.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/modules/multiline.rs b/src/modules/multiline.rs index 85d01f7..c9c6640 100644 --- a/src/modules/multiline.rs +++ b/src/modules/multiline.rs @@ -35,6 +35,7 @@ pub struct MlineBatch { pub notice: bool, pub parts: Vec<(String, bool)>, // (text, concat-with-previous-part) pub bytes: usize, + pub overflowed: bool, // a line exceeded the byte/line limit — reject the whole batch } /// uid -> its open batch. Stored in `Server.ext`. @@ -52,6 +53,7 @@ fn open(s: &mut Server, uid: Uid, bref: &str, target: &str) { notice: false, parts: Vec::new(), bytes: 0, + overflowed: false, }, ); } @@ -74,6 +76,10 @@ pub fn accumulate( mb.notice = notice; mb.bytes += text.len(); mb.parts.push((text.to_string(), concat)); + } else { + // over the byte/line budget — flag so close() rejects the whole batch + // rather than silently delivering a truncated message. + mb.overflowed = true; } true } @@ -90,6 +96,15 @@ fn close(s: &mut Server, uid: Uid, bref: &str) -> Option<(String, bool, Vec return None, } let mb = store.0.remove(&uid)?; + if mb.overflowed { + s.fail( + uid, + "BATCH", + "MULTILINE_INVALID", + "Multiline batch exceeded the size/line limit and was dropped.", + ); + return None; + } let mut lines: Vec = Vec::new(); for (text, concat) in mb.parts { if concat && !lines.is_empty() {