objectstore_server/extractors/
byte_range.rs1use axum::extract::FromRequestParts;
4use http::request::Parts;
5use objectstore_types::range::{ByteRange, RangeError};
6
7use crate::{endpoints::common::ApiError, state::ServiceState};
8
9#[derive(Debug, Clone)]
11pub struct OptionalByteRange(pub Option<ByteRange>);
12
13impl FromRequestParts<ServiceState> for OptionalByteRange {
14 type Rejection = ApiError;
15
16 async fn from_request_parts(
17 parts: &mut Parts,
18 _state: &ServiceState,
19 ) -> Result<Self, Self::Rejection> {
20 let headers = &parts.headers;
21 let Some(range) = headers.get(http::header::RANGE) else {
22 return Ok(Self(None));
23 };
24 let range = range
25 .to_str()
26 .map_err(|_| ApiError::Client("invalid Range header".into()))?;
27
28 match range.parse::<ByteRange>() {
29 Ok(range) => Ok(Self(Some(range))),
30 Err(RangeError::MultiRange) => {
38 objectstore_log::warn!(
39 "received range request with multiple range specifiers, ignoring"
40 );
41 Ok(Self(None))
42 }
43 Err(err) => Err(ApiError::Client(format!("invalid Range header: {err}"))),
47 }
48 }
49}