From 6c7f9704eabad3f19e426371b21f174f7e1dc2cf Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Mon, 13 Jul 2020 16:51:30 +0200 Subject: Implement correct ETag for objects created with PutObject --- src/api/s3_put.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'src/api/s3_put.rs') diff --git a/src/api/s3_put.rs b/src/api/s3_put.rs index 0a010a82..fdc188c9 100644 --- a/src/api/s3_put.rs +++ b/src/api/s3_put.rs @@ -2,6 +2,7 @@ use std::collections::{BTreeMap, VecDeque}; use std::fmt::Write; use std::sync::Arc; +use md5::{Md5, Digest}; use futures::stream::*; use hyper::{Body, Request, Response}; @@ -41,18 +42,22 @@ pub async fn handle_put( }; if first_block.len() < INLINE_THRESHOLD { + let mut md5sum = Md5::new(); + md5sum.update(&first_block[..]); + let etag = hex::encode(md5sum.finalize()); + object_version.state = ObjectVersionState::Complete(ObjectVersionData::Inline( ObjectVersionMeta { headers, size: first_block.len() as u64, - etag: "".to_string(), // TODO + etag: etag.clone(), }, first_block, )); let object = Object::new(bucket.into(), key.into(), vec![object_version]); garage.object_table.insert(&object).await?; - return Ok(put_response(version_uuid)); + return Ok(put_response(version_uuid, etag)); } let version = Version::new(version_uuid, bucket.into(), key.into(), false, vec![]); @@ -61,7 +66,7 @@ pub async fn handle_put( let object = Object::new(bucket.into(), key.into(), vec![object_version.clone()]); garage.object_table.insert(&object).await?; - let total_size = read_and_put_blocks( + let (total_size, etag) = read_and_put_blocks( &garage, version, 1, @@ -77,7 +82,7 @@ pub async fn handle_put( ObjectVersionMeta { headers, size: total_size, - etag: "".to_string(), // TODO + etag: etag.clone(), }, first_block_hash, )); @@ -85,7 +90,7 @@ pub async fn handle_put( let object = Object::new(bucket.into(), key.into(), vec![object_version]); garage.object_table.insert(&object).await?; - Ok(put_response(version_uuid)) + Ok(put_response(version_uuid, etag)) } async fn read_and_put_blocks( @@ -95,7 +100,10 @@ async fn read_and_put_blocks( first_block: Vec, first_block_hash: Hash, chunker: &mut BodyChunker, -) -> Result { +) -> Result<(u64, String), Error> { + let mut md5sum = Md5::new(); + md5sum.update(&first_block[..]); + let mut next_offset = first_block.len(); let mut put_curr_version_block = put_block_meta( garage.clone(), @@ -113,6 +121,7 @@ async fn read_and_put_blocks( let (_, _, next_block) = futures::try_join!(put_curr_block, put_curr_version_block, chunker.next())?; if let Some(block) = next_block { + md5sum.update(&block[..]); let block_hash = hash(&block[..]); let block_len = block.len(); put_curr_version_block = put_block_meta( @@ -130,7 +139,9 @@ async fn read_and_put_blocks( } } - Ok(next_offset as u64) + let total_size = next_offset as u64; + let md5sum = hex::encode(md5sum.finalize()); + Ok((total_size, md5sum)) } async fn put_block_meta( @@ -203,9 +214,10 @@ impl BodyChunker { } } -pub fn put_response(version_uuid: UUID) -> Response { +pub fn put_response(version_uuid: UUID, etag: String) -> Response { Response::builder() .header("x-amz-version-id", hex::encode(version_uuid)) + .header("ETag", etag) // TODO ETag .body(Body::from(vec![])) .unwrap() -- cgit v1.2.3