diff options
Diffstat (limited to 'src/api')
30 files changed, 117 insertions, 89 deletions
diff --git a/src/api/admin/Cargo.toml b/src/api/admin/Cargo.toml index 02cbfc3d..804166b3 100644 --- a/src/api/admin/Cargo.toml +++ b/src/api/admin/Cargo.toml @@ -69,3 +69,6 @@ quick-xml.workspace = true opentelemetry.workspace = true opentelemetry-prometheus = { workspace = true, optional = true } prometheus = { workspace = true, optional = true } + +[features] +metrics = [ "opentelemetry-prometheus", "prometheus", "garage_api_common/metrics" ] diff --git a/src/api/admin/api_server.rs b/src/api/admin/api_server.rs index 7f8a51a6..e39fa1ba 100644 --- a/src/api/admin/api_server.rs +++ b/src/api/admin/api_server.rs @@ -21,6 +21,7 @@ use garage_util::error::Error as GarageError; use garage_util::socket_address::UnixOrTCPSocketAddress; use garage_api_common::generic_server::*; +use garage_api_common::helpers::*; use crate::bucket::*; use crate::cluster::*; @@ -28,7 +29,6 @@ use crate::error::*; use crate::key::*; use crate::router_v0; use crate::router_v1::{Authorization, Endpoint}; -use garage_api_common::helpers::*; pub type ResBody = BoxBody<Error>; diff --git a/src/api/admin/bucket.rs b/src/api/admin/bucket.rs index 3afed694..2537bfc9 100644 --- a/src/api/admin/bucket.rs +++ b/src/api/admin/bucket.rs @@ -17,11 +17,12 @@ use garage_model::permission::*; use garage_model::s3::mpu_table; use garage_model::s3::object_table::*; +use garage_api_common::common_error::CommonError; +use garage_api_common::helpers::*; + use crate::api_server::ResBody; use crate::error::*; use crate::key::ApiBucketKeyPerm; -use garage_api_common::common_error::CommonError; -use garage_api_common::helpers::*; pub async fn handle_list_buckets(garage: &Arc<Garage>) -> Result<Response<ResBody>, Error> { let buckets = garage diff --git a/src/api/admin/cluster.rs b/src/api/admin/cluster.rs index d4a645a2..ffa0fa71 100644 --- a/src/api/admin/cluster.rs +++ b/src/api/admin/cluster.rs @@ -12,9 +12,10 @@ use garage_rpc::layout; use garage_model::garage::Garage; +use garage_api_common::helpers::{json_ok_response, parse_json_body}; + use crate::api_server::ResBody; use crate::error::*; -use garage_api_common::helpers::{json_ok_response, parse_json_body}; pub async fn handle_get_cluster_status(garage: &Arc<Garage>) -> Result<Response<ResBody>, Error> { let layout = garage.system.cluster_layout(); diff --git a/src/api/admin/error.rs b/src/api/admin/error.rs index 1c962776..201f9b40 100644 --- a/src/api/admin/error.rs +++ b/src/api/admin/error.rs @@ -6,7 +6,7 @@ use hyper::{HeaderMap, StatusCode}; pub use garage_model::helper::error::Error as HelperError; -use garage_api_common::common_error::CommonError; +use garage_api_common::common_error::{commonErrorDerivative, CommonError}; pub use garage_api_common::common_error::{ CommonErrorDerivative, OkOrBadRequest, OkOrInternalError, }; @@ -18,7 +18,7 @@ use garage_api_common::helpers::*; pub enum Error { #[error(display = "{}", _0)] /// Error from common error - Common(CommonError), + Common(#[error(source)] CommonError), // Category: cannot process /// The API access key does not exist @@ -33,14 +33,7 @@ pub enum Error { KeyAlreadyExists(String), } -impl<T> From<T> for Error -where - CommonError: From<T>, -{ - fn from(err: T) -> Self { - Error::Common(CommonError::from(err)) - } -} +commonErrorDerivative!(Error); /// FIXME: helper errors are transformed into their corresponding variants /// in the Error struct, but in many case a helper error should be considered @@ -55,8 +48,6 @@ impl From<HelperError> for Error { } } -impl CommonErrorDerivative for Error {} - impl Error { fn code(&self) -> &'static str { match self { diff --git a/src/api/admin/key.rs b/src/api/admin/key.rs index 0c017a26..bebf3063 100644 --- a/src/api/admin/key.rs +++ b/src/api/admin/key.rs @@ -9,9 +9,10 @@ use garage_table::*; use garage_model::garage::Garage; use garage_model::key_table::*; +use garage_api_common::helpers::*; + use crate::api_server::ResBody; use crate::error::*; -use garage_api_common::helpers::*; pub async fn handle_list_keys(garage: &Arc<Garage>) -> Result<Response<ResBody>, Error> { let res = garage diff --git a/src/api/admin/router_v0.rs b/src/api/admin/router_v0.rs index 0c832fe1..9dd742ba 100644 --- a/src/api/admin/router_v0.rs +++ b/src/api/admin/router_v0.rs @@ -2,9 +2,10 @@ use std::borrow::Cow; use hyper::{Method, Request}; -use crate::error::*; use garage_api_common::router_macros::*; +use crate::error::*; + router_match! {@func /// List of all Admin API endpoints. diff --git a/src/api/admin/router_v1.rs b/src/api/admin/router_v1.rs index d9febd34..0b4901ea 100644 --- a/src/api/admin/router_v1.rs +++ b/src/api/admin/router_v1.rs @@ -2,9 +2,10 @@ use std::borrow::Cow; use hyper::{Method, Request}; +use garage_api_common::router_macros::*; + use crate::error::*; use crate::router_v0; -use garage_api_common::router_macros::*; pub enum Authorization { None, diff --git a/src/api/common/common_error.rs b/src/api/common/common_error.rs index 1e3f9feb..597a3511 100644 --- a/src/api/common/common_error.rs +++ b/src/api/common/common_error.rs @@ -57,6 +57,35 @@ pub enum CommonError { InvalidBucketName(String), } +#[macro_export] +macro_rules! commonErrorDerivative { + ( $error_struct: ident ) => { + impl From<garage_util::error::Error> for $error_struct { + fn from(err: garage_util::error::Error) -> Self { + Self::Common(CommonError::InternalError(err)) + } + } + impl From<http::Error> for $error_struct { + fn from(err: http::Error) -> Self { + Self::Common(CommonError::Http(err)) + } + } + impl From<hyper::Error> for $error_struct { + fn from(err: hyper::Error) -> Self { + Self::Common(CommonError::Hyper(err)) + } + } + impl From<hyper::header::ToStrError> for $error_struct { + fn from(err: hyper::header::ToStrError) -> Self { + Self::Common(CommonError::InvalidHeader(err)) + } + } + impl CommonErrorDerivative for $error_struct {} + }; +} + +pub use commonErrorDerivative; + impl CommonError { pub fn http_status_code(&self) -> StatusCode { match self { diff --git a/src/api/k2v/api_server.rs b/src/api/k2v/api_server.rs index 1fc512f9..0791c07d 100644 --- a/src/api/k2v/api_server.rs +++ b/src/api/k2v/api_server.rs @@ -12,17 +12,16 @@ use garage_util::socket_address::UnixOrTCPSocketAddress; use garage_model::garage::Garage; -use crate::error::*; use garage_api_common::generic_server::*; - +use garage_api_common::helpers::*; use garage_api_common::signature::verify_request; +use garage_api_s3::cors::*; use crate::batch::*; +use crate::error::*; use crate::index::*; use crate::item::*; use crate::router::Endpoint; -use garage_api_common::helpers::*; -use garage_api_s3::cors::*; pub use garage_api_common::signature::streaming::ReqBody; pub type ResBody = BoxBody<Error>; @@ -31,7 +30,7 @@ pub struct K2VApiServer { garage: Arc<Garage>, } -pub(crate) struct K2VApiEndpoint { +pub struct K2VApiEndpoint { bucket_name: String, endpoint: Endpoint, } diff --git a/src/api/k2v/batch.rs b/src/api/k2v/batch.rs index 1dd90456..c284dbd4 100644 --- a/src/api/k2v/batch.rs +++ b/src/api/k2v/batch.rs @@ -6,12 +6,13 @@ use garage_table::{EnumerationOrder, TableSchema}; use garage_model::k2v::item_table::*; -use crate::k2v::api_server::{ReqBody, ResBody}; -use crate::k2v::error::*; -use crate::k2v::item::parse_causality_token; -use crate::k2v::range::read_range; use garage_api_common::helpers::*; +use crate::api_server::{ReqBody, ResBody}; +use crate::error::*; +use crate::item::parse_causality_token; +use crate::range::read_range; + pub async fn handle_insert_batch( ctx: ReqCtx, req: Request<ReqBody>, diff --git a/src/api/k2v/error.rs b/src/api/k2v/error.rs index a4d3be1c..3cd0e6f7 100644 --- a/src/api/k2v/error.rs +++ b/src/api/k2v/error.rs @@ -2,7 +2,7 @@ use err_derive::Error; use hyper::header::HeaderValue; use hyper::{HeaderMap, StatusCode}; -use garage_api_common::common_error::CommonError; +use garage_api_common::common_error::{commonErrorDerivative, CommonError}; pub(crate) use garage_api_common::common_error::{helper_error_as_internal, pass_helper_error}; pub use garage_api_common::common_error::{ CommonErrorDerivative, OkOrBadRequest, OkOrInternalError, @@ -16,7 +16,7 @@ use garage_api_common::signature::error::Error as SignatureError; pub enum Error { #[error(display = "{}", _0)] /// Error from common error - Common(CommonError), + Common(#[error(source)] CommonError), // Category: cannot process /// Authorization Header Malformed @@ -44,16 +44,7 @@ pub enum Error { InvalidUtf8Str(#[error(source)] std::str::Utf8Error), } -impl<T> From<T> for Error -where - CommonError: From<T>, -{ - fn from(err: T) -> Self { - Error::Common(CommonError::from(err)) - } -} - -impl CommonErrorDerivative for Error {} +commonErrorDerivative!(Error); impl From<SignatureError> for Error { fn from(err: SignatureError) -> Self { diff --git a/src/api/k2v/index.rs b/src/api/k2v/index.rs index 423c1f97..fbfaad98 100644 --- a/src/api/k2v/index.rs +++ b/src/api/k2v/index.rs @@ -5,10 +5,11 @@ use garage_table::util::*; use garage_model::k2v::item_table::{BYTES, CONFLICTS, ENTRIES, VALUES}; +use garage_api_common::helpers::*; + use crate::api_server::ResBody; use crate::error::*; use crate::range::read_range; -use garage_api_common::helpers::*; pub async fn handle_read_index( ctx: ReqCtx, diff --git a/src/api/k2v/item.rs b/src/api/k2v/item.rs index 315f647c..4e28b499 100644 --- a/src/api/k2v/item.rs +++ b/src/api/k2v/item.rs @@ -6,9 +6,10 @@ use hyper::{Request, Response, StatusCode}; use garage_model::k2v::causality::*; use garage_model::k2v::item_table::*; +use garage_api_common::helpers::*; + use crate::api_server::{ReqBody, ResBody}; use crate::error::*; -use garage_api_common::helpers::*; pub const X_GARAGE_CAUSALITY_TOKEN: &str = "X-Garage-Causality-Token"; diff --git a/src/api/k2v/range.rs b/src/api/k2v/range.rs index fdb17e22..eb4738db 100644 --- a/src/api/k2v/range.rs +++ b/src/api/k2v/range.rs @@ -7,9 +7,10 @@ use std::sync::Arc; use garage_table::replication::TableShardedReplication; use garage_table::*; -use crate::error::*; use garage_api_common::helpers::key_after_prefix; +use crate::error::*; + /// Read range in a Garage table. /// Returns (entries, more?, nextStart) #[allow(clippy::too_many_arguments)] diff --git a/src/api/s3/api_server.rs b/src/api/s3/api_server.rs index d24f6a0c..a0dbf52c 100644 --- a/src/api/s3/api_server.rs +++ b/src/api/s3/api_server.rs @@ -14,15 +14,15 @@ use garage_util::socket_address::UnixOrTCPSocketAddress; use garage_model::garage::Garage; use garage_model::key_table::Key; -use crate::error::*; use garage_api_common::generic_server::*; - +use garage_api_common::helpers::*; use garage_api_common::signature::verify_request; use crate::bucket::*; use crate::copy::*; use crate::cors::*; use crate::delete::*; +use crate::error::*; use crate::get::*; use crate::lifecycle::*; use crate::list::*; @@ -31,7 +31,6 @@ use crate::post_object::handle_post_object; use crate::put::*; use crate::router::Endpoint; use crate::website::*; -use garage_api_common::helpers::*; pub use garage_api_common::signature::streaming::ReqBody; pub type ResBody = BoxBody<Error>; @@ -40,7 +39,7 @@ pub struct S3ApiServer { garage: Arc<Garage>, } -pub(crate) struct S3ApiEndpoint { +pub struct S3ApiEndpoint { bucket_name: Option<String>, endpoint: Endpoint, } diff --git a/src/api/s3/bucket.rs b/src/api/s3/bucket.rs index 09c5742b..0a192ba6 100644 --- a/src/api/s3/bucket.rs +++ b/src/api/s3/bucket.rs @@ -13,13 +13,14 @@ use garage_util::crdt::*; use garage_util::data::*; use garage_util::time::*; -use crate::api_server::{ReqBody, ResBody}; -use crate::error::*; -use crate::xml as s3_xml; use garage_api_common::common_error::CommonError; use garage_api_common::helpers::*; use garage_api_common::signature::verify_signed_content; +use crate::api_server::{ReqBody, ResBody}; +use crate::error::*; +use crate::xml as s3_xml; + pub fn handle_get_bucket_location(ctx: ReqCtx) -> Result<Response<ResBody>, Error> { let ReqCtx { garage, .. } = ctx; let loc = s3_xml::LocationConstraint { diff --git a/src/api/s3/copy.rs b/src/api/s3/copy.rs index 1a474fd0..e4992a18 100644 --- a/src/api/s3/copy.rs +++ b/src/api/s3/copy.rs @@ -20,6 +20,8 @@ use garage_model::s3::mpu_table::*; use garage_model::s3::object_table::*; use garage_model::s3::version_table::*; +use garage_api_common::helpers::*; + use crate::api_server::{ReqBody, ResBody}; use crate::checksum::*; use crate::encryption::EncryptionParams; @@ -28,7 +30,6 @@ use crate::get::full_object_byte_stream; use crate::multipart; use crate::put::{get_headers, save_stream, ChecksumMode, SaveStreamResult}; use crate::xml::{self as s3_xml, xmlns_tag}; -use garage_api_common::helpers::*; // -------- CopyObject --------- diff --git a/src/api/s3/cors.rs b/src/api/s3/cors.rs index ae8352c3..4bd81e32 100644 --- a/src/api/s3/cors.rs +++ b/src/api/s3/cors.rs @@ -15,16 +15,17 @@ use http_body_util::BodyExt; use serde::{Deserialize, Serialize}; -use crate::api_server::{ReqBody, ResBody}; -use crate::error::*; -use crate::xml::{to_xml_with_header, xmlns_tag, IntValue, Value}; +use garage_model::bucket_table::{Bucket, BucketParams, CorsRule as GarageCorsRule}; +use garage_model::garage::Garage; +use garage_util::data::*; + use garage_api_common::common_error::{helper_error_as_internal, CommonError}; use garage_api_common::helpers::*; use garage_api_common::signature::verify_signed_content; -use garage_model::bucket_table::{Bucket, BucketParams, CorsRule as GarageCorsRule}; -use garage_model::garage::Garage; -use garage_util::data::*; +use crate::api_server::{ReqBody, ResBody}; +use crate::error::*; +use crate::xml::{to_xml_with_header, xmlns_tag, IntValue, Value}; pub async fn handle_get_cors(ctx: ReqCtx) -> Result<Response<ResBody>, Error> { let ReqCtx { bucket_params, .. } = ctx; diff --git a/src/api/s3/delete.rs b/src/api/s3/delete.rs index 1711a9b4..b799e67a 100644 --- a/src/api/s3/delete.rs +++ b/src/api/s3/delete.rs @@ -5,12 +5,13 @@ use garage_util::data::*; use garage_model::s3::object_table::*; +use garage_api_common::helpers::*; +use garage_api_common::signature::verify_signed_content; + use crate::api_server::{ReqBody, ResBody}; use crate::error::*; use crate::put::next_timestamp; use crate::xml as s3_xml; -use garage_api_common::helpers::*; -use garage_api_common::signature::verify_signed_content; async fn handle_delete_internal(ctx: &ReqCtx, key: &str) -> Result<(Uuid, Uuid), Error> { let ReqCtx { diff --git a/src/api/s3/encryption.rs b/src/api/s3/encryption.rs index c54d487b..b38d7792 100644 --- a/src/api/s3/encryption.rs +++ b/src/api/s3/encryption.rs @@ -28,9 +28,10 @@ use garage_util::migrate::Migrate; use garage_model::garage::Garage; use garage_model::s3::object_table::{ObjectVersionEncryption, ObjectVersionMetaInner}; +use garage_api_common::common_error::*; + use crate::checksum::Md5Checksum; use crate::error::Error; -use garage_api_common::common_error::*; const X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM: HeaderName = HeaderName::from_static("x-amz-server-side-encryption-customer-algorithm"); diff --git a/src/api/s3/error.rs b/src/api/s3/error.rs index 77dc07c8..1bb8909c 100644 --- a/src/api/s3/error.rs +++ b/src/api/s3/error.rs @@ -8,23 +8,26 @@ use garage_model::helper::error::Error as HelperError; pub(crate) use garage_api_common::common_error::pass_helper_error; -use garage_api_common::common_error::{helper_error_as_internal, CommonError}; +use garage_api_common::common_error::{ + commonErrorDerivative, helper_error_as_internal, CommonError, +}; pub use garage_api_common::common_error::{ CommonErrorDerivative, OkOrBadRequest, OkOrInternalError, }; -use crate::xml as s3_xml; use garage_api_common::generic_server::ApiError; use garage_api_common::helpers::*; use garage_api_common::signature::error::Error as SignatureError; +use crate::xml as s3_xml; + /// Errors of this crate #[derive(Debug, Error)] pub enum Error { #[error(display = "{}", _0)] /// Error from common error - Common(CommonError), + Common(#[error(source)] CommonError), // Category: cannot process /// Authorization Header Malformed @@ -86,14 +89,7 @@ pub enum Error { NotImplemented(String), } -impl<T> From<T> for Error -where - CommonError: From<T>, -{ - fn from(err: T) -> Self { - Error::Common(CommonError::from(err)) - } -} +commonErrorDerivative!(Error); // Helper errors are always passed as internal errors by default. // To pass the specific error code back to the client, use `pass_helper_error`. @@ -103,8 +99,6 @@ impl From<HelperError> for Error { } } -impl CommonErrorDerivative for Error {} - impl From<roxmltree::Error> for Error { fn from(err: roxmltree::Error) -> Self { Self::InvalidXml(format!("{}", err)) diff --git a/src/api/s3/get.rs b/src/api/s3/get.rs index c4cd9d48..c2393a51 100644 --- a/src/api/s3/get.rs +++ b/src/api/s3/get.rs @@ -25,11 +25,12 @@ use garage_model::garage::Garage; use garage_model::s3::object_table::*; use garage_model::s3::version_table::*; +use garage_api_common::helpers::*; + use crate::api_server::ResBody; use crate::checksum::{add_checksum_response_headers, X_AMZ_CHECKSUM_MODE}; use crate::encryption::EncryptionParams; use crate::error::*; -use garage_api_common::helpers::*; const X_AMZ_MP_PARTS_COUNT: &str = "x-amz-mp-parts-count"; diff --git a/src/api/s3/lifecycle.rs b/src/api/s3/lifecycle.rs index da211585..c35047ed 100644 --- a/src/api/s3/lifecycle.rs +++ b/src/api/s3/lifecycle.rs @@ -5,11 +5,12 @@ use hyper::{Request, Response, StatusCode}; use serde::{Deserialize, Serialize}; +use garage_api_common::helpers::*; +use garage_api_common::signature::verify_signed_content; + use crate::api_server::{ReqBody, ResBody}; use crate::error::*; use crate::xml::{to_xml_with_header, xmlns_tag, IntValue, Value}; -use garage_api_common::helpers::*; -use garage_api_common::signature::verify_signed_content; use garage_model::bucket_table::{ parse_lifecycle_date, Bucket, LifecycleExpiration as GarageLifecycleExpiration, diff --git a/src/api/s3/list.rs b/src/api/s3/list.rs index de808c32..a5cc03b0 100644 --- a/src/api/s3/list.rs +++ b/src/api/s3/list.rs @@ -13,13 +13,14 @@ use garage_model::s3::object_table::*; use garage_table::EnumerationOrder; +use garage_api_common::encoding::*; +use garage_api_common::helpers::*; + use crate::api_server::{ReqBody, ResBody}; use crate::encryption::EncryptionParams; use crate::error::*; use crate::multipart as s3_multipart; use crate::xml as s3_xml; -use garage_api_common::encoding::*; -use garage_api_common::helpers::*; const DUMMY_NAME: &str = "Dummy Key"; const DUMMY_KEY: &str = "GKDummyKey"; diff --git a/src/api/s3/multipart.rs b/src/api/s3/multipart.rs index 047ed06a..fe39fc93 100644 --- a/src/api/s3/multipart.rs +++ b/src/api/s3/multipart.rs @@ -15,14 +15,15 @@ use garage_model::s3::mpu_table::*; use garage_model::s3::object_table::*; use garage_model::s3::version_table::*; +use garage_api_common::helpers::*; +use garage_api_common::signature::verify_signed_content; + use crate::api_server::{ReqBody, ResBody}; use crate::checksum::*; use crate::encryption::EncryptionParams; use crate::error::*; use crate::put::*; use crate::xml as s3_xml; -use garage_api_common::helpers::*; -use garage_api_common::signature::verify_signed_content; // ---- diff --git a/src/api/s3/post_object.rs b/src/api/s3/post_object.rs index 6416c523..2bcabf1d 100644 --- a/src/api/s3/post_object.rs +++ b/src/api/s3/post_object.rs @@ -16,6 +16,9 @@ use serde::Deserialize; use garage_model::garage::Garage; use garage_model::s3::object_table::*; +use garage_api_common::helpers::*; +use garage_api_common::signature::payload::{verify_v4, Authorization}; + use crate::api_server::ResBody; use crate::checksum::*; use crate::cors::*; @@ -23,8 +26,6 @@ use crate::encryption::EncryptionParams; use crate::error::*; use crate::put::{get_headers, save_stream, ChecksumMode}; use crate::xml as s3_xml; -use garage_api_common::helpers::*; -use garage_api_common::signature::payload::{verify_v4, Authorization}; pub async fn handle_post_object( garage: Arc<Garage>, diff --git a/src/api/s3/put.rs b/src/api/s3/put.rs index 47dcb8f7..530b4e7b 100644 --- a/src/api/s3/put.rs +++ b/src/api/s3/put.rs @@ -30,11 +30,12 @@ use garage_model::s3::block_ref_table::*; use garage_model::s3::object_table::*; use garage_model::s3::version_table::*; +use garage_api_common::helpers::*; + use crate::api_server::{ReqBody, ResBody}; use crate::checksum::*; use crate::encryption::EncryptionParams; use crate::error::*; -use garage_api_common::helpers::*; const PUT_BLOCKS_MAX_PARALLEL: usize = 3; diff --git a/src/api/s3/router.rs b/src/api/s3/router.rs index 94951e80..9de84b2b 100644 --- a/src/api/s3/router.rs +++ b/src/api/s3/router.rs @@ -3,10 +3,11 @@ use std::borrow::Cow; use hyper::header::HeaderValue; use hyper::{HeaderMap, Method, Request}; -use crate::error::*; use garage_api_common::helpers::Authorization; use garage_api_common::router_macros::{generateQueryParameters, router_match}; +use crate::error::*; + router_match! {@func /// List of all S3 API endpoints. diff --git a/src/api/s3/website.rs b/src/api/s3/website.rs index 46decccf..b55bb345 100644 --- a/src/api/s3/website.rs +++ b/src/api/s3/website.rs @@ -4,14 +4,15 @@ use http_body_util::BodyExt; use hyper::{Request, Response, StatusCode}; use serde::{Deserialize, Serialize}; -use crate::api_server::{ReqBody, ResBody}; -use crate::error::*; -use crate::xml::{to_xml_with_header, xmlns_tag, IntValue, Value}; +use garage_model::bucket_table::*; +use garage_util::data::*; + use garage_api_common::helpers::*; use garage_api_common::signature::verify_signed_content; -use garage_model::bucket_table::*; -use garage_util::data::*; +use crate::api_server::{ReqBody, ResBody}; +use crate::error::*; +use crate::xml::{to_xml_with_header, xmlns_tag, IntValue, Value}; pub async fn handle_get_website(ctx: ReqCtx) -> Result<Response<ResBody>, Error> { let ReqCtx { bucket_params, .. } = ctx; |