syncweb-core 0.1.1-alpha.4

delay-tolerant web surfing
Documentation
use axum::http::HeaderMap;

#[derive(Debug, Clone, Copy)]
pub struct ByteRange {
    pub start: u64,
    pub end: u64,
}

pub fn parse_range_header(headers: &HeaderMap, total_size: u64) -> Option<ByteRange> {
    let header_value = headers.get(axum::http::header::RANGE)?.to_str().ok()?;

    let remainder = header_value.strip_prefix("bytes=")?;

    let (start_str, end_str) = remainder.split_once('-')?;

    let start: u64 = start_str.parse().ok()?;

    let end: u64 = if end_str.is_empty() {
        total_size.saturating_sub(1)
    } else {
        end_str.parse().ok()?
    };

    if start > end || start >= total_size {
        return None;
    }

    Some(ByteRange {
        start,
        end: end.min(total_size.saturating_sub(1)),
    })
}

pub fn content_range(start: u64, end: u64, total_size: u64) -> String {
    format!("bytes {start}-{end}/{total_size}")
}

#[cfg(test)]
mod tests {
    use super::*;

    fn headers_with_range(range: &str) -> HeaderMap {
        let mut h = HeaderMap::new();
        h.insert(axum::http::header::RANGE, range.parse().unwrap());
        h
    }

    #[test]
    fn test_simple_range() {
        let h = headers_with_range("bytes=0-1023");
        let r = parse_range_header(&h, 5000);
        assert!(r.is_some());
        let r_val = r.unwrap();
        assert_eq!(r_val.start, 0);
        assert_eq!(r_val.end, 1023);
    }

    #[test]
    fn test_open_ended_range() {
        let h = headers_with_range("bytes=2000-");
        let r = parse_range_header(&h, 5000);
        assert!(r.is_some());
        let r_val = r.unwrap();
        assert_eq!(r_val.start, 2000);
        assert_eq!(r_val.end, 4999);
    }

    #[test]
    fn test_no_range_header() {
        let h = HeaderMap::new();
        assert!(parse_range_header(&h, 1000).is_none());
    }

    #[test]
    fn test_malformed_header() {
        let h = headers_with_range("not-bytes=0-100");
        assert!(parse_range_header(&h, 1000).is_none());
    }

    #[test]
    fn test_content_range_format() {
        assert_eq!(content_range(0, 1023, 5000), "bytes 0-1023/5000");
    }
}