From: Casey Bodley Date: Mon, 28 Jul 2025 20:41:56 +0000 (-0400) Subject: rgw/s3: support paginated ListBuckets X-Git-Tag: v21.0.0~50^2~137^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=e0d797da7907cae4db6d0c9eec85b6809898b37d;p=ceph.git rgw/s3: support paginated ListBuckets at some point, aws added pagination support to ListBuckets[1] in the form of query params max-buckets and continuation-token RGWListBuckets already supported pagination for the swift api, so we only need to hook up the s3 request/response formats to use it Fixes: https://tracker.ceph.com/issues/72315 [1] https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html Signed-off-by: Casey Bodley --- diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 61c3c4107764..cbc5273afb8b 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -1611,6 +1611,37 @@ void RGWDeleteBucketReplication_ObjStore_S3::send_response() dump_start(s); } +int RGWListBuckets_ObjStore_S3::get_params(optional_yield y) +{ + auto continuation_token = s->info.args.get_optional("continuation-token"); + if (continuation_token) { + marker = *continuation_token; + } + + auto max_buckets = s->info.args.get_optional("max-buckets"); + if (max_buckets) { + std::optional value = ceph::parse(*max_buckets); + if (!value) { + s->err.message = "max-buckets must be an integer"; + return -EINVAL; + } + if (*value < 1 || *value > 10000) { + s->err.message = "max-buckets must be between 1 and 10000 inclusive"; + return -EINVAL; + } + limit = *value; + } + // TODO: support "prefix" and "bucket-region" params? + + // a request is only considered to be "paginated" if it specifies + // either "max-buckets" or "continuation-token" + if (!continuation_token && !max_buckets) { + limit = -1; /* no limit */ + } + + return 0; +} + void RGWListBuckets_ObjStore_S3::send_response_begin(bool has_buckets) { if (op_ret) @@ -1643,7 +1674,10 @@ void RGWListBuckets_ObjStore_S3::send_response_data(std::spanformatter->close_section(); + s->formatter->close_section(); // Buckets + if (!marker.empty()) { + s->formatter->dump_string("ContinuationToken", marker); + } list_all_buckets_end(s); rgw_flush_formatter_and_reset(s, s->formatter); } diff --git a/src/rgw/rgw_rest_s3.h b/src/rgw/rgw_rest_s3.h index 4996197692b5..337f9f4d11a4 100644 --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@ -131,10 +131,7 @@ public: RGWListBuckets_ObjStore_S3() {} ~RGWListBuckets_ObjStore_S3() override {} - int get_params(optional_yield y) override { - limit = -1; /* no limit */ - return 0; - } + int get_params(optional_yield y) override; void send_response_begin(bool has_buckets) override; void send_response_data(std::span buckets) override; void send_response_end() override;