fix: content-range (#216)

This commit is contained in:
weisd
2025-07-15 17:23:33 +08:00
committed by GitHub
parent a9d77a618f
commit 4c1fc9317e
5 changed files with 30 additions and 14 deletions
+4 -3
View File
@@ -43,15 +43,16 @@ pub async fn create_bitrot_reader(
) -> disk::error::Result<Option<BitrotReader<Box<dyn AsyncRead + Send + Sync + Unpin>>>> { ) -> disk::error::Result<Option<BitrotReader<Box<dyn AsyncRead + Send + Sync + Unpin>>>> {
// Calculate the total length to read, including the checksum overhead // Calculate the total length to read, including the checksum overhead
let length = length.div_ceil(shard_size) * checksum_algo.size() + length; let length = length.div_ceil(shard_size) * checksum_algo.size() + length;
let offset = offset.div_ceil(shard_size) * checksum_algo.size() + offset;
if let Some(data) = inline_data { if let Some(data) = inline_data {
// Use inline data // Use inline data
let rd = Cursor::new(data.to_vec()); let mut rd = Cursor::new(data.to_vec());
rd.set_position(offset as u64);
let reader = BitrotReader::new(Box::new(rd) as Box<dyn AsyncRead + Send + Sync + Unpin>, shard_size, checksum_algo); let reader = BitrotReader::new(Box::new(rd) as Box<dyn AsyncRead + Send + Sync + Unpin>, shard_size, checksum_algo);
Ok(Some(reader)) Ok(Some(reader))
} else if let Some(disk) = disk { } else if let Some(disk) = disk {
// Read from disk // Read from disk
match disk.read_file_stream(bucket, path, offset, length).await { match disk.read_file_stream(bucket, path, offset, length - offset).await {
Ok(rd) => { Ok(rd) => {
let reader = BitrotReader::new(rd, shard_size, checksum_algo); let reader = BitrotReader::new(rd, shard_size, checksum_algo);
Ok(Some(reader)) Ok(Some(reader))
-5
View File
@@ -1611,11 +1611,6 @@ impl DiskAPI for LocalDisk {
#[tracing::instrument(level = "debug", skip(self))] #[tracing::instrument(level = "debug", skip(self))]
async fn read_file_stream(&self, volume: &str, path: &str, offset: usize, length: usize) -> Result<FileReader> { async fn read_file_stream(&self, volume: &str, path: &str, offset: usize, length: usize) -> Result<FileReader> {
// warn!(
// "disk read_file_stream: volume: {}, path: {}, offset: {}, length: {}",
// volume, path, offset, length
// );
let volume_dir = self.get_bucket_path(volume)?; let volume_dir = self.get_bucket_path(volume)?;
if !skip_access_checks(volume) { if !skip_access_checks(volume) {
access(&volume_dir) access(&volume_dir)
+3 -1
View File
@@ -2123,6 +2123,8 @@ impl SetDisks {
let till_offset = erasure.shard_file_offset(part_offset, part_length, part_size); let till_offset = erasure.shard_file_offset(part_offset, part_length, part_size);
let read_offset = (part_offset / erasure.block_size) * erasure.shard_size();
let mut readers = Vec::with_capacity(disks.len()); let mut readers = Vec::with_capacity(disks.len());
let mut errors = Vec::with_capacity(disks.len()); let mut errors = Vec::with_capacity(disks.len());
for (idx, disk_op) in disks.iter().enumerate() { for (idx, disk_op) in disks.iter().enumerate() {
@@ -2131,7 +2133,7 @@ impl SetDisks {
disk_op.as_ref(), disk_op.as_ref(),
bucket, bucket,
&format!("{}/{}/part.{}", object, files[idx].data_dir.unwrap_or_default(), part_number), &format!("{}/{}/part.{}", object, files[idx].data_dir.unwrap_or_default(), part_number),
part_offset, read_offset,
till_offset, till_offset,
erasure.shard_size(), erasure.shard_size(),
HashAlgorithm::HighwayHash256, HashAlgorithm::HighwayHash256,
+1 -1
View File
@@ -201,7 +201,7 @@ impl GetObjectReader {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct HTTPRangeSpec { pub struct HTTPRangeSpec {
pub is_suffix_length: bool, pub is_suffix_length: bool,
pub start: i64, pub start: i64,
+22 -4
View File
@@ -770,18 +770,18 @@ impl S3 for FS {
}; };
let reader = store let reader = store
.get_object_reader(bucket.as_str(), key.as_str(), rs, h, &opts) .get_object_reader(bucket.as_str(), key.as_str(), rs.clone(), h, &opts)
.await .await
.map_err(ApiError::from)?; .map_err(ApiError::from)?;
let info = reader.object_info; let info = reader.object_info;
let event_info = info.clone(); let event_info = info.clone();
let content_type = { let content_type = {
if let Some(content_type) = info.content_type { if let Some(content_type) = &info.content_type {
match ContentType::from_str(&content_type) { match ContentType::from_str(content_type) {
Ok(res) => Some(res), Ok(res) => Some(res),
Err(err) => { Err(err) => {
error!("parse content-type err {} {:?}", &content_type, err); error!("parse content-type err {} {:?}", content_type, err);
// //
None None
} }
@@ -797,11 +797,29 @@ impl S3 for FS {
info.size as usize, info.size as usize,
))); )));
let mut rs = rs;
if let Some(part_number) = part_number {
if rs.is_none() {
rs = HTTPRangeSpec::from_object_info(&info, part_number);
}
}
let content_range = if let Some(rs) = rs {
let total_size = info.get_actual_size().map_err(ApiError::from)?;
let (start, length) = rs.get_offset_length(total_size as i64).map_err(ApiError::from)?;
Some(format!("bytes {}-{}/{}", start, start as i64 + length - 1, total_size))
} else {
None
};
let output = GetObjectOutput { let output = GetObjectOutput {
body, body,
content_length: Some(info.size as i64), content_length: Some(info.size as i64),
last_modified, last_modified,
content_type, content_type,
accept_ranges: Some("bytes".to_string()),
content_range,
..Default::default() ..Default::default()
}; };