fix: cap listener connections, serve HEAD, fix feed parser CR round-trip

This commit is contained in:
randogoth 2026-10-05 11:12:23 +03:00
parent 1e782310b6
commit 267625b411
3 changed files with 244 additions and 13 deletions

View file

@ -96,8 +96,14 @@ impl Feed {
}
pub fn parse(text: &str) -> Feed {
// Trailing CRs are line endings, never content: `str::lines` strips
// only one CR before a newline, so a CR run would survive one parse
// and partly vanish on the next, breaking the render fixpoint.
Feed {
items: text.lines().map(parse_line).collect(),
items: text
.lines()
.map(|line| parse_line(line.trim_end_matches('\r')))
.collect(),
}
}
@ -424,4 +430,34 @@ mod tests {
self.meta("nick")
}
}
/// xorshift: deterministic pseudo-randomness, dependency-free.
fn next(seed: &mut u64) -> u64 {
*seed ^= *seed << 13;
*seed ^= *seed >> 7;
*seed ^= *seed << 17;
*seed
}
#[test]
fn parse_never_panics_and_render_reaches_a_fixpoint() {
// Hostile pieces in random order: the parser must survive anything,
// and whatever it accepts must render to a form that re-parses to
// itself, so a store save can never corrupt a feed it loaded.
let pieces = [
"# ", "# key = value\n", "smol:mail ", "smol:repost ", "\t", "\n", "---\n",
"2026-10-01T12:47:00Z", "a", "mfrggzdfmztwq2lknnwg23tpoa3...", "/", "\u{e9}",
"\r", " ", "#\n", "smol:host_key = ",
];
let mut seed = 0x5eed_1234_u64;
for _ in 0..2000 {
let n = (next(&mut seed) % 48) as usize;
let input: String = (0..n)
.map(|_| pieces[(next(&mut seed) % pieces.len() as u64) as usize])
.collect();
let once = Feed::parse(&input).render();
let twice = Feed::parse(&once).render();
assert_eq!(once, twice, "render must be a fixpoint after parse");
}
}
}