gatewayd: strict status lines and chunk lines; no as casts (M4a review, findings 1 and 3)

A status line splits on single spaces only, and every chunk line must end in CRLF. The bounded
`as` casts in http.rs, handshake.rs and proto's sha1.rs become try_from and from.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-24 01:23:51 -07:00
co-authored by Claude Opus 5.5
parent 131b3677fd
commit 0081f24b70
5 changed files with 87 additions and 28 deletions
+9 -13
View File
@@ -14,24 +14,20 @@ const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx
pub fn base64(bytes: &[u8]) -> String {
// Standard alphabet (ALPHABET), "=" padding: each 3 bytes become 4 characters; a last group of
// 1 or 2 bytes becomes 2 or 3 characters and 2 or 1 "=". No indexing that can go out of bounds.
let sextet = |n: u32, shift: u32| -> char {
let index = usize::try_from((n >> shift) & 0x3f).unwrap_or(0);
char::from(ALPHABET.get(index).copied().unwrap_or(b'A'))
};
let mut out = String::new();
for chunk in bytes.chunks(3) {
let b0 = chunk.first().copied().unwrap_or(0);
let b1 = chunk.get(1).copied().unwrap_or(0);
let b2 = chunk.get(2).copied().unwrap_or(0);
let n = ((b0 as u32) << 16) | ((b1 as u32) << 8) | (b2 as u32);
out.push(ALPHABET[((n >> 18) & 0x3f) as usize] as char);
out.push(ALPHABET[((n >> 12) & 0x3f) as usize] as char);
out.push(if chunk.len() > 1 {
ALPHABET[((n >> 6) & 0x3f) as usize] as char
} else {
'='
});
out.push(if chunk.len() > 2 {
ALPHABET[(n & 0x3f) as usize] as char
} else {
'='
});
let n = (u32::from(b0) << 16) | (u32::from(b1) << 8) | u32::from(b2);
out.push(sextet(n, 18));
out.push(sextet(n, 12));
out.push(if chunk.len() > 1 { sextet(n, 6) } else { '=' });
out.push(if chunk.len() > 2 { sextet(n, 0) } else { '=' });
}
out
}