From de6b14b5417e2875a1dd8e9be93b3e689cec5704 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Wed, 28 Oct 2026 05:04:53 +0000 Subject: [PATCH] Accept CRLF lines of exactly the maximum length in the MCP reader Found while testing crates/mcp/src/server.rs:180-205 (read_line_capped) Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/mcp/src/server.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/crates/mcp/src/server.rs b/crates/mcp/src/server.rs index 8fef0ee46..c0139bccc 100644 --- a/crates/mcp/src/server.rs +++ b/crates/mcp/src/server.rs @@ -189,6 +189,13 @@ pub(crate) fn read_line_capped(reader: &mut impl BufRead, buf: &mut Vec, max upto.min(max.saturating_add(1).saturating_sub(buf.len())) }; if take == 0 { + // Exactly `max` content bytes plus the `\r` of a CRLF ending fill the bound; the line + // is still within the limit when the `\n` follows. + if buf.last() == Some(&b'\r') && reader.fill_buf()?.first() == Some(&b'\n') { + reader.consume(1); + buf.pop(); + return Ok(true); + } // Already past the bound: the caller sees `buf.len() > max`. return Ok(true); } @@ -459,3 +466,29 @@ impl Server { } } } + +#[cfg(test)] +mod line_reader_tests { + use super::read_line_capped; + use std::io::Cursor; + + #[test] + fn crlf_line_of_exactly_max_bytes_is_within_the_limit() { + for ending in ["\n", "\r\n"] { + let mut input = Cursor::new(format!("{}{ending}next\n", "a".repeat(10)).into_bytes()); + let mut buf = Vec::new(); + assert!(read_line_capped(&mut input, &mut buf, 10).unwrap()); + assert_eq!(buf, b"aaaaaaaaaa", "ending {ending:?}"); + assert!(read_line_capped(&mut input, &mut buf, 10).unwrap()); + assert_eq!(buf, b"next"); + } + } + + #[test] + fn crlf_line_over_max_is_still_overlong() { + let mut input = Cursor::new(format!("{}\r\n", "a".repeat(11)).into_bytes()); + let mut buf = Vec::new(); + assert!(read_line_capped(&mut input, &mut buf, 10).unwrap()); + assert!(buf.len() > 10); + } +}