1static PREFIX: &'static [u8] = b"bytes=";
7const PREFIX_LEN: usize = 6;
8
9#[derive(Debug)]
11pub enum HttpRangeParseError {
12 InvalidRange,
14 NoOverlap,
18}
19
20#[derive(Debug, Clone, Copy)]
22pub struct HttpRange {
23 pub start: u64,
24 pub length: u64,
25}
26
27impl HttpRange {
28 pub fn parse(header: &str, size: u64) -> Result<Vec<HttpRange>, HttpRangeParseError> {
33 Self::parse_bytes(header.as_bytes(), size)
34 }
35
36 pub fn parse_bytes(header: &[u8], size: u64) -> Result<Vec<HttpRange>, HttpRangeParseError> {
37 if header.is_empty() {
38 return Ok(Vec::new());
39 }
40
41 if !header.starts_with(PREFIX) {
42 return Err(HttpRangeParseError::InvalidRange);
43 }
44
45 let mut no_overlap = false;
46
47 let ranges: Vec<HttpRange> = header[PREFIX_LEN..]
48 .split(|b| *b == b',')
49 .filter_map(|ra| {
50 let ra = ra.trim();
51 if ra.is_empty() {
52 return None;
53 }
54 match Self::parse_single_range(ra, size) {
55 Ok(Some(range)) => Some(Ok(range)),
56 Ok(None) => {
57 no_overlap = true;
58 None
59 }
60 Err(e) => Some(Err(e)),
61 }
62 })
63 .collect::<Result<_, _>>()?;
64
65 if no_overlap && ranges.is_empty() {
66 return Err(HttpRangeParseError::NoOverlap);
67 }
68
69 Ok(ranges)
70 }
71
72 fn parse_single_range(
73 bytes: &[u8],
74 size: u64,
75 ) -> Result<Option<HttpRange>, HttpRangeParseError> {
76 let mut start_end_iter = bytes.splitn(2, |b| *b == b'-');
77
78 let start_str = start_end_iter
79 .next()
80 .ok_or(HttpRangeParseError::InvalidRange)?
81 .trim();
82 let end_str = start_end_iter
83 .next()
84 .ok_or(HttpRangeParseError::InvalidRange)?
85 .trim();
86
87 if start_str.is_empty() {
88 if end_str.is_empty() || end_str[0] == b'-' {
94 return Err(HttpRangeParseError::InvalidRange);
95 }
96
97 let mut length: u64 = end_str
98 .parse_u64()
99 .map_err(|_| HttpRangeParseError::InvalidRange)?;
100
101 if length == 0 {
102 return Ok(None);
103 }
104
105 if length > size {
106 length = size;
107 }
108
109 Ok(Some(HttpRange {
110 start: (size - length),
111 length,
112 }))
113 } else {
114 let start: u64 = start_str
115 .parse_u64()
116 .map_err(|_| HttpRangeParseError::InvalidRange)?;
117
118 if start >= size {
119 return Ok(None);
120 }
121
122 let length = if end_str.is_empty() {
123 size - start
125 } else {
126 let mut end: u64 = end_str
127 .parse_u64()
128 .map_err(|_| HttpRangeParseError::InvalidRange)?;
129
130 if start > end {
131 return Err(HttpRangeParseError::InvalidRange);
132 }
133
134 if end >= size {
135 end = size - 1;
136 }
137
138 end - start + 1
139 };
140
141 Ok(Some(HttpRange { start, length }))
142 }
143 }
144}
145
146trait SliceExt {
147 fn trim(&self) -> &Self;
148 fn parse_u64(&self) -> Result<u64, ()>;
149}
150
151impl SliceExt for [u8] {
152 fn trim(&self) -> &[u8] {
153 fn is_whitespace(c: &u8) -> bool {
154 *c == b'\t' || *c == b' '
155 }
156
157 fn is_not_whitespace(c: &u8) -> bool {
158 !is_whitespace(c)
159 }
160
161 if let Some(first) = self.iter().position(is_not_whitespace) {
162 if let Some(last) = self.iter().rposition(is_not_whitespace) {
163 &self[first..last + 1]
164 } else {
165 unreachable!();
166 }
167 } else {
168 &[]
169 }
170 }
171
172 fn parse_u64(&self) -> Result<u64, ()> {
173 if self.is_empty() {
174 return Err(());
175 }
176 let mut res = 0u64;
177 for b in self {
178 if *b >= b'0' && *b <= b'9' {
179 res = res
180 .checked_mul(10)
181 .ok_or(())?
182 .checked_add((b - b'0') as u64)
183 .ok_or(())?;
184 } else {
185 return Err(());
186 }
187 }
188
189 Ok(res)
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 struct T(&'static str, u64, Vec<HttpRange>);
198
199 #[test]
200 fn test_parse() {
201 let tests = vec![
202 T("", 0, vec![]),
203 T("", 1000, vec![]),
204 T("foo", 0, vec![]),
205 T("bytes=", 0, vec![]),
206 T("bytes=", 200, vec![]),
207 T("bytes=7", 10, vec![]),
208 T("bytes= 7 ", 10, vec![]),
209 T("bytes=1-", 0, vec![]),
210 T("bytes=5-4", 10, vec![]),
211 T("bytes=--6", 200, vec![]),
212 T("bytes=--0", 200, vec![]),
213 T("bytes=---0", 200, vec![]),
214 T(
215 "bytes=-6",
216 200,
217 vec![HttpRange {
218 start: 194,
219 length: 6,
220 }],
221 ),
222 T(
223 "bytes=6-",
224 200,
225 vec![HttpRange {
226 start: 6,
227 length: 194,
228 }],
229 ),
230 T("bytes=-6-", 0, vec![]),
231 T("bytes=-0", 200, vec![]),
232 T("bytes=0-2,5-4", 10, vec![]),
233 T("bytes=2-5,4-3", 10, vec![]),
234 T("bytes=--5,4--3", 10, vec![]),
235 T("bytes=A-", 10, vec![]),
236 T("bytes=A- ", 10, vec![]),
237 T("bytes=A-Z", 10, vec![]),
238 T("bytes= -Z", 10, vec![]),
239 T("bytes=5-Z", 10, vec![]),
240 T("bytes=Ran-dom, garbage", 10, vec![]),
241 T("bytes=0x01-0x02", 10, vec![]),
242 T("bytes= ", 10, vec![]),
243 T("bytes= , , , ", 10, vec![]),
244 T(
245 "bytes=0-9",
246 10,
247 vec![HttpRange {
248 start: 0,
249 length: 10,
250 }],
251 ),
252 T(
253 "bytes=0-",
254 10,
255 vec![HttpRange {
256 start: 0,
257 length: 10,
258 }],
259 ),
260 T(
261 "bytes=5-",
262 10,
263 vec![HttpRange {
264 start: 5,
265 length: 5,
266 }],
267 ),
268 T(
269 "bytes=0-20",
270 10,
271 vec![HttpRange {
272 start: 0,
273 length: 10,
274 }],
275 ),
276 T(
277 "bytes=15-,0-5",
278 10,
279 vec![HttpRange {
280 start: 0,
281 length: 6,
282 }],
283 ),
284 T(
285 "bytes=1-2,5-",
286 10,
287 vec![
288 HttpRange {
289 start: 1,
290 length: 2,
291 },
292 HttpRange {
293 start: 5,
294 length: 5,
295 },
296 ],
297 ),
298 T(
299 "bytes=-2 , 7-",
300 11,
301 vec![
302 HttpRange {
303 start: 9,
304 length: 2,
305 },
306 HttpRange {
307 start: 7,
308 length: 4,
309 },
310 ],
311 ),
312 T(
313 "bytes=0-0 ,2-2, 7-",
314 11,
315 vec![
316 HttpRange {
317 start: 0,
318 length: 1,
319 },
320 HttpRange {
321 start: 2,
322 length: 1,
323 },
324 HttpRange {
325 start: 7,
326 length: 4,
327 },
328 ],
329 ),
330 T(
331 "bytes=-5",
332 10,
333 vec![HttpRange {
334 start: 5,
335 length: 5,
336 }],
337 ),
338 T(
339 "bytes=-15",
340 10,
341 vec![HttpRange {
342 start: 0,
343 length: 10,
344 }],
345 ),
346 T(
347 "bytes=0-499",
348 10000,
349 vec![HttpRange {
350 start: 0,
351 length: 500,
352 }],
353 ),
354 T(
355 "bytes=500-999",
356 10000,
357 vec![HttpRange {
358 start: 500,
359 length: 500,
360 }],
361 ),
362 T(
363 "bytes=-500",
364 10000,
365 vec![HttpRange {
366 start: 9500,
367 length: 500,
368 }],
369 ),
370 T(
371 "bytes=9500-",
372 10000,
373 vec![HttpRange {
374 start: 9500,
375 length: 500,
376 }],
377 ),
378 T(
379 "bytes=0-0,-1",
380 10000,
381 vec![
382 HttpRange {
383 start: 0,
384 length: 1,
385 },
386 HttpRange {
387 start: 9999,
388 length: 1,
389 },
390 ],
391 ),
392 T(
393 "bytes=500-600,601-999",
394 10000,
395 vec![
396 HttpRange {
397 start: 500,
398 length: 101,
399 },
400 HttpRange {
401 start: 601,
402 length: 399,
403 },
404 ],
405 ),
406 T(
407 "bytes=500-700,601-999",
408 10000,
409 vec![
410 HttpRange {
411 start: 500,
412 length: 201,
413 },
414 HttpRange {
415 start: 601,
416 length: 399,
417 },
418 ],
419 ),
420 T(
422 "bytes= 1 -2 , 4- 5, 7 - 8 , ,,",
423 11,
424 vec![
425 HttpRange {
426 start: 1,
427 length: 2,
428 },
429 HttpRange {
430 start: 4,
431 length: 2,
432 },
433 HttpRange {
434 start: 7,
435 length: 2,
436 },
437 ],
438 ),
439 T(
440 "bytes=50-60,2-3",
441 10,
442 vec![HttpRange {
443 start: 2,
444 length: 2,
445 }],
446 ),
447 T(
448 "bytes=50-60,-5",
449 10,
450 vec![HttpRange {
451 start: 5,
452 length: 5,
453 }],
454 ),
455 T(
456 "bytes=50-60,7-",
457 10,
458 vec![HttpRange {
459 start: 7,
460 length: 3,
461 }],
462 ),
463 T("bytes=50-60,20-", 10, vec![]),
464 T(
465 "bytes=50-60,20-,3-4",
466 10,
467 vec![HttpRange {
468 start: 3,
469 length: 2,
470 }],
471 ),
472 T(
473 "bytes=9-20,-5",
474 10,
475 vec![
476 HttpRange {
477 start: 9,
478 length: 1,
479 },
480 HttpRange {
481 start: 5,
482 length: 5,
483 },
484 ],
485 ),
486 T("bytes=15-20,-0", 10, vec![]),
487 T(
488 "bytes=15-20,-0",
489 20,
490 vec![HttpRange {
491 start: 15,
492 length: 5,
493 }],
494 ),
495 T("bytes=1-2,bytes=3-4", 10, vec![]),
496 T("bytes=1-2,blergh=3-4", 10, vec![]),
497 T("blergh=1-2,bytes=3-4", 10, vec![]),
498 T("bytes=-0", 0, vec![]),
499 T("bytes=-0", 5, vec![]),
500 T(
501 "bytes=-1",
502 0,
503 vec![HttpRange {
504 start: 0,
505 length: 0,
506 }],
507 ),
508 T(
509 "bytes=0-99999999999999999999999999999999999999999999",
510 10,
511 vec![],
512 ),
513 ];
514
515 for t in tests {
516 let header = t.0;
517 let size = t.1;
518 let expected = t.2;
519
520 let res = HttpRange::parse(header, size);
521
522 if res.is_err() {
523 if expected.is_empty() {
524 continue;
525 } else {
526 assert!(
527 false,
528 "parse({}, {}) returned error {:?}",
529 header,
530 size,
531 res.unwrap_err()
532 );
533 }
534 }
535
536 let got = res.unwrap();
537
538 if got.len() != expected.len() {
539 assert!(
540 false,
541 "len(parseRange({}, {})) = {}, want {}",
542 header,
543 size,
544 got.len(),
545 expected.len()
546 );
547 continue;
548 }
549
550 for i in 0..expected.len() {
551 if got[i].start != expected[i].start {
552 assert!(
553 false,
554 "parseRange({}, {})[{}].start = {}, want {}",
555 header, size, i, got[i].start, expected[i].start
556 )
557 }
558 if got[i].length != expected[i].length {
559 assert!(
560 false,
561 "parseRange({}, {})[{}].length = {}, want {}",
562 header, size, i, got[i].length, expected[i].length
563 )
564 }
565 }
566 }
567 }
568}