1#[derive(Debug, Clone, Copy)]
5pub struct HttpRange {
6 pub start: u64,
8 pub length: u64,
10}
11
12static PREFIX: &'static str = "bytes=";
13const PREFIX_LEN: usize = 6;
14
15impl HttpRange {
16 pub fn parse(header: &str, size: u64) -> Result<Vec<Self>, ()> {
21 if header.is_empty() {
22 return Ok(Vec::new());
23 }
24 if !header.starts_with(PREFIX) {
25 return Err(());
26 }
27
28 let size_sig = size as i64;
29 let mut no_overlap = false;
30
31 let mut ranges = Vec::new();
32
33 for ra in header[PREFIX_LEN..].split(',').map(|x| x.trim()).filter(|x| !x.is_empty()) {
34 let mut start_end_iter = ra.split('-');
35
36 let start_str = start_end_iter.next().ok_or(())?.trim();
37 let end_str = start_end_iter.next().ok_or(())?.trim();
38
39 if start_str.is_empty() {
40 let mut length: i64 = end_str.parse().map_err(|_| ())?;
43
44 if length > size_sig {
45 length = size_sig;
46 }
47
48 ranges.push(Self {
49 start: (size_sig - length) as u64,
50 length: length as u64,
51 })
52 } else {
53 let start: i64 = start_str.parse().map_err(|_| ())?;
54
55 if start < 0 {
56 return Err(());
57 }
58 if start >= size_sig {
59 no_overlap = true;
60 continue;
61 }
62
63 let length = if end_str.is_empty() {
64 size_sig - start
66 } else {
67 let mut end: i64 = end_str.parse().map_err(|_| ())?;
68
69 if start > end {
70 return Err(());
71 }
72
73 if end >= size_sig {
74 end = size_sig - 1;
75 }
76
77 end - start + 1
78 };
79
80 ranges.push(Self {
81 start: start as u64,
82 length: length as u64,
83 });
84 }
85 }
86
87 if no_overlap && ranges.is_empty() {
88 return Err(());
89 }
90
91 Ok(ranges)
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 struct T(&'static str, u64, Vec<HttpRange>);
100
101 #[test]
102 fn verify_parser() {
103 let tests = vec![
104 T("", 0, vec![]),
105 T("", 1000, vec![]),
106 T("foo", 0, vec![]),
107 T("bytes=", 0, vec![]),
108 T("bytes=7", 10, vec![]),
109 T("bytes= 7 ", 10, vec![]),
110 T("bytes=1-", 0, vec![]),
111 T("bytes=5-4", 10, vec![]),
112 T("bytes=0-2,5-4", 10, vec![]),
113 T("bytes=2-5,4-3", 10, vec![]),
114 T("bytes=--5,4--3", 10, vec![]),
115 T("bytes=A-", 10, vec![]),
116 T("bytes=A- ", 10, vec![]),
117 T("bytes=A-Z", 10, vec![]),
118 T("bytes= -Z", 10, vec![]),
119 T("bytes=5-Z", 10, vec![]),
120 T("bytes=Ran-dom, garbage", 10, vec![]),
121 T("bytes=0x01-0x02", 10, vec![]),
122 T("bytes= ", 10, vec![]),
123 T("bytes= , , , ", 10, vec![]),
124 T(
125 "bytes=0-9",
126 10,
127 vec![HttpRange {
128 start: 0,
129 length: 10,
130 }],
131 ),
132 T(
133 "bytes=0-",
134 10,
135 vec![HttpRange {
136 start: 0,
137 length: 10,
138 }],
139 ),
140 T(
141 "bytes=5-",
142 10,
143 vec![HttpRange {
144 start: 5,
145 length: 5,
146 }],
147 ),
148 T(
149 "bytes=0-20",
150 10,
151 vec![HttpRange {
152 start: 0,
153 length: 10,
154 }],
155 ),
156 T(
157 "bytes=15-,0-5",
158 10,
159 vec![HttpRange {
160 start: 0,
161 length: 6,
162 }],
163 ),
164 T(
165 "bytes=1-2,5-",
166 10,
167 vec![
168 HttpRange {
169 start: 1,
170 length: 2,
171 },
172 HttpRange {
173 start: 5,
174 length: 5,
175 },
176 ],
177 ),
178 T(
179 "bytes=-2 , 7-",
180 11,
181 vec![
182 HttpRange {
183 start: 9,
184 length: 2,
185 },
186 HttpRange {
187 start: 7,
188 length: 4,
189 },
190 ],
191 ),
192 T(
193 "bytes=0-0 ,2-2, 7-",
194 11,
195 vec![
196 HttpRange {
197 start: 0,
198 length: 1,
199 },
200 HttpRange {
201 start: 2,
202 length: 1,
203 },
204 HttpRange {
205 start: 7,
206 length: 4,
207 },
208 ],
209 ),
210 T(
211 "bytes=-5",
212 10,
213 vec![HttpRange {
214 start: 5,
215 length: 5,
216 }],
217 ),
218 T(
219 "bytes=-15",
220 10,
221 vec![HttpRange {
222 start: 0,
223 length: 10,
224 }],
225 ),
226 T(
227 "bytes=0-499",
228 10000,
229 vec![HttpRange {
230 start: 0,
231 length: 500,
232 }],
233 ),
234 T(
235 "bytes=500-999",
236 10000,
237 vec![HttpRange {
238 start: 500,
239 length: 500,
240 }],
241 ),
242 T(
243 "bytes=-500",
244 10000,
245 vec![HttpRange {
246 start: 9500,
247 length: 500,
248 }],
249 ),
250 T(
251 "bytes=9500-",
252 10000,
253 vec![HttpRange {
254 start: 9500,
255 length: 500,
256 }],
257 ),
258 T(
259 "bytes=0-0,-1",
260 10000,
261 vec![
262 HttpRange {
263 start: 0,
264 length: 1,
265 },
266 HttpRange {
267 start: 9999,
268 length: 1,
269 },
270 ],
271 ),
272 T(
273 "bytes=500-600,601-999",
274 10000,
275 vec![
276 HttpRange {
277 start: 500,
278 length: 101,
279 },
280 HttpRange {
281 start: 601,
282 length: 399,
283 },
284 ],
285 ),
286 T(
287 "bytes=500-700,601-999",
288 10000,
289 vec![
290 HttpRange {
291 start: 500,
292 length: 201,
293 },
294 HttpRange {
295 start: 601,
296 length: 399,
297 },
298 ],
299 ),
300 T(
302 "bytes= 1 -2 , 4- 5, 7 - 8 , ,,",
303 11,
304 vec![
305 HttpRange {
306 start: 1,
307 length: 2,
308 },
309 HttpRange {
310 start: 4,
311 length: 2,
312 },
313 HttpRange {
314 start: 7,
315 length: 2,
316 },
317 ],
318 ),
319 ];
320
321 for t in tests {
322 let header = t.0;
323 let size = t.1;
324 let expected = t.2;
325
326 let res = HttpRange::parse(header, size);
327
328 if res.is_err() {
329 if expected.is_empty() {
330 continue;
331 } else {
332 assert!(
333 false,
334 "parse({}, {}) returned error {:?}",
335 header,
336 size,
337 res.unwrap_err()
338 );
339 }
340 }
341
342 let got = res.unwrap();
343
344 if got.len() != expected.len() {
345 assert!(
346 false,
347 "len(parseRange({}, {})) = {}, want {}",
348 header,
349 size,
350 got.len(),
351 expected.len()
352 );
353 continue;
354 }
355
356 for i in 0..expected.len() {
357 if got[i].start != expected[i].start {
358 assert!(
359 false,
360 "parseRange({}, {})[{}].start = {}, want {}",
361 header, size, i, got[i].start, expected[i].start
362 )
363 }
364 if got[i].length != expected[i].length {
365 assert!(
366 false,
367 "parseRange({}, {})[{}].length = {}, want {}",
368 header, size, i, got[i].length, expected[i].length
369 )
370 }
371 }
372 }
373 }
374}