diff options
author | metamuffin <metamuffin@disroot.org> | 2025-04-01 13:22:33 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-04-01 13:22:45 +0200 |
commit | 06251927c9d598e5ea7655a5b63d2476030f21b0 (patch) | |
tree | 0e210d716e7ffc7cb7c42110ad053df42824040e | |
parent | dd105f82d89070c6929f070a87848b9a9ac8799a (diff) | |
download | gnix-06251927c9d598e5ea7655a5b63d2476030f21b0.tar gnix-06251927c9d598e5ea7655a5b63d2476030f21b0.tar.bz2 gnix-06251927c9d598e5ea7655a5b63d2476030f21b0.tar.zst |
add proper unsatisfied ranges implementation
-rw-r--r-- | src/modules/files.rs | 84 |
1 files changed, 45 insertions, 39 deletions
diff --git a/src/modules/files.rs b/src/modules/files.rs index caee799..ab98f66 100644 --- a/src/modules/files.rs +++ b/src/modules/files.rs @@ -174,7 +174,7 @@ impl Node for Files { // }; let range = request.headers().typed_get::<headers::Range>(); - let range = bytes_range(range, metadata.len())?; + let (range_satisfied, range) = bytes_range(range, metadata.len()); debug!("sending file {path:?}"); let file = File::open(path.clone()).await?; @@ -190,15 +190,24 @@ impl Node for Files { ))) }; - if !skip_body && range.end - range.start != metadata.len() { - *r.status_mut() = StatusCode::PARTIAL_CONTENT; - r.headers_mut().typed_insert( - ContentRange::bytes(range.clone(), metadata.len()).expect("valid ContentRange"), - ); - } - // if not_modified || etag_matches { - if not_modified { + if skip_body { *r.status_mut() = StatusCode::NOT_MODIFIED; + } else { + if range_satisfied { + if range.end - range.start != metadata.len() { + *r.status_mut() = StatusCode::PARTIAL_CONTENT; + r.headers_mut().typed_insert( + ContentRange::bytes(range.clone(), metadata.len()) + .expect("valid ContentRange"), + ); + } else { + *r.status_mut() = StatusCode::OK; + } + } else { + *r.status_mut() = StatusCode::RANGE_NOT_SATISFIABLE; + r.headers_mut() + .typed_insert(ContentRange::unsatisfied_bytes(metadata.len())); + } } r.headers_mut().typed_insert(AcceptRanges::bytes()); @@ -284,46 +293,43 @@ fn file_stream( } // Also adapted from warp -fn bytes_range(range: Option<headers::Range>, max_len: u64) -> Result<Range<u64>, ServiceError> { +// Returns the a valid range and if the range request was satisfied. +fn bytes_range(range: Option<headers::Range>, max_len: u64) -> (bool, Range<u64>) { use std::ops::Bound; let range = if let Some(range) = range { range } else { - return Ok(0..max_len); + return (true, 0..max_len); }; - let ret = range - .satisfiable_ranges(max_len) - .map(|(start, end)| { - let start = match start { - Bound::Unbounded => 0, - Bound::Included(s) => s, - Bound::Excluded(s) => s + 1, - }; + let sat = range.satisfiable_ranges(max_len).find_map(|(start, end)| { + let start = match start { + Bound::Unbounded => 0, + Bound::Included(s) => s, + Bound::Excluded(s) => s + 1, + }; - let end = match end { - Bound::Unbounded => max_len, - Bound::Included(s) => { - // For the special case where s == the file size - if s == max_len { - s - } else { - s + 1 - } + let end = match end { + Bound::Unbounded => max_len, + Bound::Included(s) => { + // For the special case where s == the file size + if s == max_len { + s + } else { + s + 1 } - Bound::Excluded(s) => s, - }; - - if start < end && end <= max_len { - Ok(start..end) - } else { - Err(ServiceError::BadRange) } - }) - .next() - .unwrap_or(Ok(0..max_len)); - ret + Bound::Excluded(s) => s, + }; + + if start < end && end <= max_len { + Some((true, start..end)) + } else { + None + } + }); + sat.unwrap_or((false, 0..max_len)) } fn reserve_at_least(buf: &mut BytesMut, cap: usize) { |