Browse Source

Match Go error behavior for truncated needle data in read_body_v2

Go's readNeedleDataVersion2 returns "index out of range %d" errors
(indices 1-7) when needle body or metadata fields are truncated.
Rust was silently tolerating truncation and returning Ok. Now returns
NeedleError::IndexOutOfRange with the matching index for each field.
rust-volume-server
Chris Lu 3 days ago
parent
commit
8fa6f7642b
  1. 22
      seaweed-volume/src/storage/needle/needle.rs

22
seaweed-volume/src/storage/needle/needle.rs

@ -281,7 +281,7 @@ impl Needle {
}
/// Read the version 2/3 body data from bytes (size bytes starting after header).
/// Tolerates EOF/truncated data (matching Go's readNeedleDataVersion2 which tolerates io.EOF).
/// Returns IndexOutOfRange errors for truncated data (matching Go's readNeedleDataVersion2).
pub fn read_body_v2(&mut self, bytes: &[u8]) -> Result<(), NeedleError> {
let len_bytes = bytes.len();
let mut index = 0;
@ -300,20 +300,18 @@ impl Needle {
// Data
if index + self.data_size as usize > len_bytes {
// Tolerate truncated data: read what we can
self.data = bytes[index..].to_vec();
return Ok(());
return Err(NeedleError::IndexOutOfRange(1));
}
self.data = bytes[index..index + self.data_size as usize].to_vec();
index += self.data_size as usize;
// Read non-data metadata (also tolerates EOF)
// Read non-data metadata
self.read_body_v2_non_data(&bytes[index..])?;
Ok(())
}
/// Read version 2/3 metadata fields (everything after Data).
/// Tolerates truncated data (matching Go's readNeedleDataVersion2 EOF tolerance).
/// Returns IndexOutOfRange errors for truncated data (matching Go's readNeedleDataVersion2).
fn read_body_v2_non_data(&mut self, bytes: &[u8]) -> Result<usize, NeedleError> {
let len_bytes = bytes.len();
let mut index = 0;
@ -331,7 +329,7 @@ impl Needle {
self.name_size = bytes[index];
index += 1;
if index + self.name_size as usize > len_bytes {
return Ok(index); // tolerate EOF
return Err(NeedleError::IndexOutOfRange(2));
}
self.name = bytes[index..index + self.name_size as usize].to_vec();
index += self.name_size as usize;
@ -342,7 +340,7 @@ impl Needle {
self.mime_size = bytes[index];
index += 1;
if index + self.mime_size as usize > len_bytes {
return Ok(index); // tolerate EOF
return Err(NeedleError::IndexOutOfRange(3));
}
self.mime = bytes[index..index + self.mime_size as usize].to_vec();
index += self.mime_size as usize;
@ -351,7 +349,7 @@ impl Needle {
// LastModified (5 bytes)
if index < len_bytes && self.has_last_modified_date() {
if index + LAST_MODIFIED_BYTES_LENGTH > len_bytes {
return Ok(index); // tolerate EOF
return Err(NeedleError::IndexOutOfRange(4));
}
self.last_modified = bytes_to_u64_5(&bytes[index..index + LAST_MODIFIED_BYTES_LENGTH]);
index += LAST_MODIFIED_BYTES_LENGTH;
@ -360,7 +358,7 @@ impl Needle {
// TTL (2 bytes)
if index < len_bytes && self.has_ttl() {
if index + TTL_BYTES_LENGTH > len_bytes {
return Ok(index); // tolerate EOF
return Err(NeedleError::IndexOutOfRange(5));
}
self.ttl = Some(TTL::from_bytes(&bytes[index..index + TTL_BYTES_LENGTH]));
index += TTL_BYTES_LENGTH;
@ -369,12 +367,12 @@ impl Needle {
// Pairs
if index < len_bytes && self.has_pairs() {
if index + 2 > len_bytes {
return Ok(index); // tolerate EOF
return Err(NeedleError::IndexOutOfRange(6));
}
self.pairs_size = u16::from_be_bytes([bytes[index], bytes[index + 1]]);
index += 2;
if index + self.pairs_size as usize > len_bytes {
return Ok(index); // tolerate EOF
return Err(NeedleError::IndexOutOfRange(7));
}
self.pairs = bytes[index..index + self.pairs_size as usize].to_vec();
index += self.pairs_size as usize;

Loading…
Cancel
Save