fix clippy warnings on api

This commit is contained in:
Trinity Pointard 2021-04-23 22:18:00 +02:00 committed by Alex Auvolat
parent 4a1e079e8f
commit 84856e84e5
No known key found for this signature in database
GPG Key ID: EDABF9711E244EB1
8 changed files with 85 additions and 81 deletions

View File

@ -92,9 +92,9 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
_ => api_key.allow_write(&bucket), _ => api_key.allow_write(&bucket),
}; };
if !allowed { if !allowed {
return Err(Error::Forbidden(format!( return Err(Error::Forbidden(
"Operation is not allowed for this key." "Operation is not allowed for this key.".to_string(),
))); ));
} }
let mut params = HashMap::new(); let mut params = HashMap::new();
@ -106,16 +106,16 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
} }
if let Some(key) = key { if let Some(key) = key {
match req.method() { match *req.method() {
&Method::HEAD => { Method::HEAD => {
// HeadObject query // HeadObject query
Ok(handle_head(garage, &req, &bucket, &key).await?) Ok(handle_head(garage, &req, &bucket, &key).await?)
} }
&Method::GET => { Method::GET => {
// GetObject query // GetObject query
Ok(handle_get(garage, &req, &bucket, &key).await?) Ok(handle_get(garage, &req, &bucket, &key).await?)
} }
&Method::PUT => { Method::PUT => {
if params.contains_key(&"partnumber".to_string()) if params.contains_key(&"partnumber".to_string())
&& params.contains_key(&"uploadid".to_string()) && params.contains_key(&"uploadid".to_string())
{ {
@ -154,7 +154,7 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
Ok(handle_put(garage, req, &bucket, &key, content_sha256).await?) Ok(handle_put(garage, req, &bucket, &key, content_sha256).await?)
} }
} }
&Method::DELETE => { Method::DELETE => {
if params.contains_key(&"uploadid".to_string()) { if params.contains_key(&"uploadid".to_string()) {
// AbortMultipartUpload query // AbortMultipartUpload query
let upload_id = params.get("uploadid").unwrap(); let upload_id = params.get("uploadid").unwrap();
@ -164,7 +164,7 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
Ok(handle_delete(garage, &bucket, &key).await?) Ok(handle_delete(garage, &bucket, &key).await?)
} }
} }
&Method::POST => { Method::POST => {
if params.contains_key(&"uploads".to_string()) { if params.contains_key(&"uploads".to_string()) {
// CreateMultipartUpload call // CreateMultipartUpload call
Ok(handle_create_multipart_upload(garage, &req, &bucket, &key).await?) Ok(handle_create_multipart_upload(garage, &req, &bucket, &key).await?)
@ -181,16 +181,16 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
) )
.await?) .await?)
} else { } else {
Err(Error::BadRequest(format!( Err(Error::BadRequest(
"Not a CreateMultipartUpload call, what is it?" "Not a CreateMultipartUpload call, what is it?".to_string(),
))) ))
} }
} }
_ => Err(Error::BadRequest(format!("Invalid method"))), _ => Err(Error::BadRequest("Invalid method".to_string())),
} }
} else { } else {
match req.method() { match *req.method() {
&Method::PUT => { Method::PUT => {
// CreateBucket // CreateBucket
// If we're here, the bucket already exists, so just answer ok // If we're here, the bucket already exists, so just answer ok
debug!( debug!(
@ -205,19 +205,19 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
.unwrap(); .unwrap();
Ok(response) Ok(response)
} }
&Method::HEAD => { Method::HEAD => {
// HeadBucket // HeadBucket
let empty_body: Body = Body::from(vec![]); let empty_body: Body = Body::from(vec![]);
let response = Response::builder().body(empty_body).unwrap(); let response = Response::builder().body(empty_body).unwrap();
Ok(response) Ok(response)
} }
&Method::DELETE => { Method::DELETE => {
// DeleteBucket query // DeleteBucket query
Err(Error::Forbidden( Err(Error::Forbidden(
"Cannot delete buckets using S3 api, please talk to Garage directly".into(), "Cannot delete buckets using S3 api, please talk to Garage directly".into(),
)) ))
} }
&Method::GET => { Method::GET => {
if params.contains_key("location") { if params.contains_key("location") {
// GetBucketLocation call // GetBucketLocation call
Ok(handle_get_bucket_location(garage)?) Ok(handle_get_bucket_location(garage)?)
@ -227,7 +227,7 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
Ok(handle_list(garage, &q).await?) Ok(handle_list(garage, &q).await?)
} }
} }
&Method::POST => { Method::POST => {
if params.contains_key(&"delete".to_string()) { if params.contains_key(&"delete".to_string()) {
// DeleteObjects // DeleteObjects
Ok(handle_delete_objects(garage, bucket, req, content_sha256).await?) Ok(handle_delete_objects(garage, bucket, req, content_sha256).await?)
@ -237,10 +237,10 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
std::str::from_utf8(&hyper::body::to_bytes(req.into_body()).await?) std::str::from_utf8(&hyper::body::to_bytes(req.into_body()).await?)
.unwrap_or("<invalid utf8>") .unwrap_or("<invalid utf8>")
); );
Err(Error::BadRequest(format!("Unsupported call"))) Err(Error::BadRequest("Unsupported call".to_string()))
} }
} }
_ => Err(Error::BadRequest(format!("Invalid method"))), _ => Err(Error::BadRequest("Invalid method".to_string())),
} }
} }
} }
@ -255,7 +255,7 @@ fn parse_bucket_key(path: &str) -> Result<(&str, Option<&str>), Error> {
let (bucket, key) = match path.find('/') { let (bucket, key) = match path.find('/') {
Some(i) => { Some(i) => {
let key = &path[i + 1..]; let key = &path[i + 1..];
if key.len() > 0 { if !key.is_empty() {
(&path[..i], Some(key)) (&path[..i], Some(key))
} else { } else {
(&path[..i], None) (&path[..i], None)
@ -263,8 +263,8 @@ fn parse_bucket_key(path: &str) -> Result<(&str, Option<&str>), Error> {
} }
None => (path, None), None => (path, None),
}; };
if bucket.len() == 0 { if bucket.is_empty() {
return Err(Error::BadRequest(format!("No bucket specified"))); return Err(Error::BadRequest("No bucket specified".to_string()));
} }
Ok((bucket, key)) Ok((bucket, key))
} }

View File

@ -8,6 +8,7 @@ use garage_util::error::Error as GarageError;
use crate::encoding::*; use crate::encoding::*;
/// Errors of this crate /// Errors of this crate
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum Error { pub enum Error {
// Category: internal error // Category: internal error
@ -140,7 +141,7 @@ impl<T> OkOrBadRequest for Option<T> {
fn ok_or_bad_request(self, reason: &'static str) -> Result<T, Error> { fn ok_or_bad_request(self, reason: &'static str) -> Result<T, Error> {
match self { match self {
Some(x) => Ok(x), Some(x) => Ok(x),
None => Err(Error::BadRequest(format!("{}", reason))), None => Err(Error::BadRequest(reason.to_string())),
} }
} }
} }
@ -172,10 +173,9 @@ impl<T> OkOrInternalError for Option<T> {
fn ok_or_internal_error(self, reason: &'static str) -> Result<T, Error> { fn ok_or_internal_error(self, reason: &'static str) -> Result<T, Error> {
match self { match self {
Some(x) => Ok(x), Some(x) => Ok(x),
None => Err(Error::InternalError(GarageError::Message(format!( None => Err(Error::InternalError(GarageError::Message(
"{}", reason.to_string(),
reason ))),
)))),
} }
} }
} }

