More error refactoring
This commit is contained in:
parent
f82b938033
commit
7a5d329e49
12 changed files with 37 additions and 54 deletions
|
@ -18,7 +18,7 @@ use garage_model::s3::object_table::ObjectFilter;
|
||||||
|
|
||||||
use crate::admin::error::*;
|
use crate::admin::error::*;
|
||||||
use crate::admin::key::ApiBucketKeyPerm;
|
use crate::admin::key::ApiBucketKeyPerm;
|
||||||
use crate::admin::parse_json_body;
|
use crate::helpers::parse_json_body;
|
||||||
|
|
||||||
pub async fn handle_list_buckets(garage: &Arc<Garage>) -> Result<Response<Body>, Error> {
|
pub async fn handle_list_buckets(garage: &Arc<Garage>) -> Result<Response<Body>, Error> {
|
||||||
let buckets = garage
|
let buckets = garage
|
||||||
|
@ -333,7 +333,7 @@ pub async fn handle_delete_bucket(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
if !objects.is_empty() {
|
if !objects.is_empty() {
|
||||||
return Err(Error::bad_request("Bucket is not empty"));
|
return Err(Error::BucketNotEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- done checking, now commit ---
|
// --- done checking, now commit ---
|
||||||
|
|
|
@ -14,7 +14,7 @@ use garage_rpc::layout::*;
|
||||||
use garage_model::garage::Garage;
|
use garage_model::garage::Garage;
|
||||||
|
|
||||||
use crate::admin::error::*;
|
use crate::admin::error::*;
|
||||||
use crate::admin::parse_json_body;
|
use crate::helpers::parse_json_body;
|
||||||
|
|
||||||
pub async fn handle_get_cluster_status(garage: &Arc<Garage>) -> Result<Response<Body>, Error> {
|
pub async fn handle_get_cluster_status(garage: &Arc<Garage>) -> Result<Response<Body>, Error> {
|
||||||
let res = GetClusterStatusResponse {
|
let res = GetClusterStatusResponse {
|
||||||
|
|
|
@ -40,10 +40,6 @@ pub enum Error {
|
||||||
/// Bucket name is not valid according to AWS S3 specs
|
/// Bucket name is not valid according to AWS S3 specs
|
||||||
#[error(display = "Invalid bucket name")]
|
#[error(display = "Invalid bucket name")]
|
||||||
InvalidBucketName,
|
InvalidBucketName,
|
||||||
|
|
||||||
/// The client sent a request for an action not supported by garage
|
|
||||||
#[error(display = "Unimplemented action: {}", _0)]
|
|
||||||
NotImplemented(String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<T> for Error
|
impl<T> From<T> for Error
|
||||||
|
@ -75,7 +71,6 @@ impl ApiError for Error {
|
||||||
Error::NoSuchAccessKey | Error::NoSuchBucket => StatusCode::NOT_FOUND,
|
Error::NoSuchAccessKey | Error::NoSuchBucket => StatusCode::NOT_FOUND,
|
||||||
Error::BucketNotEmpty | Error::BucketAlreadyExists => StatusCode::CONFLICT,
|
Error::BucketNotEmpty | Error::BucketAlreadyExists => StatusCode::CONFLICT,
|
||||||
Error::Forbidden(_) => StatusCode::FORBIDDEN,
|
Error::Forbidden(_) => StatusCode::FORBIDDEN,
|
||||||
Error::NotImplemented(_) => StatusCode::NOT_IMPLEMENTED,
|
|
||||||
Error::InvalidBucketName => StatusCode::BAD_REQUEST,
|
Error::InvalidBucketName => StatusCode::BAD_REQUEST,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use garage_model::garage::Garage;
|
||||||
use garage_model::key_table::*;
|
use garage_model::key_table::*;
|
||||||
|
|
||||||
use crate::admin::error::*;
|
use crate::admin::error::*;
|
||||||
use crate::admin::parse_json_body;
|
use crate::helpers::parse_json_body;
|
||||||
|
|
||||||
pub async fn handle_list_keys(garage: &Arc<Garage>) -> Result<Response<Body>, Error> {
|
pub async fn handle_list_keys(garage: &Arc<Garage>) -> Result<Response<Body>, Error> {
|
||||||
let res = garage
|
let res = garage
|
||||||
|
|
|
@ -5,14 +5,3 @@ mod router;
|
||||||
mod bucket;
|
mod bucket;
|
||||||
mod cluster;
|
mod cluster;
|
||||||
mod key;
|
mod key;
|
||||||
|
|
||||||
use hyper::{Body, Request};
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
use error::*;
|
|
||||||
|
|
||||||
pub async fn parse_json_body<T: for<'de> Deserialize<'de>>(req: Request<Body>) -> Result<T, Error> {
|
|
||||||
let body = hyper::body::to_bytes(req.into_body()).await?;
|
|
||||||
let resp: T = serde_json::from_slice(&body).ok_or_bad_request("Invalid JSON")?;
|
|
||||||
Ok(resp)
|
|
||||||
}
|
|
||||||
|
|
|
@ -38,6 +38,11 @@ impl CommonError {
|
||||||
CommonError::BadRequest(_) => StatusCode::BAD_REQUEST,
|
CommonError::BadRequest(_) => StatusCode::BAD_REQUEST,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn bad_request<M: ToString>(msg: M) -> Self {
|
||||||
|
CommonError::BadRequest(msg.to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait to map error to the Bad Request error code
|
/// Trait to map error to the Bad Request error code
|
||||||
|
|
|
@ -2,12 +2,7 @@ use hyper::{Body, Request};
|
||||||
use idna::domain_to_unicode;
|
use idna::domain_to_unicode;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use garage_util::data::*;
|
use crate::common_error::{*, CommonError as Error};
|
||||||
|
|
||||||
use garage_model::garage::Garage;
|
|
||||||
use garage_model::key_table::Key;
|
|
||||||
|
|
||||||
use crate::s3::error::*;
|
|
||||||
|
|
||||||
/// What kind of authorization is required to perform a given action
|
/// What kind of authorization is required to perform a given action
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -81,28 +76,6 @@ pub fn authority_to_host(authority: &str) -> Result<String, Error> {
|
||||||
authority.map(|h| domain_to_unicode(h).0)
|
authority.map(|h| domain_to_unicode(h).0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::ptr_arg)]
|
|
||||||
pub async fn resolve_bucket(
|
|
||||||
garage: &Garage,
|
|
||||||
bucket_name: &String,
|
|
||||||
api_key: &Key,
|
|
||||||
) -> Result<Uuid, Error> {
|
|
||||||
let api_key_params = api_key
|
|
||||||
.state
|
|
||||||
.as_option()
|
|
||||||
.ok_or_internal_error("Key should not be deleted at this point")?;
|
|
||||||
|
|
||||||
if let Some(Some(bucket_id)) = api_key_params.local_aliases.get(bucket_name) {
|
|
||||||
Ok(*bucket_id)
|
|
||||||
} else {
|
|
||||||
Ok(garage
|
|
||||||
.bucket_helper()
|
|
||||||
.resolve_global_bucket_name(bucket_name)
|
|
||||||
.await?
|
|
||||||
.ok_or(Error::NoSuchBucket)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extract the bucket name and the key name from an HTTP path and possibly a bucket provided in
|
/// Extract the bucket name and the key name from an HTTP path and possibly a bucket provided in
|
||||||
/// the host header of the request
|
/// the host header of the request
|
||||||
///
|
///
|
||||||
|
|
|
@ -100,7 +100,7 @@ impl ApiHandler for K2VApiServer {
|
||||||
"k2v",
|
"k2v",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let bucket_id = resolve_bucket(&garage, &bucket_name, &api_key).await?;
|
let bucket_id = garage.bucket_helper().resolve_bucket(&bucket_name, &api_key).await?;
|
||||||
let bucket = garage
|
let bucket = garage
|
||||||
.bucket_table
|
.bucket_table
|
||||||
.get(&EmptyKey, &bucket_id)
|
.get(&EmptyKey, &bucket_id)
|
||||||
|
|
|
@ -149,7 +149,7 @@ impl ApiHandler for S3ApiServer {
|
||||||
return handle_create_bucket(&garage, req, content_sha256, api_key, bucket_name).await;
|
return handle_create_bucket(&garage, req, content_sha256, api_key, bucket_name).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
let bucket_id = resolve_bucket(&garage, &bucket_name, &api_key).await?;
|
let bucket_id = garage.bucket_helper().resolve_bucket(&bucket_name, &api_key).await?;
|
||||||
let bucket = garage
|
let bucket = garage
|
||||||
.bucket_table
|
.bucket_table
|
||||||
.get(&EmptyKey, &bucket_id)
|
.get(&EmptyKey, &bucket_id)
|
||||||
|
|
|
@ -19,7 +19,7 @@ use garage_model::s3::object_table::*;
|
||||||
use garage_model::s3::version_table::*;
|
use garage_model::s3::version_table::*;
|
||||||
|
|
||||||
use crate::s3::error::*;
|
use crate::s3::error::*;
|
||||||
use crate::helpers::{parse_bucket_key, resolve_bucket};
|
use crate::helpers::{parse_bucket_key};
|
||||||
use crate::s3::put::{decode_upload_id, get_headers};
|
use crate::s3::put::{decode_upload_id, get_headers};
|
||||||
use crate::s3::xml::{self as s3_xml, xmlns_tag};
|
use crate::s3::xml::{self as s3_xml, xmlns_tag};
|
||||||
|
|
||||||
|
@ -413,7 +413,7 @@ async fn get_copy_source(
|
||||||
let copy_source = percent_encoding::percent_decode_str(copy_source).decode_utf8()?;
|
let copy_source = percent_encoding::percent_decode_str(copy_source).decode_utf8()?;
|
||||||
|
|
||||||
let (source_bucket, source_key) = parse_bucket_key(©_source, None)?;
|
let (source_bucket, source_key) = parse_bucket_key(©_source, None)?;
|
||||||
let source_bucket_id = resolve_bucket(garage, &source_bucket.to_string(), api_key).await?;
|
let source_bucket_id = garage.bucket_helper().resolve_bucket(&source_bucket.to_string(), api_key).await?;
|
||||||
|
|
||||||
if !api_key.allow_read(&source_bucket_id) {
|
if !api_key.allow_read(&source_bucket_id) {
|
||||||
return Err(Error::Forbidden(format!(
|
return Err(Error::Forbidden(format!(
|
||||||
|
|
|
@ -15,7 +15,6 @@ use serde::Deserialize;
|
||||||
use garage_model::garage::Garage;
|
use garage_model::garage::Garage;
|
||||||
|
|
||||||
use crate::s3::error::*;
|
use crate::s3::error::*;
|
||||||
use crate::helpers::resolve_bucket;
|
|
||||||
use crate::s3::put::{get_headers, save_stream};
|
use crate::s3::put::{get_headers, save_stream};
|
||||||
use crate::s3::xml as s3_xml;
|
use crate::s3::xml as s3_xml;
|
||||||
use crate::signature::payload::{parse_date, verify_v4};
|
use crate::signature::payload::{parse_date, verify_v4};
|
||||||
|
@ -129,7 +128,7 @@ pub async fn handle_post_object(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let bucket_id = resolve_bucket(&garage, &bucket, &api_key).await?;
|
let bucket_id = garage.bucket_helper().resolve_bucket(&bucket, &api_key).await?;
|
||||||
|
|
||||||
if !api_key.allow_write(&bucket_id) {
|
if !api_key.allow_write(&bucket_id) {
|
||||||
return Err(Error::Forbidden(
|
return Err(Error::Forbidden(
|
||||||
|
|
|
@ -6,6 +6,7 @@ use garage_util::time::*;
|
||||||
|
|
||||||
use crate::bucket_alias_table::*;
|
use crate::bucket_alias_table::*;
|
||||||
use crate::bucket_table::*;
|
use crate::bucket_table::*;
|
||||||
|
use crate::key_table::*;
|
||||||
use crate::garage::Garage;
|
use crate::garage::Garage;
|
||||||
use crate::helper::error::*;
|
use crate::helper::error::*;
|
||||||
use crate::helper::key::KeyHelper;
|
use crate::helper::key::KeyHelper;
|
||||||
|
@ -49,6 +50,27 @@ impl<'a> BucketHelper<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::ptr_arg)]
|
||||||
|
pub async fn resolve_bucket(
|
||||||
|
&self,
|
||||||
|
bucket_name: &String,
|
||||||
|
api_key: &Key,
|
||||||
|
) -> Result<Uuid, Error> {
|
||||||
|
let api_key_params = api_key
|
||||||
|
.state
|
||||||
|
.as_option()
|
||||||
|
.ok_or_message("Key should not be deleted at this point")?;
|
||||||
|
|
||||||
|
if let Some(Some(bucket_id)) = api_key_params.local_aliases.get(bucket_name) {
|
||||||
|
Ok(*bucket_id)
|
||||||
|
} else {
|
||||||
|
Ok(self.
|
||||||
|
resolve_global_bucket_name(bucket_name)
|
||||||
|
.await?
|
||||||
|
.ok_or_else(|| Error::NoSuchBucket(bucket_name.to_string()))?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a Bucket if it is present in bucket table,
|
/// Returns a Bucket if it is present in bucket table,
|
||||||
/// even if it is in deleted state. Querying a non-existing
|
/// even if it is in deleted state. Querying a non-existing
|
||||||
/// bucket ID returns an internal error.
|
/// bucket ID returns an internal error.
|
||||||
|
|
Loading…
Reference in a new issue