Skip to main content

lfsx_server/
range.rs

1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2pub enum Range {
3    Full,
4    Slice { start: u64, end: u64 },
5    Unsatisfiable,
6}
7
8impl Range {
9    pub fn parse(header: Option<&str>, size: u64) -> Self {
10        let Some(header) = header else {
11            return Self::Full;
12        };
13
14        let Some(spec) = header.trim().strip_prefix("bytes=") else {
15            return Self::Full;
16        };
17
18        if spec.contains(',') {
19            return Self::Full;
20        }
21
22        let Some((first, last)) = spec.trim().split_once('-') else {
23            return Self::Full;
24        };
25
26        match (first.trim(), last.trim()) {
27            ("", suffix) => match suffix.parse::<u64>() {
28                Ok(0) => Self::Unsatisfiable,
29                Ok(length) if size > 0 => Self::Slice {
30                    start: size.saturating_sub(length),
31                    end: size - 1,
32                },
33                Ok(_) => Self::Unsatisfiable,
34                Err(_) => Self::Full,
35            },
36            (start, "") => match start.parse::<u64>() {
37                Ok(start) if start < size => Self::Slice {
38                    start,
39                    end: size - 1,
40                },
41                Ok(_) => Self::Unsatisfiable,
42                Err(_) => Self::Full,
43            },
44            (start, end) => match (start.parse::<u64>(), end.parse::<u64>()) {
45                (Ok(start), Ok(end)) if start < size && start <= end => Self::Slice {
46                    start,
47                    end: end.min(size - 1),
48                },
49                (Ok(_), Ok(_)) => Self::Unsatisfiable,
50                _ => Self::Full,
51            },
52        }
53    }
54
55    pub fn length(&self, size: u64) -> u64 {
56        match self {
57            Self::Slice { start, end } => end - start + 1,
58            _ => size,
59        }
60    }
61}
62
63#[cfg(test)]
64mod tests;