diff --git a/doc/drafts/admin-api.md b/doc/drafts/admin-api.md index 14c4ec39..e8ed087d 100644 --- a/doc/drafts/admin-api.md +++ b/doc/drafts/admin-api.md @@ -457,6 +457,26 @@ Deletes a storage bucket. A bucket cannot be deleted if it is not empty. Warning: this will delete all aliases associated with the bucket! +### PutBucketWebsite `PUT /bucket/website?id=` + +Sets the website configuration for a bucket (this also enables website access for this bucket). + +Request body format: + +```json +{ + "indexDocument": "index.html", + "errorDocument": "404.html", +} +``` + +The field `errorDocument` is optional, if no error document is set a generic error message is displayed when errors happen. + + +### DeleteBucketWebsite `DELETE /bucket/website?id=` + +Deletes the website configuration for a bucket (disables website access for this bucket). + ## Operations on permissions for keys on buckets @@ -502,6 +522,7 @@ Request body format: Flags in `permissions` which have the value `true` will be deactivated. Other flags will remain unchanged. + ## Operations on bucket aliases ### GlobalAliasBucket `PUT /bucket/alias/global?id=&alias=` diff --git a/src/api/admin/api_server.rs b/src/api/admin/api_server.rs index a51d66e5..6f568024 100644 --- a/src/api/admin/api_server.rs +++ b/src/api/admin/api_server.rs @@ -144,6 +144,12 @@ impl ApiHandler for AdminApiServer { } Endpoint::CreateBucket => handle_create_bucket(&self.garage, req).await, Endpoint::DeleteBucket { id } => handle_delete_bucket(&self.garage, id).await, + Endpoint::PutBucketWebsite { id } => { + handle_put_bucket_website(&self.garage, id, req).await + } + Endpoint::DeleteBucketWebsite { id } => { + handle_delete_bucket_website(&self.garage, id).await + } // Bucket-key permissions Endpoint::BucketAllowKey => { handle_bucket_change_key_perm(&self.garage, req, true).await diff --git a/src/api/admin/bucket.rs b/src/api/admin/bucket.rs index cc37089a..3ad2c735 100644 --- a/src/api/admin/bucket.rs +++ b/src/api/admin/bucket.rs @@ -374,6 +374,61 @@ pub async fn handle_delete_bucket( .body(Body::empty())?) } +// ---- BUCKET WEBSITE CONFIGURATION ---- + +pub async fn handle_put_bucket_website( + garage: &Arc, + id: String, + req: Request, +) -> Result, Error> { + let req = parse_json_body::(req).await?; + let bucket_id = parse_bucket_id(&id)?; + + let mut bucket = garage + .bucket_helper() + .get_existing_bucket(bucket_id) + .await?; + + let state = bucket.state.as_option_mut().unwrap(); + state.website_config.update(Some(WebsiteConfig { + index_document: req.index_document, + error_document: req.error_document, + })); + + garage.bucket_table.insert(&bucket).await?; + + bucket_info_results(garage, bucket_id).await +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct PutBucketWebsiteRequest { + index_document: String, + #[serde(default)] + error_document: Option, +} + +pub async fn handle_delete_bucket_website( + garage: &Arc, + id: String, +) -> Result, Error> { + let bucket_id = parse_bucket_id(&id)?; + + let mut bucket = garage + .bucket_helper() + .get_existing_bucket(bucket_id) + .await?; + + let state = bucket.state.as_option_mut().unwrap(); + state.website_config.update(None); + + garage.bucket_table.insert(&bucket).await?; + + bucket_info_results(garage, bucket_id).await +} + +// ---- BUCKET/KEY PERMISSIONS ---- + pub async fn handle_bucket_change_key_perm( garage: &Arc, req: Request, @@ -426,6 +481,8 @@ struct BucketKeyPermChangeRequest { permissions: ApiBucketKeyPerm, } +// ---- BUCKET ALIASES ---- + pub async fn handle_global_alias_bucket( garage: &Arc, bucket_id: String, @@ -488,6 +545,8 @@ pub async fn handle_local_unalias_bucket( bucket_info_results(garage, bucket_id).await } +// ---- HELPER ---- + fn parse_bucket_id(id: &str) -> Result { let id_hex = hex::decode(&id).ok_or_bad_request("Invalid bucket id")?; Ok(Uuid::try_from(&id_hex).ok_or_bad_request("Invalid bucket id")?) diff --git a/src/api/admin/router.rs b/src/api/admin/router.rs index 6961becb..ae9e6681 100644 --- a/src/api/admin/router.rs +++ b/src/api/admin/router.rs @@ -46,6 +46,12 @@ pub enum Endpoint { DeleteBucket { id: String, }, + PutBucketWebsite { + id: String, + }, + DeleteBucketWebsite { + id: String, + }, // Bucket-Key Permissions BucketAllowKey, BucketDenyKey, @@ -103,6 +109,8 @@ impl Endpoint { GET "/bucket" => ListBuckets, POST "/bucket" => CreateBucket, DELETE "/bucket" if id => DeleteBucket (query::id), + PUT "/bucket/website" if id => PutBucketWebsite (query::id), + DELETE "/bucket/website" if id => DeleteBucketWebsite (query::id), // Bucket-key permissions POST "/bucket/allow" => BucketAllowKey, POST "/bucket/deny" => BucketDenyKey,