1use rand::{self, Rng};
3
4
5
6const MULTIPART_BOUNDARY_MAX_LENGTH: usize = 66;
8
9static BOUNDARY_CHARS: &[char] = &[
11 '\'',
12 '(', ')', '+', ',', '-', '.', '/',
13 '0', '1', '2', '3', '4', '5', '6', '7',
14 '8', '9', ':', '=', '?',
15 'A', 'B', 'C', 'D', 'E', 'F', 'G',
16 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
17 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
18 'X', 'Y', 'Z', '_',
19 'a', 'b', 'c', 'd', 'e', 'f', 'g',
20 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
21 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
22 'x', 'y', 'z',
23];
24
25static ANTI_COLLISION_CHARS: &str = "=_^";
27
28pub fn create_structured_random_boundary(count: usize) -> String {
59 let mut out = format!("{anti_collision}{count:x}.",
60 anti_collision=ANTI_COLLISION_CHARS,
61 count=count
62 );
63
64 let rem = MULTIPART_BOUNDARY_MAX_LENGTH-out.len();
65 out.reserve(rem);
66
67 let mut rng = rand::thread_rng();
68 let len = BOUNDARY_CHARS.len();
69 for _ in 0..rem {
70 let idx = rng.gen_range(0, len);
71 out.push(BOUNDARY_CHARS[idx]);
72 }
73
74 out
75}
76
77
78#[cfg(test)]
79mod test {
80
81 mod write_random_boundary_to {
82 use super::super::*;
83
84 #[test]
85 fn boundary_is_not_quoted() {
86 let out = create_structured_random_boundary(0);
87 assert!(!out.starts_with("\""));
88 assert!(!out.ends_with("\""));
89 }
90
91 #[test]
92 fn boundary_start_special() {
93 let out = create_structured_random_boundary(0);
94 assert!(out.starts_with("=_^0."));
95 }
96
97 #[test]
98 fn boundary_has_a_resonable_length() {
99 let out = create_structured_random_boundary(0);
100 assert!(out.len() > 22 && out.len() <= MULTIPART_BOUNDARY_MAX_LENGTH);
101 let out = create_structured_random_boundary(1000);
102 assert!(out.len() > 22 && out.len() <= MULTIPART_BOUNDARY_MAX_LENGTH);
103 }
104
105 #[test]
106 fn boundary_does_not_contain_space_or_slach_or_quotes() {
107 let out = create_structured_random_boundary(0);
109
110 for ch in out[1..out.len()-1].chars() {
111 assert!(ch as u32 >= 32);
112 assert!(ch as u32 <= 126);
113 assert_ne!(ch, '\t');
114 assert_ne!(ch, '\\');
115 assert_ne!(ch, '"');
116 }
117
118 assert_ne!(out.as_bytes()[out.len()-1], b' ');
119 }
120 }
121}