diff options
Diffstat (limited to 'src/api/s3_get.rs')
-rw-r--r-- | src/api/s3_get.rs | 59 |
1 files changed, 35 insertions, 24 deletions
diff --git a/src/api/s3_get.rs b/src/api/s3_get.rs index 42cf55d1..25b3d3e3 100644 --- a/src/api/s3_get.rs +++ b/src/api/s3_get.rs @@ -12,13 +12,14 @@ use garage_table::EmptyKey; use garage_model::garage::Garage; use garage_model::object_table::*; -fn object_headers(version: &ObjectVersion) -> http::response::Builder { +fn object_headers(version: &ObjectVersion, version_meta: &ObjectVersionMeta) -> http::response::Builder { let date = UNIX_EPOCH + Duration::from_millis(version.timestamp); let date_str = httpdate::fmt_http_date(date); Response::builder() - .header("Content-Type", version.mime_type.to_string()) - .header("Content-Length", format!("{}", version.size)) + .header("Content-Type", version_meta.headers.content_type.to_string()) + .header("Content-Length", format!("{}", version_meta.size)) + .header("ETag", version_meta.etag.to_string()) .header("Last-Modified", date_str) .header("Accept-Ranges", format!("bytes")) } @@ -47,9 +48,14 @@ pub async fn handle_head( Some(v) => v, None => return Err(Error::NotFound), }; + let version_meta = match &version.state { + ObjectVersionState::Complete(ObjectVersionData::Inline(meta, _)) => meta, + ObjectVersionState::Complete(ObjectVersionData::FirstBlock(meta, _)) => meta, + _ => unreachable!(), + }; let body: Body = Body::from(vec![]); - let response = object_headers(&version) + let response = object_headers(&version, version_meta) .status(StatusCode::OK) .body(body) .unwrap(); @@ -81,13 +87,22 @@ pub async fn handle_get( Some(v) => v, None => return Err(Error::NotFound), }; + let last_v_data = match &last_v.state { + ObjectVersionState::Complete(x) => x, + _ => unreachable!(), + }; + let last_v_meta = match last_v_data { + ObjectVersionData::DeleteMarker => return Err(Error::NotFound), + ObjectVersionData::Inline(meta, _) => meta, + ObjectVersionData::FirstBlock(meta, _) => meta, + }; let range = match req.headers().get("range") { Some(range) => { let range_str = range .to_str() .map_err(|e| Error::BadRequest(format!("Invalid range header: {}", e)))?; - let mut ranges = http_range::HttpRange::parse(range_str, last_v.size) + let mut ranges = http_range::HttpRange::parse(range_str, last_v_meta.size) .map_err(|_e| Error::BadRequest(format!("Invalid range")))?; if ranges.len() > 1 { return Err(Error::BadRequest(format!("Multiple ranges not supported"))); @@ -98,21 +113,18 @@ pub async fn handle_get( None => None, }; if let Some(range) = range { - return handle_get_range(garage, last_v, range.start, range.start + range.length).await; + return handle_get_range(garage, last_v, last_v_data, last_v_meta, range.start, range.start + range.length).await; } - let resp_builder = object_headers(&last_v).status(StatusCode::OK); + let resp_builder = object_headers(&last_v, last_v_meta).status(StatusCode::OK); - match &last_v.data { - ObjectVersionData::Uploading => Err(Error::Message(format!( - "Version is_complete() but data is stil Uploading (internal error)" - ))), - ObjectVersionData::DeleteMarker => Err(Error::NotFound), - ObjectVersionData::Inline(bytes) => { + match &last_v_data { + ObjectVersionData::DeleteMarker => unreachable!(), + ObjectVersionData::Inline(_, bytes) => { let body: Body = Body::from(bytes.to_vec()); Ok(resp_builder.body(body)?) } - ObjectVersionData::FirstBlock(first_block_hash) => { + ObjectVersionData::FirstBlock(_, first_block_hash) => { let read_first_block = garage.block_manager.rpc_get_block(&first_block_hash); let get_next_blocks = garage.version_table.get(&last_v.uuid, &EmptyKey); @@ -155,26 +167,25 @@ pub async fn handle_get( pub async fn handle_get_range( garage: Arc<Garage>, version: &ObjectVersion, + version_data: &ObjectVersionData, + version_meta: &ObjectVersionMeta, begin: u64, end: u64, ) -> Result<Response<Body>, Error> { - if end > version.size { + if end > version_meta.size { return Err(Error::BadRequest(format!("Range not included in file"))); } - let resp_builder = object_headers(&version) + let resp_builder = object_headers(version, version_meta) .header( "Content-Range", - format!("bytes {}-{}/{}", begin, end, version.size), + format!("bytes {}-{}/{}", begin, end, version_meta.size), ) .status(StatusCode::PARTIAL_CONTENT); - match &version.data { - ObjectVersionData::Uploading => Err(Error::Message(format!( - "Version is_complete() but data is stil Uploading (internal error)" - ))), - ObjectVersionData::DeleteMarker => Err(Error::NotFound), - ObjectVersionData::Inline(bytes) => { + match &version_data { + ObjectVersionData::DeleteMarker => unreachable!(), + ObjectVersionData::Inline(_meta, bytes) => { if end as usize <= bytes.len() { let body: Body = Body::from(bytes[begin as usize..end as usize].to_vec()); Ok(resp_builder.body(body)?) @@ -182,7 +193,7 @@ pub async fn handle_get_range( Err(Error::Message(format!("Internal error: requested range not present in inline bytes when it should have been"))) } } - ObjectVersionData::FirstBlock(_first_block_hash) => { + ObjectVersionData::FirstBlock(_meta, _first_block_hash) => { let version = garage.version_table.get(&version.uuid, &EmptyKey).await?; let version = match version { Some(v) => v, |