From 9f8ed57dd68c1c9d462bea3a4fac591ea0736e52 Mon Sep 17 00:00:00 2001 From: Sion Kang Date: Wed, 6 May 2026 18:10:45 +0900 Subject: [PATCH] perf: raise server MAX_READ_SIZE to SFTP standard 255 KiB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bssh-server hard-capped every SFTP `READ` reply at 64 KiB (`MAX_READ_SIZE = 65536`) regardless of what the client requested. `bssh-russh-sftp` and OpenSSH's `sftp-server` both use the SFTP standard `MAX_READ_LENGTH = 261120` (255 KiB) for request sizing, so a client asking for a 256 KiB chunk only ever got 64 KiB back, forcing it to issue four extra requests for the same byte stream. Bump `MAX_READ_SIZE` to `261120` so server replies match the standard chunk size used by the rest of the stack. Combined with client-side pipelining (#196), this directly cuts the per-MiB request count on downloads from 16 → 4. Memory exposure stays bounded: handles are still capped at `MAX_HANDLES = 1000` per session and each in-flight read still uses a single per-request buffer of this size (max ~255 KiB × in-flight requests). --- src/server/sftp.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/server/sftp.rs b/src/server/sftp.rs index b4119b53..6a59b69c 100644 --- a/src/server/sftp.rs +++ b/src/server/sftp.rs @@ -164,8 +164,15 @@ struct DirEntryInfo { /// Maximum number of open handles per session to prevent resource exhaustion. const MAX_HANDLES: usize = 1000; -/// Maximum read buffer size (64KB) to prevent memory exhaustion. -const MAX_READ_SIZE: u32 = 65536; +/// Maximum read buffer size per request. Matches the SFTP standard +/// `MAX_READ_LENGTH` (255 KiB) used by `bssh-russh-sftp` and OpenSSH +/// `sftp-server`. The previous 64 KiB cap silently truncated client `READ` +/// requests for 256 KiB chunks down to 64 KiB, multiplying request count 4× +/// for the same byte stream and dragging down sustained download throughput. +/// Memory exposure remains bounded because handles are capped at +/// [`MAX_HANDLES`] per session and each in-flight read uses a single +/// per-request buffer of this size. +const MAX_READ_SIZE: u32 = 261120; /// Normalize a path's `..` and `.` components without touching the filesystem. ///