#[derive(Debug, Clone, Copy)]
pub struct ByteRange {
pub start: u64,
pub end: u64, // inclusive
}
#[derive(Debug)]
pub enum RangeError {
Unsatisfiable,
}
impl ByteRange {
pub fn content_length(&self) -> u64 {
self.end - self.start + 1
}
pub fn parse(header: &str, file_len: u64) -> Option<Result<ByteRange, RangeError>> {
let spec = header.strip_prefix("bytes=")?;
if spec.contains(',') {
return None; // multi-range not supported
}
let (raw_start, raw_end) = spec.split_once('-')?;
let (start, end) = match (raw_start.trim(), raw_end.trim()) {
("", suffix) => {
let n: u64 = suffix.parse().ok()?;
if n == 0 {
return Some(Err(RangeError::Unsatisfiable));
}
let n = n.min(file_len);
(file_len - n, file_len - 1)
}
(start, "") => {
let s: u64 = start.parse().ok()?;
(s, file_len - 1)
}
(start, end) => {
let s: u64 = start.parse().ok()?;
let e: u64 = end.parse().ok()?;
(s, e.min(file_len - 1))
}
};
if file_len == 0 || start >= file_len || start > end {
return Some(Err(RangeError::Unsatisfiable));
}
Some(Ok(ByteRange { start, end }))
}
}
use axum::body::Body;
use axum::extract::Path;
use axum::http::{header, HeaderMap, StatusCode};
use axum::response::{IntoResponse, Response};
use tokio::fs::File;
use tokio::io::AsyncSeekExt;
use tokio_util::io::ReaderStream;
use crate::range::{ByteRange, RangeError};
pub async fn serve_file(Path(name): Path<String>, headers: HeaderMap) -> Response {
let path = format!("./media/{name}");
let mut file = match File::open(&path).await {
Ok(f) => f,
Err(_) => return StatusCode::NOT_FOUND.into_response(),
};
let total = match file.metadata().await {
Ok(m) => m.len(),
Err(_) => return StatusCode::INTERNAL_SERVER_ERROR.into_response(),
};
let range = headers
.get(header::RANGE)
.and_then(|v| v.to_str().ok())
.and_then(|h| ByteRange::parse(h, total));
match range {
Some(Ok(r)) => {
if file.seek(std::io::SeekFrom::Start(r.start)).await.is_err() {
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
}
let len = r.content_length();
let stream = ReaderStream::new(file.take(len));
Response::builder()
.status(StatusCode::PARTIAL_CONTENT)
.header(header::ACCEPT_RANGES, "bytes")
.header(header::CONTENT_LENGTH, len)
.header(
header::CONTENT_RANGE,
format!("bytes {}-{}/{}", r.start, r.end, total),
)
.body(Body::from_stream(stream))
.unwrap()
}
Some(Err(RangeError::Unsatisfiable)) => Response::builder()
.status(StatusCode::RANGE_NOT_SATISFIABLE)
.header(header::CONTENT_RANGE, format!("bytes */{total}"))
.body(Body::empty())
.unwrap(),
None => {
let stream = ReaderStream::new(file);
Response::builder()
.status(StatusCode::OK)
.header(header::ACCEPT_RANGES, "bytes")
.header(header::CONTENT_LENGTH, total)
.body(Body::from_stream(stream))
.unwrap()
}
}
}
mod handler;
mod range;
use axum::{routing::get, Router};
use handler::serve_file;
#[tokio::main]
async fn main() {
let app = Router::new().route("/media/{name}", get(serve_file));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
.await
.expect("bind");
println!("serving media on http://0.0.0.0:3000");
axum::serve(listener, app).await.expect("server");
}
HTTP range requests let clients ask for a byte slice of a resource instead of the whole thing, which is what makes video seeking and resumable downloads work. A server signals support with Accept-Ranges: bytes, and when a request carries a Range header it responds with 206 Partial Content, a Content-Range header, and only the requested bytes. This snippet implements that flow in an Axum handler backed by Tokio file IO.
The range parser tab isolates the fiddly part: turning a header like bytes=200-1023 into a concrete (start, end) pair against a known file length. ByteRange::parse handles the three real shapes the spec allows — start-end, an open-ended start- that runs to the last byte, and a suffix -N meaning the final N bytes. It rejects multi-range requests (the comma case) and syntactically broken input by returning None, which the caller treats as "ignore the header and serve the whole file". Crucially it also validates bounds: if start is past the end of the file the range is unsatisfiable, modeled as a distinct RangeError::Unsatisfiable so the handler can answer with 416.
The file handler tab wires this into Axum. serve_file first stats the file to learn its length, then branches on whether a Range header is present. With no header it returns a normal 200 and the full body. With a valid range it seeks the File to start, wraps a tokio::io::Take so only len bytes are read, and streams that through ReaderStream into a Body — so large files are never buffered in memory. The response sets Content-Range, Content-Length, and the 206 status. An Unsatisfiable range short-circuits to a 416 carrying a Content-Range: bytes */total header, exactly as the spec requires.
The router tab shows the trivial mounting of the route. The design keeps parsing pure and testable while confining IO and header assembly to the handler. A common pitfall it avoids is off-by-one errors: HTTP ranges are inclusive, so the number of bytes to read is end - start + 1, which ByteRange::content_length centralizes. Streaming rather than reading-to-Vec is the other key choice, making the handler safe for gigabyte media files.
Related snips
export interface RetryOptions {
retries: number;
baseMs: number;
maxMs: number;
signal?: AbortSignal;
onRetry?: (attempt: number, delay: number, err: unknown) => void;
Exponential backoff with jitter for retries
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
// Creating a Promise
const myPromise = new Promise((resolve, reject) => {
const success = true;
setTimeout(() => {
if (success) {
Promises and async/await patterns for asynchronous JavaScript
export type Settled<R> =
| { status: 'fulfilled'; value: R }
| { status: 'rejected'; reason: unknown };
export interface ConcurrencyOptions {
limit: number;
Simple concurrency limiter for batch operations
package deps
import (
"net"
"net/http"
"time"
HTTP client tuned for production: timeouts, transport, and connection reuse
package api
import (
"io"
"net/http"
"os"
Safe multipart uploads using temp files (bounded memory)
Share this code
Here's the card — post it anywhere.