ic_http_certification/utils/
wildcard_paths.rs1pub const PATH_PREFIX: &str = "http_expr";
3
4pub const PATH_PREFIX_BYTES: &[u8] = PATH_PREFIX.as_bytes();
6
7pub const PATH_DIR_SEPARATOR: &str = "";
9
10pub const PATH_DIR_SEPARATOR_BYTES: &[u8] = PATH_DIR_SEPARATOR.as_bytes();
12
13pub const EXACT_PATH_TERMINATOR: &str = "<$>";
15
16pub const EXACT_PATH_TERMINATOR_BYTES: &[u8] = EXACT_PATH_TERMINATOR.as_bytes();
18
19pub const WILDCARD_PATH_TERMINATOR: &str = "<*>";
21
22pub const WILDCARD_PATH_TERMINATOR_BYTES: &[u8] = WILDCARD_PATH_TERMINATOR.as_bytes();
24
25pub fn is_wildcard_path_valid_for_request_path(
27 wildcard_path: &[Vec<u8>],
28 request_path: &[Vec<u8>],
29) -> bool {
30 if request_path.starts_with(wildcard_path) {
32 return true;
33 }
34
35 if wildcard_path.ends_with(&[PATH_DIR_SEPARATOR_BYTES.to_vec()]) {
38 return request_path.starts_with(&wildcard_path[..wildcard_path.len() - 1]);
39 }
40
41 false
42}
43
44fn strip_path_affixes(path: &mut Vec<Vec<u8>>) {
45 if matches!(
47 path.first(),
48 Some(first) if first == PATH_PREFIX_BYTES,
49 ) {
50 path.remove(0);
51 }
52
53 if matches!(path.last(), Some(last) if
55 last == EXACT_PATH_TERMINATOR_BYTES ||
56 last == WILDCARD_PATH_TERMINATOR_BYTES)
57 {
58 path.pop();
59 }
60
61 if path.len() > 1
65 && matches!(
66 path.first(),
67 Some(first) if first == PATH_DIR_SEPARATOR_BYTES,
68 )
69 {
70 path.remove(0);
71 }
72}
73
74pub fn more_specific_wildcards_for(
83 requested_path: &[Vec<u8>],
84 responding_wildcard_path: &[Vec<u8>],
85) -> Vec<Vec<Vec<u8>>> {
86 let mut valid_wildcards: Vec<Vec<Vec<u8>>> = vec![];
87
88 let mut potential_path = requested_path.to_vec();
89 strip_path_affixes(&mut potential_path);
90
91 let mut responding_wildcard_path = responding_wildcard_path.to_vec();
92 strip_path_affixes(&mut responding_wildcard_path);
93
94 if !is_wildcard_path_valid_for_request_path(&responding_wildcard_path, &potential_path) {
97 responding_wildcard_path = vec![];
98 }
99
100 while potential_path.len() > responding_wildcard_path.len()
101 || potential_path.last() != responding_wildcard_path.last()
102 {
103 potential_path.push(WILDCARD_PATH_TERMINATOR_BYTES.to_vec());
104 valid_wildcards.push(potential_path.clone());
105 potential_path.pop(); if potential_path.ends_with(&[PATH_DIR_SEPARATOR_BYTES.to_vec()]) {
110 potential_path.pop(); } else {
112 potential_path.pop(); potential_path.push(PATH_DIR_SEPARATOR_BYTES.to_vec());
114 }
115 }
116
117 valid_wildcards
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use rstest::*;
124
125 #[rstest]
126 #[case(responding_path_a(), more_specific_paths_a())]
127 #[case(responding_path_b(), more_specific_paths_b())]
128 #[case(responding_path_c(), more_specific_paths_c())]
129 #[case(responding_path_d(), more_specific_paths_d())]
130 #[case(responding_path_e(), more_specific_paths_e())]
131 #[case(responding_path_f(), more_specific_paths_f())]
132 #[case(responding_path_g(), more_specific_paths_g())]
133 #[case(responding_path_h(), more_specific_paths_h())]
134 fn test_more_specific_wildcards_for(
135 requested_path: Vec<Vec<u8>>,
136 #[case] responding_path: Vec<Vec<u8>>,
137 #[case] expected: Vec<Vec<Vec<u8>>>,
138 ) {
139 let more_specific_paths = more_specific_wildcards_for(&requested_path, &responding_path);
140
141 assert_eq!(more_specific_paths, expected);
142 }
143
144 #[fixture]
145 fn requested_path() -> Vec<Vec<u8>> {
146 vec![b"a".to_vec(), b"b".to_vec(), b"c".to_vec()]
147 }
148
149 #[fixture]
150 fn responding_path_a() -> Vec<Vec<u8>> {
151 vec![b"a".to_vec(), b"b".to_vec(), b"c".to_vec()]
152 }
153
154 #[fixture]
155 fn more_specific_paths_a() -> Vec<Vec<Vec<u8>>> {
156 vec![]
157 }
158
159 #[fixture]
160 fn responding_path_b() -> Vec<Vec<u8>> {
161 vec![
162 b"a".to_vec(),
163 b"b".to_vec(),
164 PATH_DIR_SEPARATOR_BYTES.to_vec(),
165 ]
166 }
167
168 #[fixture]
169 fn more_specific_paths_b() -> Vec<Vec<Vec<u8>>> {
170 vec![vec![
171 b"a".to_vec(),
172 b"b".to_vec(),
173 b"c".to_vec(),
174 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
175 ]]
176 }
177
178 #[fixture]
179 fn responding_path_c() -> Vec<Vec<u8>> {
180 vec![b"a".to_vec(), b"b".to_vec()]
181 }
182
183 #[fixture]
184 fn more_specific_paths_c() -> Vec<Vec<Vec<u8>>> {
185 vec![
186 vec![
187 b"a".to_vec(),
188 b"b".to_vec(),
189 b"c".to_vec(),
190 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
191 ],
192 vec![
193 b"a".to_vec(),
194 b"b".to_vec(),
195 PATH_DIR_SEPARATOR_BYTES.to_vec(),
196 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
197 ],
198 ]
199 }
200
201 #[fixture]
202 fn responding_path_d() -> Vec<Vec<u8>> {
203 vec![b"a".to_vec(), PATH_DIR_SEPARATOR_BYTES.to_vec()]
204 }
205
206 #[fixture]
207 fn more_specific_paths_d() -> Vec<Vec<Vec<u8>>> {
208 vec![
209 vec![
210 b"a".to_vec(),
211 b"b".to_vec(),
212 b"c".to_vec(),
213 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
214 ],
215 vec![
216 b"a".to_vec(),
217 b"b".to_vec(),
218 PATH_DIR_SEPARATOR_BYTES.to_vec(),
219 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
220 ],
221 vec![
222 b"a".to_vec(),
223 b"b".to_vec(),
224 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
225 ],
226 ]
227 }
228
229 #[fixture]
230 fn responding_path_e() -> Vec<Vec<u8>> {
231 vec![b"a".to_vec()]
232 }
233
234 #[fixture]
235 fn more_specific_paths_e() -> Vec<Vec<Vec<u8>>> {
236 vec![
237 vec![
238 b"a".to_vec(),
239 b"b".to_vec(),
240 b"c".to_vec(),
241 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
242 ],
243 vec![
244 b"a".to_vec(),
245 b"b".to_vec(),
246 PATH_DIR_SEPARATOR_BYTES.to_vec(),
247 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
248 ],
249 vec![
250 b"a".to_vec(),
251 b"b".to_vec(),
252 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
253 ],
254 vec![
255 b"a".to_vec(),
256 PATH_DIR_SEPARATOR_BYTES.to_vec(),
257 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
258 ],
259 ]
260 }
261
262 #[fixture]
263 fn responding_path_f() -> Vec<Vec<u8>> {
264 vec![PATH_DIR_SEPARATOR_BYTES.to_vec()]
265 }
266
267 #[fixture]
268 fn more_specific_paths_f() -> Vec<Vec<Vec<u8>>> {
269 vec![
270 vec![
271 b"a".to_vec(),
272 b"b".to_vec(),
273 b"c".to_vec(),
274 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
275 ],
276 vec![
277 b"a".to_vec(),
278 b"b".to_vec(),
279 PATH_DIR_SEPARATOR_BYTES.to_vec(),
280 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
281 ],
282 vec![
283 b"a".to_vec(),
284 b"b".to_vec(),
285 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
286 ],
287 vec![
288 b"a".to_vec(),
289 PATH_DIR_SEPARATOR_BYTES.to_vec(),
290 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
291 ],
292 vec![b"a".to_vec(), WILDCARD_PATH_TERMINATOR_BYTES.to_vec()],
293 ]
294 }
295
296 #[fixture]
297 fn responding_path_g() -> Vec<Vec<u8>> {
298 vec![]
299 }
300
301 #[fixture]
302 fn more_specific_paths_g() -> Vec<Vec<Vec<u8>>> {
303 vec![
304 vec![
305 b"a".to_vec(),
306 b"b".to_vec(),
307 b"c".to_vec(),
308 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
309 ],
310 vec![
311 b"a".to_vec(),
312 b"b".to_vec(),
313 PATH_DIR_SEPARATOR_BYTES.to_vec(),
314 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
315 ],
316 vec![
317 b"a".to_vec(),
318 b"b".to_vec(),
319 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
320 ],
321 vec![
322 b"a".to_vec(),
323 PATH_DIR_SEPARATOR_BYTES.to_vec(),
324 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
325 ],
326 vec![b"a".to_vec(), WILDCARD_PATH_TERMINATOR_BYTES.to_vec()],
327 vec![
328 PATH_DIR_SEPARATOR_BYTES.to_vec(),
329 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
330 ],
331 ]
332 }
333
334 #[fixture]
335 fn responding_path_h() -> Vec<Vec<u8>> {
336 vec![b"d".to_vec(), b"e".to_vec(), b"f".to_vec()]
337 }
338
339 #[fixture]
340 fn more_specific_paths_h() -> Vec<Vec<Vec<u8>>> {
341 vec![
342 vec![
343 b"a".to_vec(),
344 b"b".to_vec(),
345 b"c".to_vec(),
346 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
347 ],
348 vec![
349 b"a".to_vec(),
350 b"b".to_vec(),
351 PATH_DIR_SEPARATOR_BYTES.to_vec(),
352 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
353 ],
354 vec![
355 b"a".to_vec(),
356 b"b".to_vec(),
357 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
358 ],
359 vec![
360 b"a".to_vec(),
361 PATH_DIR_SEPARATOR_BYTES.to_vec(),
362 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
363 ],
364 vec![b"a".to_vec(), WILDCARD_PATH_TERMINATOR_BYTES.to_vec()],
365 vec![
366 PATH_DIR_SEPARATOR_BYTES.to_vec(),
367 WILDCARD_PATH_TERMINATOR_BYTES.to_vec(),
368 ],
369 ]
370 }
371}