View File

@ -33,8 +33,7 @@ pub async fn handle_copy(
.versions() .versions()
.iter() .iter()
.rev() .rev()
.filter(|v| v.is_complete()) .find(|v| v.is_complete())
.next()
.ok_or(Error::NotFound)?; .ok_or(Error::NotFound)?;
let source_last_state = match &source_last_v.state { let source_last_state = match &source_last_v.state {

View File

@ -24,10 +24,12 @@ async fn handle_delete_internal(
.await? .await?
.ok_or(Error::NotFound)?; // No need to delete .ok_or(Error::NotFound)?; // No need to delete
let interesting_versions = object.versions().iter().filter(|v| match v.state { let interesting_versions = object.versions().iter().filter(|v| {
ObjectVersionState::Aborted => false, !matches!(
ObjectVersionState::Complete(ObjectVersionData::DeleteMarker) => false, v.state,
_ => true, ObjectVersionState::Aborted
| ObjectVersionState::Complete(ObjectVersionData::DeleteMarker)
)
}); });
let mut version_to_delete = None; let mut version_to_delete = None;

View File

@ -28,7 +28,7 @@ fn object_headers(
version_meta.headers.content_type.to_string(), version_meta.headers.content_type.to_string(),
) )
.header("Last-Modified", date_str) .header("Last-Modified", date_str)
.header("Accept-Ranges", format!("bytes")); .header("Accept-Ranges", "bytes".to_string());
if !version_meta.etag.is_empty() { if !version_meta.etag.is_empty() {
resp = resp.header("ETag", format!("\"{}\"", version_meta.etag)); resp = resp.header("ETag", format!("\"{}\"", version_meta.etag));
@ -97,8 +97,7 @@ pub async fn handle_head(
.versions() .versions()
.iter() .iter()
.rev() .rev()
.filter(|v| v.is_data()) .find(|v| v.is_data())
.next()
.ok_or(Error::NotFound)?; .ok_or(Error::NotFound)?;
let version_meta = match &version.state { let version_meta = match &version.state {
@ -137,8 +136,7 @@ pub async fn handle_get(
.versions() .versions()
.iter() .iter()
.rev() .rev()
.filter(|v| v.is_complete()) .find(|v| v.is_complete())
.next()
.ok_or(Error::NotFound)?; .ok_or(Error::NotFound)?;
let last_v_data = match &last_v.state { let last_v_data = match &last_v.state {
@ -160,7 +158,9 @@ pub async fn handle_get(
let range_str = range.to_str()?; let range_str = range.to_str()?;
let mut ranges = http_range::HttpRange::parse(range_str, last_v_meta.size)?; let mut ranges = http_range::HttpRange::parse(range_str, last_v_meta.size)?;
if ranges.len() > 1 { if ranges.len() > 1 {
return Err(Error::BadRequest(format!("Multiple ranges not supported"))); return Err(Error::BadRequest(
"Multiple ranges not supported".to_string(),
));
} else { } else {
ranges.pop() ranges.pop()
} }
@ -236,7 +236,7 @@ async fn handle_get_range(
end: u64, end: u64,
) -> Result<Response<Body>, Error> { ) -> Result<Response<Body>, Error> {
if end > version_meta.size { if end > version_meta.size {
return Err(Error::BadRequest(format!("Range not included in file"))); return Err(Error::BadRequest("Range not included in file".to_string()));
} }
let resp_builder = object_headers(version, version_meta) let resp_builder = object_headers(version, version_meta)
@ -282,7 +282,7 @@ async fn handle_get_range(
} }
// Keep only blocks that have an intersection with the requested range // Keep only blocks that have an intersection with the requested range
if true_offset < end && true_offset + b.size > begin { if true_offset < end && true_offset + b.size > begin {
blocks.push((b.clone(), true_offset)); blocks.push((*b, true_offset));
} }
true_offset += b.size; true_offset += b.size;
} }
@ -303,9 +303,9 @@ async fn handle_get_range(
} else { } else {
end - true_offset end - true_offset
}; };
Result::<Bytes, Error>::Ok(Bytes::from( Result::<Bytes, Error>::Ok(
data.slice(start_in_block as usize..end_in_block as usize), data.slice(start_in_block as usize..end_in_block as usize),
)) )
} }
}) })
.buffered(2); .buffered(2);

View File

@ -50,7 +50,7 @@ pub fn parse_list_objects_query(
.ok_or_bad_request("Invalid value for max-keys") .ok_or_bad_request("Invalid value for max-keys")
}) })
.unwrap_or(Ok(1000))?, .unwrap_or(Ok(1000))?,
prefix: params.get("prefix").cloned().unwrap_or(String::new()), prefix: params.get("prefix").cloned().unwrap_or_default(),
marker: params.get("marker").cloned(), marker: params.get("marker").cloned(),
continuation_token: params.get("continuation-token").cloned(), continuation_token: params.get("continuation-token").cloned(),
start_after: params.get("start-after").cloned(), start_after: params.get("start-after").cloned(),
@ -72,10 +72,13 @@ pub async fn handle_list(
if let Some(ct) = &query.continuation_token { if let Some(ct) = &query.continuation_token {
String::from_utf8(base64::decode(ct.as_bytes())?)? String::from_utf8(base64::decode(ct.as_bytes())?)?
} else { } else {
query.start_after.clone().unwrap_or(query.prefix.clone()) query
.start_after
.clone()
.unwrap_or_else(|| query.prefix.clone())
} }
} else { } else {
query.marker.clone().unwrap_or(query.prefix.clone()) query.marker.clone().unwrap_or_else(|| query.prefix.clone())
}; };
debug!( debug!(
@ -155,7 +158,7 @@ pub async fn handle_list(
truncated = None; truncated = None;
break 'query_loop; break 'query_loop;
} }
if objects.len() > 0 { if !objects.is_empty() {
next_chunk_start = objects[objects.len() - 1].key.clone(); next_chunk_start = objects[objects.len() - 1].key.clone();
} }
} }

