use rand::{self, Rng};
const MULTIPART_BOUNDARY_MAX_LENGTH: usize = 66;
static BOUNDARY_CHARS: &[char] = &[
'\'',
'(', ')', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', '=', '?',
'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '_',
'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z',
];
static ANTI_COLLISION_CHARS: &str = "=_^";
pub fn create_structured_random_boundary(count: usize) -> String {
let mut out = format!("{anti_collision}{count:x}.",
anti_collision=ANTI_COLLISION_CHARS,
count=count
);
let rem = MULTIPART_BOUNDARY_MAX_LENGTH-out.len();
out.reserve(rem);
let mut rng = rand::thread_rng();
let len = BOUNDARY_CHARS.len();
for _ in 0..rem {
let idx = rng.gen_range(0, len);
out.push(BOUNDARY_CHARS[idx]);
}
out
}
#[cfg(test)]
mod test {
mod write_random_boundary_to {
use super::super::*;
#[test]
fn boundary_is_not_quoted() {
let out = create_structured_random_boundary(0);
assert!(!out.starts_with("\""));
assert!(!out.ends_with("\""));
}
#[test]
fn boundary_start_special() {
let out = create_structured_random_boundary(0);
assert!(out.starts_with("=_^0."));
}
#[test]
fn boundary_has_a_resonable_length() {
let out = create_structured_random_boundary(0);
assert!(out.len() > 22 && out.len() <= MULTIPART_BOUNDARY_MAX_LENGTH);
let out = create_structured_random_boundary(1000);
assert!(out.len() > 22 && out.len() <= MULTIPART_BOUNDARY_MAX_LENGTH);
}
#[test]
fn boundary_does_not_contain_space_or_slach_or_quotes() {
let out = create_structured_random_boundary(0);
for ch in out[1..out.len()-1].chars() {
assert!(ch as u32 >= 32);
assert!(ch as u32 <= 126);
assert_ne!(ch, '\t');
assert_ne!(ch, '\\');
assert_ne!(ch, '"');
}
assert_ne!(out.as_bytes()[out.len()-1], b' ');
}
}
}