diff options
author | Alex Auvolat <alex@adnab.me> | 2020-04-28 10:18:14 +0000 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2020-04-28 10:18:14 +0000 |
commit | 0957d0fdfadb27e49c24d63994f52197a9c9cd1c (patch) | |
tree | 35b048599d44de01650d99ccc2de942498ac4038 /src/api/api_server.rs | |
parent | be35cbdce2bd4e42a2bfc41ff5b21e332d20eb29 (diff) | |
download | garage-0957d0fdfadb27e49c24d63994f52197a9c9cd1c.tar.gz garage-0957d0fdfadb27e49c24d63994f52197a9c9cd1c.zip |
Work on API
Diffstat (limited to 'src/api/api_server.rs')
-rw-r--r-- | src/api/api_server.rs | 75 |
1 files changed, 56 insertions, 19 deletions
diff --git a/src/api/api_server.rs b/src/api/api_server.rs index b92f4403..6ba5e532 100644 --- a/src/api/api_server.rs +++ b/src/api/api_server.rs @@ -14,6 +14,8 @@ use garage_core::garage::Garage; use crate::http_util::*; use crate::signature::check_signature; +use crate::s3_copy::*; +use crate::s3_delete::*; use crate::s3_get::*; use crate::s3_list::*; use crate::s3_put::*; @@ -71,15 +73,7 @@ async fn handler_inner( req: Request<Body>, ) -> Result<Response<BodyType>, Error> { let path = req.uri().path().to_string(); - let path = path.trim_start_matches('/'); - let (bucket, key) = match path.find('/') { - Some(i) => { - let (bucket, key) = path.split_at(i); - let key = key.trim_start_matches('/'); - (bucket, Some(key)) - } - None => (path, None), - }; + let (bucket, key) = parse_bucket_key(path.as_str())?; if bucket.len() == 0 { return Err(Error::Forbidden(format!( "Operations on buckets not allowed" @@ -116,14 +110,28 @@ async fn handler_inner( Ok(handle_get(garage, &bucket, &key).await?) } &Method::PUT => { - if ["partnumber", "uploadid"] - .iter() - .all(|x| params.contains_key(&x.to_string())) + if params.contains_key(&"partnumber".to_string()) + && params.contains_key(&"uploadid".to_string()) { // UploadPart query let part_number = params.get("partnumber").unwrap(); let upload_id = params.get("uploadid").unwrap(); Ok(handle_put_part(garage, req, &bucket, &key, part_number, upload_id).await?) + } else if req.headers().contains_key("x-amz-copy-source") { + // CopyObject query + let copy_source = req.headers().get("x-amz-copy-source").unwrap().to_str()?; + let (source_bucket, source_key) = parse_bucket_key(copy_source)?; + if !api_key.allow_read(&source_bucket) { + return Err(Error::Forbidden(format!( + "Reading from bucket {} not allowed for this key", + source_bucket + ))); + } + let source_key = match source_key { + None => return Err(Error::BadRequest(format!("No source key specified"))), + Some(x) => x, + }; + Ok(handle_copy(garage, &bucket, &key, &source_bucket, &source_key).await?) } else { // PutObject query Ok(handle_put(garage, req, &bucket, &key).await?) @@ -148,7 +156,10 @@ async fn handler_inner( } else if params.contains_key(&"uploadid".to_string()) { // CompleteMultipartUpload call let upload_id = params.get("uploadid").unwrap(); - Ok(handle_complete_multipart_upload(garage, req, &bucket, &key, upload_id).await?) + Ok( + handle_complete_multipart_upload(garage, req, &bucket, &key, upload_id) + .await?, + ) } else { Err(Error::BadRequest(format!( "Not a CreateMultipartUpload call, what is it?" @@ -176,12 +187,9 @@ async fn handler_inner( )) } &Method::GET => { - if ["delimiter", "prefix"] - .iter() - .all(|x| params.contains_key(&x.to_string())) - { + if params.contains_key(&"prefix".to_string()) { // ListObjects query - let delimiter = params.get("delimiter").unwrap(); + let delimiter = params.get("delimiter").map(|x| x.as_str()).unwrap_or(&""); let max_keys = params .get("max-keys") .map(|x| { @@ -191,7 +199,21 @@ async fn handler_inner( }) .unwrap_or(Ok(1000))?; let prefix = params.get("prefix").unwrap(); - Ok(handle_list(garage, bucket, delimiter, max_keys, prefix).await?) + let urlencode_resp = params + .get("encoding-type") + .map(|x| x == "url") + .unwrap_or(false); + let marker = params.get("marker").map(String::as_str); + Ok(handle_list( + garage, + bucket, + delimiter, + max_keys, + prefix, + marker, + urlencode_resp, + ) + .await?) } else { Err(Error::BadRequest(format!( "Not a list call, so what is it?" @@ -202,3 +224,18 @@ async fn handler_inner( } } } + +fn parse_bucket_key(path: &str) -> Result<(&str, Option<&str>), Error> { + if !path.starts_with('/') { + return Err(Error::BadRequest(format!( + "Invalid path: {}, should start with a /", + path + ))); + } + let path = &path[1..]; + + match path.find('/') { + Some(i) => Ok((&path[..i], Some(&path[i + 1..]))), + None => Ok((path, None)), + } +} |