Skip to main content

ehttpd_range/
rangerequest.rs

1//! An extension trait for HTTP requests to work with range requests
2
3use crate::anyrange::AnyInclusiveRange;
4use ehttpd::bytes::Parse;
5use ehttpd::err;
6use ehttpd::error::Error;
7use ehttpd::http::Request;
8
9/// An extension trait for HTTP requests to work with range requests
10pub trait RangeRequest {
11    /// The request `Range` field if any
12    fn range(&self) -> Result<Option<AnyInclusiveRange<u64>>, Error>;
13}
14impl<'a, const HEADER_SIZE_MAX: usize> RangeRequest for Request<'a, HEADER_SIZE_MAX> {
15    fn range(&self) -> Result<Option<AnyInclusiveRange<u64>>, Error> {
16        // Get the range request
17        let Some(range) = self.field("Range") else {
18            return Ok(None);
19        };
20
21        // Parse the range header
22        let range = &mut range.as_ref();
23        let kind = Parse::split_off(range, b"=").ok_or_else(|| err!("Invalid range header field"))?;
24        if !kind.eq(b"bytes") {
25            return Err(err!("Invalid range kind"))?;
26        }
27
28        // Read start and end values
29        let start = Parse::split_off(range, b"-").ok_or_else(|| err!("Invalid range"))?;
30        let end = range;
31
32        // Parse the start and end values
33        let range = match (start.as_ref(), end.as_ref()) {
34            (b"", b"") => AnyInclusiveRange::Full,
35            (start, b"") => AnyInclusiveRange::From { start: start.parse()? },
36            (b"", end) => AnyInclusiveRange::To { end: end.parse()? },
37            (start, end) => AnyInclusiveRange::FromTo { start: start.parse()?, end: end.parse()? },
38        };
39        Ok(Some(range))
40    }
41}