View File

@ -46,7 +46,7 @@ pub async fn handle_put(
let body = req.into_body(); let body = req.into_body();
let mut chunker = BodyChunker::new(body, garage.config.block_size); let mut chunker = BodyChunker::new(body, garage.config.block_size);
let first_block = chunker.next().await?.unwrap_or(vec![]); let first_block = chunker.next().await?.unwrap_or_default();
// If body is small enough, store it directly in the object table // If body is small enough, store it directly in the object table
// as "inline data". We can then return immediately. // as "inline data". We can then return immediately.
@ -160,16 +160,18 @@ fn ensure_checksum_matches(
) -> Result<(), Error> { ) -> Result<(), Error> {
if let Some(expected_sha256) = content_sha256 { if let Some(expected_sha256) = content_sha256 {
if expected_sha256 != data_sha256sum { if expected_sha256 != data_sha256sum {
return Err(Error::BadRequest(format!( return Err(Error::BadRequest(
"Unable to validate x-amz-content-sha256" "Unable to validate x-amz-content-sha256".to_string(),
))); ));
} else { } else {
trace!("Successfully validated x-amz-content-sha256"); trace!("Successfully validated x-amz-content-sha256");
} }
} }
if let Some(expected_md5) = content_md5 { if let Some(expected_md5) = content_md5 {
if expected_md5.trim_matches('"') != base64::encode(data_md5sum) { if expected_md5.trim_matches('"') != base64::encode(data_md5sum) {
return Err(Error::BadRequest(format!("Unable to validate content-md5"))); return Err(Error::BadRequest(
"Unable to validate content-md5".to_string(),
));
} else { } else {
trace!("Successfully validated content-md5"); trace!("Successfully validated content-md5");
} }
@ -291,7 +293,7 @@ impl BodyChunker {
self.read_all = true; self.read_all = true;
} }
} }
if self.buf.len() == 0 { if self.buf.is_empty() {
Ok(None) Ok(None)
} else if self.buf.len() <= self.block_size { } else if self.buf.len() <= self.block_size {
let block = self.buf.drain(..).collect::<Vec<u8>>(); let block = self.buf.drain(..).collect::<Vec<u8>>();
@ -387,8 +389,8 @@ pub async fn handle_put_part(
futures::try_join!(garage.object_table.get(&bucket, &key), chunker.next(),)?; futures::try_join!(garage.object_table.get(&bucket, &key), chunker.next(),)?;
// Check object is valid and multipart block can be accepted // Check object is valid and multipart block can be accepted
let first_block = first_block.ok_or(Error::BadRequest(format!("Empty body")))?; let first_block = first_block.ok_or_else(|| Error::BadRequest("Empty body".to_string()))?;
let object = object.ok_or(Error::BadRequest(format!("Object not found")))?; let object = object.ok_or_else(|| Error::BadRequest("Object not found".to_string()))?;
if !object if !object
.versions() .versions()
@ -462,21 +464,21 @@ pub async fn handle_complete_multipart_upload(
garage.version_table.get(&version_uuid, &EmptyKey), garage.version_table.get(&version_uuid, &EmptyKey),
)?; )?;
let object = object.ok_or(Error::BadRequest(format!("Object not found")))?; let object = object.ok_or_else(|| Error::BadRequest("Object not found".to_string()))?;
let mut object_version = object let mut object_version = object
.versions() .versions()
.iter() .iter()
.find(|v| v.uuid == version_uuid && v.is_uploading()) .find(|v| v.uuid == version_uuid && v.is_uploading())
.cloned() .cloned()
.ok_or(Error::BadRequest(format!("Version not found")))?; .ok_or_else(|| Error::BadRequest("Version not found".to_string()))?;
let version = version.ok_or(Error::BadRequest(format!("Version not found")))?; let version = version.ok_or_else(|| Error::BadRequest("Version not found".to_string()))?;
if version.blocks.len() == 0 { if version.blocks.is_empty() {
return Err(Error::BadRequest(format!("No data was uploaded"))); return Err(Error::BadRequest("No data was uploaded".to_string()));
} }
let headers = match object_version.state { let headers = match object_version.state {
ObjectVersionState::Uploading(headers) => headers.clone(), ObjectVersionState::Uploading(headers) => headers,
_ => unreachable!(), _ => unreachable!(),
}; };
@ -493,7 +495,9 @@ pub async fn handle_complete_multipart_upload(
.map(|x| (&x.part_number, &x.etag)) .map(|x| (&x.part_number, &x.etag))
.eq(parts); .eq(parts);
if !same_parts { if !same_parts {
return Err(Error::BadRequest(format!("We don't have the same parts"))); return Err(Error::BadRequest(
"We don't have the same parts".to_string(),
));
} }
// Calculate etag of final object // Calculate etag of final object
@ -557,7 +561,7 @@ pub async fn handle_abort_multipart_upload(
.object_table .object_table
.get(&bucket.to_string(), &key.to_string()) .get(&bucket.to_string(), &key.to_string())
.await?; .await?;
let object = object.ok_or(Error::BadRequest(format!("Object not found")))?; let object = object.ok_or_else(|| Error::BadRequest("Object not found".to_string()))?;
let object_version = object let object_version = object
.versions() .versions()

View File

@ -43,13 +43,12 @@ pub async fn check_signature(
let date = headers let date = headers
.get("x-amz-date") .get("x-amz-date")
.ok_or_bad_request("Missing X-Amz-Date field")?; .ok_or_bad_request("Missing X-Amz-Date field")?;
let date: NaiveDateTime = NaiveDateTime::parse_from_str(date, LONG_DATETIME) let date: NaiveDateTime =
.ok_or_bad_request("Invalid date")? NaiveDateTime::parse_from_str(date, LONG_DATETIME).ok_or_bad_request("Invalid date")?;
.into();
let date: DateTime<Utc> = DateTime::from_utc(date, Utc); let date: DateTime<Utc> = DateTime::from_utc(date, Utc);
if Utc::now() - date > Duration::hours(24) { if Utc::now() - date > Duration::hours(24) {
return Err(Error::BadRequest(format!("Date is too old"))); return Err(Error::BadRequest("Date is too old".to_string()));
} }
let scope = format!( let scope = format!(
@ -66,10 +65,7 @@ pub async fn check_signature(
.get(&EmptyKey, &authorization.key_id) .get(&EmptyKey, &authorization.key_id)
.await? .await?
.filter(|k| !k.deleted.get()) .filter(|k| !k.deleted.get())
.ok_or(Error::Forbidden(format!( .ok_or_else(|| Error::Forbidden(format!("No such key: {}", authorization.key_id)))?;
"No such key: {}",
authorization.key_id
)))?;
let canonical_request = canonical_request( let canonical_request = canonical_request(
request.method(), request.method(),
@ -95,7 +91,7 @@ pub async fn check_signature(
trace!("Canonical request: ``{}``", canonical_request); trace!("Canonical request: ``{}``", canonical_request);
trace!("String to sign: ``{}``", string_to_sign); trace!("String to sign: ``{}``", string_to_sign);
trace!("Expected: {}, got: {}", signature, authorization.signature); trace!("Expected: {}, got: {}", signature, authorization.signature);
return Err(Error::Forbidden(format!("Invalid signature"))); return Err(Error::Forbidden("Invalid signature".to_string()));
} }
let content_sha256 = if authorization.content_sha256 == "UNSIGNED-PAYLOAD" { let content_sha256 = if authorization.content_sha256 == "UNSIGNED-PAYLOAD" {
@ -105,7 +101,7 @@ pub async fn check_signature(
.ok_or_bad_request("Invalid content sha256 hash")?; .ok_or_bad_request("Invalid content sha256 hash")?;
Some( Some(
Hash::try_from(&bytes[..]) Hash::try_from(&bytes[..])
.ok_or(Error::BadRequest(format!("Invalid content sha256 hash")))?, .ok_or_else(|| Error::BadRequest("Invalid content sha256 hash".to_string()))?,
) )
}; };
@ -173,9 +169,9 @@ fn parse_query_authorization(headers: &HashMap<String, String>) -> Result<Author
.get("x-amz-algorithm") .get("x-amz-algorithm")
.ok_or_bad_request("X-Amz-Algorithm not found in query parameters")?; .ok_or_bad_request("X-Amz-Algorithm not found in query parameters")?;
if algo != "AWS4-HMAC-SHA256" { if algo != "AWS4-HMAC-SHA256" {
return Err(Error::BadRequest(format!( return Err(Error::BadRequest(
"Unsupported authorization method" "Unsupported authorization method".to_string(),
))); ));
} }
let cred = headers let cred = headers
@ -293,9 +289,9 @@ pub fn verify_signed_content(content_sha256: Option<Hash>, body: &[u8]) -> Resul
let expected_sha256 = let expected_sha256 =
content_sha256.ok_or_bad_request("Request content hash not signed, aborting.")?; content_sha256.ok_or_bad_request("Request content hash not signed, aborting.")?;
if expected_sha256 != sha256sum(body) { if expected_sha256 != sha256sum(body) {
return Err(Error::BadRequest(format!( return Err(Error::BadRequest(
"Request content hash does not match signed hash" "Request content hash does not match signed hash".to_string(),
))); ));
} }
Ok(()) Ok(())
} }