rust 47 lines · 10 steps

Parsing an HTTP Range header in Rust

How to parse a bytes= Range header and read exactly that slice of a file from disk.

Explained by highlit
1use std::fs::File;
2use std::io::{Read, Seek, SeekFrom};
3 
4#[derive(Debug)]
5pub struct RangeSlice {
6 pub start: u64,
7 pub end: u64,
8 pub total: u64,
9 pub bytes: Vec<u8>,
10}
11 
12pub fn read_range(path: &str, header: &str) -> std::io::Result<Option<RangeSlice>> {
13 let mut file = File::open(path)?;
14 let total = file.metadata()?.len();
15 
16 let spec = match header.strip_prefix("bytes=") {
17 Some(s) => s.trim(),
18 None => return Ok(None),
19 };
20 
21 if spec.contains(',') || total == 0 {
22 return Ok(None);
23 }
24 
25 let (start_raw, end_raw) = spec.split_once('-')?;
26 
27 let (start, end) = match (start_raw.trim(), end_raw.trim()) {
28 ("", suffix) => {
29 let len: u64 = suffix.parse().ok()?;
30 let len = len.min(total);
31 (total - len, total - 1)
32 }
33 (s, "") => (s.parse().ok()?, total - 1),
34 (s, e) => (s.parse().ok()?, e.parse::<u64>().ok()?.min(total - 1)),
35 };
36 
37 if start > end || start >= total {
38 return Ok(None);
39 }
40 
41 let len = (end - start + 1) as usize;
42 let mut bytes = vec![0u8; len];
43 file.seek(SeekFrom::Start(start))?;
44 file.read_exact(&mut bytes)?;
45 
46 Ok(Some(RangeSlice { start, end, total, bytes }))
47}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Returning Option inside a Result cleanly separates 'no valid range' from real I/O errors.
  2. 2The ? operator on Option lets malformed input bail out early without verbose match ladders.
  3. 3Suffix and open-ended range forms each need distinct arithmetic against the file's total length.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Parsing an HTTP Range header in Rust — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code