aboutsummaryrefslogtreecommitdiff
path: root/src/api/api_server.rs
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2020-04-26 20:39:32 +0000
committerAlex Auvolat <alex@adnab.me>2020-04-26 20:39:32 +0000
commit81ecc4999e16c58ce6d0e97501f7b6b1497f6cf6 (patch)
treed22638738b6105ebc8c7eb8fe1d633bf3627b034 /src/api/api_server.rs
parent1999c0ae5152917625558c588e71b27f63950f41 (diff)
downloadgarage-81ecc4999e16c58ce6d0e97501f7b6b1497f6cf6.tar.gz
garage-81ecc4999e16c58ce6d0e97501f7b6b1497f6cf6.zip
Implement multipart uploads
Diffstat (limited to 'src/api/api_server.rs')
-rw-r--r--src/api/api_server.rs83
1 files changed, 53 insertions, 30 deletions
diff --git a/src/api/api_server.rs b/src/api/api_server.rs
index 37c95f92..947d1a91 100644
--- a/src/api/api_server.rs
+++ b/src/api/api_server.rs
@@ -3,7 +3,6 @@ use std::net::SocketAddr;
use std::sync::Arc;
use futures::future::Future;
-use hyper::body::{Bytes, HttpBody};
use hyper::server::conn::AddrStream;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, Server};
@@ -15,11 +14,9 @@ use garage_core::garage::Garage;
use crate::http_util::*;
use crate::signature::check_signature;
-use crate::s3_get::{handle_get, handle_head};
-use crate::s3_list::handle_list;
-use crate::s3_put::{handle_delete, handle_put};
-
-pub type BodyType = Box<dyn HttpBody<Data = Bytes, Error = Error> + Send + Unpin>;
+use crate::s3_get::*;
+use crate::s3_list::*;
+use crate::s3_put::*;
pub async fn run_api_server(
garage: Arc<Garage>,
@@ -100,33 +97,62 @@ async fn handler_inner(
)));
}
+ let mut params = HashMap::new();
+ if let Some(query) = req.uri().query() {
+ let query_pairs = url::form_urlencoded::parse(query.as_bytes());
+ for (key, val) in query_pairs {
+ params.insert(key.to_lowercase(), val.to_string());
+ }
+ }
+
if let Some(key) = key {
match req.method() {
- &Method::HEAD => Ok(handle_head(garage, &bucket, &key).await?),
- &Method::GET => Ok(handle_get(garage, &bucket, &key).await?),
+ &Method::HEAD => {
+ // HeadObject query
+ Ok(handle_head(garage, &bucket, &key).await?)
+ }
+ &Method::GET => {
+ // GetObject query
+ Ok(handle_get(garage, &bucket, &key).await?)
+ }
&Method::PUT => {
- let mime_type = req
- .headers()
- .get(hyper::header::CONTENT_TYPE)
- .map(|x| x.to_str())
- .unwrap_or(Ok("blob"))?
- .to_string();
- let version_uuid =
- handle_put(garage, &mime_type, &bucket, &key, req.into_body()).await?;
- let response = format!("{}\n", hex::encode(version_uuid,));
- Ok(Response::new(Box::new(BytesBody::from(response))))
+ if ["partnumber", "uploadid"]
+ .iter()
+ .all(|x| params.contains_key(&x.to_string()))
+ {
+ 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 {
+ // PutObject query
+ Ok(handle_put(garage, req, &bucket, &key).await?)
+ }
}
&Method::DELETE => {
+ // DeleteObject query
let version_uuid = handle_delete(garage, &bucket, &key).await?;
- let response = format!("{}\n", hex::encode(version_uuid,));
+ let response = format!("{}\n", hex::encode(version_uuid));
Ok(Response::new(Box::new(BytesBody::from(response))))
}
+ &Method::POST => {
+ if params.contains_key(&"uploads".to_string()) {
+ // CreateMultipartUpload call
+ Ok(handle_create_multipart_upload(garage, &req, &bucket, &key).await?)
+ } else if params.contains_key(&"uploadid".to_string()) {
+ let upload_id = params.get("uploadid").unwrap();
+ Ok(handle_complete_multipart_upload(garage, req, &bucket, &key, upload_id).await?)
+ } else {
+ Err(Error::BadRequest(format!(
+ "Not a CreateMultipartUpload call, what is it?"
+ )))
+ }
+ }
_ => Err(Error::BadRequest(format!("Invalid method"))),
}
} else {
match req.method() {
&Method::PUT | &Method::HEAD => {
- // If PUT: corresponds to a bucket creation call
+ // If PUT: CreateBucket, if HEAD: HeadBucket
// If we're here, the bucket already exists, so just answer ok
let empty_body: BodyType = Box::new(BytesBody::from(vec![]));
let response = Response::builder()
@@ -135,21 +161,18 @@ async fn handler_inner(
.unwrap();
Ok(response)
}
- &Method::DELETE => Err(Error::Forbidden(
- "Cannot delete buckets using S3 api, please talk to Garage directly".into(),
- )),
+ &Method::DELETE => {
+ // DeleteBucket query
+ Err(Error::Forbidden(
+ "Cannot delete buckets using S3 api, please talk to Garage directly".into(),
+ ))
+ }
&Method::GET => {
- let mut params = HashMap::new();
- if let Some(query) = req.uri().query() {
- let query_pairs = url::form_urlencoded::parse(query.as_bytes());
- for (key, val) in query_pairs {
- params.insert(key.to_lowercase(), val.to_string());
- }
- }
if ["delimiter", "prefix"]
.iter()
.all(|x| params.contains_key(&x.to_string()))
{
+ // ListObjects query
let delimiter = params.get("delimiter").unwrap();
let max_keys = params
.get("max-keys")