pub const MAX_YAML_FLOW_DEPTH: usize = 1024;
#[must_use]
pub fn flow_depth_within_limit(text: &str) -> bool {
let bytes = text.as_bytes();
let mut i = 0usize;
let mut depth = 0usize;
let mut prev_significant: u8 = 0;
while i < bytes.len() {
let c = bytes[i];
match c {
b'\n' => {
prev_significant = 0;
i += 1;
}
b' ' | b'\t' | b'\r' => {
i += 1;
}
b'"' => {
i += 1;
while i < bytes.len() {
match bytes[i] {
b'\\' => i += 2,
b'"' => {
i += 1;
break;
}
_ => i += 1,
}
}
prev_significant = b'"';
}
b'\'' => {
i += 1;
while i < bytes.len() {
if bytes[i] == b'\'' {
if bytes.get(i + 1) == Some(&b'\'') {
i += 2;
} else {
i += 1;
break;
}
} else {
i += 1;
}
}
prev_significant = b'\'';
}
b'#' if depth == 0 && (prev_significant == 0 || prev_significant == b' ') => {
while i < bytes.len() && bytes[i] != b'\n' {
i += 1;
}
}
b'[' | b'{' => {
let opens_flow = depth > 0
|| matches!(
prev_significant,
0 | b':' | b'-' | b',' | b'?' | b'[' | b'{'
);
if opens_flow {
depth += 1;
if depth > MAX_YAML_FLOW_DEPTH {
return false;
}
}
prev_significant = c;
i += 1;
}
b']' | b'}' => {
depth = depth.saturating_sub(1);
prev_significant = c;
i += 1;
}
_ => {
prev_significant = c;
i += 1;
}
}
}
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn shallow_and_realistic_yaml_passes() {
assert!(flow_depth_within_limit(
"a: [1, 2, [3, {b: 4}]]\nc:\n - x\n - y\n"
));
assert!(flow_depth_within_limit(&"k: value[0][1]\n".repeat(5000)));
assert!(flow_depth_within_limit(&"k: \"[[[[[[[[[[\"\n".repeat(5000)));
}
#[test]
fn deep_flow_nesting_is_rejected() {
let bomb = format!("x: {}{}", "[".repeat(5000), "]".repeat(5000));
assert!(!flow_depth_within_limit(&bomb));
let bomb2 = format!("x: {}1{}", "[1,".repeat(2000), "]".repeat(2000));
assert!(!flow_depth_within_limit(&bomb2));
let bomb3 = format!("x: {}1{}", "{a: ".repeat(2000), "}".repeat(2000));
assert!(!flow_depth_within_limit(&bomb3));
}
}