summaryrefslogtreecommitdiffstats
path: root/src/rgw/rgw_op.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/rgw/rgw_op.h')
-rw-r--r--src/rgw/rgw_op.h2346
1 files changed, 2346 insertions, 0 deletions
diff --git a/src/rgw/rgw_op.h b/src/rgw/rgw_op.h
new file mode 100644
index 00000000..e76b1258
--- /dev/null
+++ b/src/rgw/rgw_op.h
@@ -0,0 +1,2346 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+/**
+ * All operations via the rados gateway are carried out by
+ * small classes known as RGWOps. This class contains a req_state
+ * and each possible command is a subclass of this with a defined
+ * execute() method that does whatever the subclass name implies.
+ * These subclasses must be further subclassed (by interface type)
+ * to provide additional virtual methods such as send_response or get_params.
+ */
+
+#ifndef CEPH_RGW_OP_H
+#define CEPH_RGW_OP_H
+
+#include <limits.h>
+
+#include <array>
+#include <memory>
+#include <string>
+#include <set>
+#include <map>
+#include <vector>
+
+#include <boost/optional.hpp>
+#include <boost/utility/in_place_factory.hpp>
+#include <boost/function.hpp>
+
+#include "common/armor.h"
+#include "common/mime.h"
+#include "common/utf8.h"
+#include "common/ceph_json.h"
+#include "common/ceph_time.h"
+
+#include "rgw_common.h"
+#include "rgw_dmclock.h"
+#include "rgw_rados.h"
+#include "rgw_user.h"
+#include "rgw_bucket.h"
+#include "rgw_acl.h"
+#include "rgw_cors.h"
+#include "rgw_quota.h"
+#include "rgw_putobj.h"
+
+#include "rgw_lc.h"
+#include "rgw_torrent.h"
+#include "rgw_tag.h"
+#include "rgw_object_lock.h"
+#include "cls/lock/cls_lock_client.h"
+#include "cls/rgw/cls_rgw_client.h"
+
+#include "services/svc_sys_obj.h"
+
+#include "include/ceph_assert.h"
+
+using ceph::crypto::SHA1;
+
+struct req_state;
+class RGWOp;
+
+
+namespace rgw {
+namespace auth {
+namespace registry {
+
+class StrategyRegistry;
+
+}
+}
+}
+
+int rgw_op_get_bucket_policy_from_attr(CephContext *cct,
+ RGWRados *store,
+ RGWBucketInfo& bucket_info,
+ map<string, bufferlist>& bucket_attrs,
+ RGWAccessControlPolicy *policy);
+
+class RGWHandler {
+protected:
+ RGWRados* store;
+ struct req_state* s;
+
+ int do_init_permissions();
+ int do_read_permissions(RGWOp* op, bool only_bucket);
+
+public:
+ RGWHandler()
+ : store(nullptr),
+ s(nullptr) {
+ }
+ virtual ~RGWHandler();
+
+ virtual int init(RGWRados* store,
+ struct req_state* _s,
+ rgw::io::BasicClient* cio);
+
+ virtual int init_permissions(RGWOp*) {
+ return 0;
+ }
+
+ virtual int retarget(RGWOp* op, RGWOp** new_op) {
+ *new_op = op;
+ return 0;
+ }
+
+ virtual int read_permissions(RGWOp* op) = 0;
+ virtual int authorize(const DoutPrefixProvider* dpp) = 0;
+ virtual int postauth_init() = 0;
+ virtual int error_handler(int err_no, std::string* error_content);
+ virtual void dump(const string& code, const string& message) const {}
+
+ virtual bool supports_quota() {
+ return true;
+ }
+};
+
+
+
+void rgw_bucket_object_pre_exec(struct req_state *s);
+
+namespace dmc = rgw::dmclock;
+
+/**
+ * Provide the base class for all ops.
+ */
+class RGWOp : public DoutPrefixProvider {
+protected:
+ struct req_state *s;
+ RGWHandler *dialect_handler;
+ RGWRados *store;
+ RGWCORSConfiguration bucket_cors;
+ bool cors_exist;
+ RGWQuotaInfo bucket_quota;
+ RGWQuotaInfo user_quota;
+ int op_ret;
+ int do_aws4_auth_completion();
+
+ virtual int init_quota();
+
+public:
+ RGWOp()
+ : s(nullptr),
+ dialect_handler(nullptr),
+ store(nullptr),
+ cors_exist(false),
+ op_ret(0) {
+ }
+
+ virtual ~RGWOp() = default;
+
+ int get_ret() const { return op_ret; }
+
+ virtual int init_processing() {
+ if (dialect_handler->supports_quota()) {
+ op_ret = init_quota();
+ if (op_ret < 0)
+ return op_ret;
+ }
+
+ return 0;
+ }
+
+ virtual void init(RGWRados *store, struct req_state *s, RGWHandler *dialect_handler) {
+ this->store = store;
+ this->s = s;
+ this->dialect_handler = dialect_handler;
+ }
+ int read_bucket_cors();
+ bool generate_cors_headers(string& origin, string& method, string& headers, string& exp_headers, unsigned *max_age);
+
+ virtual int verify_params() { return 0; }
+ virtual bool prefetch_data() { return false; }
+
+ /* Authenticate requester -- verify its identity.
+ *
+ * NOTE: typically the procedure is common across all operations of the same
+ * dialect (S3, Swift API). However, there are significant exceptions in
+ * both APIs: browser uploads, /info and OPTIONS handlers. All of them use
+ * different, specific authentication schema driving the need for per-op
+ * authentication. The alternative is to duplicate parts of the method-
+ * dispatch logic in RGWHandler::authorize() and pollute it with a lot
+ * of special cases. */
+ virtual int verify_requester(const rgw::auth::StrategyRegistry& auth_registry) {
+ /* TODO(rzarzynski): rename RGWHandler::authorize to generic_authenticate. */
+ return dialect_handler->authorize(this);
+ }
+ virtual int verify_permission() = 0;
+ virtual int verify_op_mask();
+ virtual void pre_exec() {}
+ virtual void execute() = 0;
+ virtual void send_response() {}
+ virtual void complete() {
+ send_response();
+ }
+ virtual const char* name() const = 0;
+ virtual RGWOpType get_type() { return RGW_OP_UNKNOWN; }
+
+ virtual uint32_t op_mask() { return 0; }
+
+ virtual int error_handler(int err_no, string *error_content);
+
+ // implements DoutPrefixProvider
+ std::ostream& gen_prefix(std::ostream& out) const override;
+ CephContext* get_cct() const override { return s->cct; }
+ unsigned get_subsys() const override { return ceph_subsys_rgw; }
+
+ virtual dmc::client_id dmclock_client() { return dmc::client_id::metadata; }
+ virtual dmc::Cost dmclock_cost() { return 1; }
+};
+
+class RGWDefaultResponseOp : public RGWOp {
+public:
+ void send_response() override;
+};
+
+class RGWGetObj_Filter : public RGWGetDataCB
+{
+protected:
+ RGWGetObj_Filter *next{nullptr};
+public:
+ RGWGetObj_Filter() {}
+ explicit RGWGetObj_Filter(RGWGetObj_Filter *next): next(next) {}
+ ~RGWGetObj_Filter() override {}
+ /**
+ * Passes data through filter.
+ * Filter can modify content of bl.
+ * When bl_len == 0 , it means 'flush
+ */
+ int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) override {
+ if (next) {
+ return next->handle_data(bl, bl_ofs, bl_len);
+ }
+ return 0;
+ }
+ /**
+ * Flushes any cached data. Used by RGWGetObjFilter.
+ * Return logic same as handle_data.
+ */
+ virtual int flush() {
+ if (next) {
+ return next->flush();
+ }
+ return 0;
+ }
+ /**
+ * Allows filter to extend range required for successful filtering
+ */
+ virtual int fixup_range(off_t& ofs, off_t& end) {
+ if (next) {
+ return next->fixup_range(ofs, end);
+ }
+ return 0;
+ }
+};
+
+class RGWGetObj : public RGWOp {
+protected:
+ seed torrent; // get torrent
+ const char *range_str;
+ const char *if_mod;
+ const char *if_unmod;
+ const char *if_match;
+ const char *if_nomatch;
+ uint32_t mod_zone_id;
+ uint64_t mod_pg_ver;
+ off_t ofs;
+ uint64_t total_len;
+ off_t start;
+ off_t end;
+ ceph::real_time mod_time;
+ ceph::real_time lastmod;
+ ceph::real_time unmod_time;
+ ceph::real_time *mod_ptr;
+ ceph::real_time *unmod_ptr;
+ map<string, bufferlist> attrs;
+ bool get_data;
+ bool partial_content;
+ bool ignore_invalid_range;
+ bool range_parsed;
+ bool skip_manifest;
+ bool skip_decrypt{false};
+ rgw_obj obj;
+ utime_t gc_invalidate_time;
+ bool is_slo;
+ string lo_etag;
+ bool rgwx_stat; /* extended rgw stat operation */
+ string version_id;
+
+ // compression attrs
+ RGWCompressionInfo cs_info;
+ off_t first_block, last_block;
+ off_t q_ofs, q_len;
+ bool first_data;
+ uint64_t cur_ofs;
+ bufferlist waiting;
+ uint64_t action = 0;
+
+ bool get_retention;
+ bool get_legal_hold;
+
+ int init_common();
+public:
+ RGWGetObj() {
+ range_str = NULL;
+ if_mod = NULL;
+ if_unmod = NULL;
+ if_match = NULL;
+ if_nomatch = NULL;
+ mod_zone_id = 0;
+ mod_pg_ver = 0;
+ start = 0;
+ ofs = 0;
+ total_len = 0;
+ end = -1;
+ mod_ptr = NULL;
+ unmod_ptr = NULL;
+ get_data = false;
+ partial_content = false;
+ range_parsed = false;
+ skip_manifest = false;
+ is_slo = false;
+ first_block = 0;
+ last_block = 0;
+ q_ofs = 0;
+ q_len = 0;
+ first_data = true;
+ cur_ofs = 0;
+ get_retention = false;
+ get_legal_hold = false;
+ }
+
+ bool prefetch_data() override;
+
+ void set_get_data(bool get_data) {
+ this->get_data = get_data;
+ }
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+ int parse_range();
+ int read_user_manifest_part(
+ rgw_bucket& bucket,
+ const rgw_bucket_dir_entry& ent,
+ RGWAccessControlPolicy * const bucket_acl,
+ const boost::optional<rgw::IAM::Policy>& bucket_policy,
+ const off_t start_ofs,
+ const off_t end_ofs,
+ bool swift_slo);
+ int handle_user_manifest(const char *prefix);
+ int handle_slo_manifest(bufferlist& bl);
+
+ int get_data_cb(bufferlist& bl, off_t ofs, off_t len);
+
+ virtual int get_params() = 0;
+ virtual int send_response_data_error() = 0;
+ virtual int send_response_data(bufferlist& bl, off_t ofs, off_t len) = 0;
+
+ const char* name() const override { return "get_obj"; }
+ RGWOpType get_type() override { return RGW_OP_GET_OBJ; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+ virtual bool need_object_expiration() { return false; }
+ /**
+ * calculates filter used to decrypt RGW objects data
+ */
+ virtual int get_decrypt_filter(std::unique_ptr<RGWGetObj_Filter>* filter, RGWGetObj_Filter* cb, bufferlist* manifest_bl) {
+ *filter = nullptr;
+ return 0;
+ }
+ dmc::client_id dmclock_client() override { return dmc::client_id::data; }
+};
+
+class RGWGetObj_CB : public RGWGetObj_Filter
+{
+ RGWGetObj *op;
+public:
+ explicit RGWGetObj_CB(RGWGetObj *_op) : op(_op) {}
+ ~RGWGetObj_CB() override {}
+
+ int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) override {
+ return op->get_data_cb(bl, bl_ofs, bl_len);
+ }
+};
+
+class RGWGetObjTags : public RGWOp {
+ protected:
+ bufferlist tags_bl;
+ bool has_tags{false};
+ public:
+ int verify_permission() override;
+ void execute() override;
+ void pre_exec() override;
+
+ virtual void send_response_data(bufferlist& bl) = 0;
+ const char* name() const override { return "get_obj_tags"; }
+ virtual uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+ RGWOpType get_type() override { return RGW_OP_GET_OBJ_TAGGING; }
+
+};
+
+class RGWPutObjTags : public RGWOp {
+ protected:
+ bufferlist tags_bl;
+ public:
+ int verify_permission() override;
+ void execute() override;
+
+ virtual void send_response() override = 0;
+ virtual int get_params() = 0;
+ const char* name() const override { return "put_obj_tags"; }
+ virtual uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+ RGWOpType get_type() override { return RGW_OP_PUT_OBJ_TAGGING; }
+
+};
+
+class RGWDeleteObjTags: public RGWOp {
+ public:
+ void pre_exec() override;
+ int verify_permission() override;
+ void execute() override;
+
+ const char* name() const override { return "delete_obj_tags"; }
+ virtual uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
+ RGWOpType get_type() override { return RGW_OP_DELETE_OBJ_TAGGING;}
+};
+
+class RGWBulkDelete : public RGWOp {
+public:
+ struct acct_path_t {
+ std::string bucket_name;
+ rgw_obj_key obj_key;
+ };
+
+ struct fail_desc_t {
+ int err;
+ acct_path_t path;
+ };
+
+ class Deleter {
+ protected:
+ const DoutPrefixProvider * dpp;
+ unsigned int num_deleted;
+ unsigned int num_unfound;
+ std::list<fail_desc_t> failures;
+
+ RGWRados * const store;
+ req_state * const s;
+
+ public:
+ Deleter(const DoutPrefixProvider* dpp, RGWRados * const str, req_state * const s)
+ : dpp(dpp),
+ num_deleted(0),
+ num_unfound(0),
+ store(str),
+ s(s) {
+ }
+
+ unsigned int get_num_deleted() const {
+ return num_deleted;
+ }
+
+ unsigned int get_num_unfound() const {
+ return num_unfound;
+ }
+
+ const std::list<fail_desc_t> get_failures() const {
+ return failures;
+ }
+
+ bool verify_permission(RGWBucketInfo& binfo,
+ map<string, bufferlist>& battrs,
+ ACLOwner& bucket_owner /* out */);
+ bool delete_single(const acct_path_t& path);
+ bool delete_chunk(const std::list<acct_path_t>& paths);
+ };
+ /* End of Deleter subclass */
+
+ static const size_t MAX_CHUNK_ENTRIES = 1024;
+
+protected:
+ std::unique_ptr<Deleter> deleter;
+
+public:
+ RGWBulkDelete()
+ : deleter(nullptr) {
+ }
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_data(std::list<acct_path_t>& items,
+ bool * is_truncated) = 0;
+ void send_response() override = 0;
+
+ const char* name() const override { return "bulk_delete"; }
+ RGWOpType get_type() override { return RGW_OP_BULK_DELETE; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
+ dmc::client_id dmclock_client() override { return dmc::client_id::data; }
+};
+
+inline ostream& operator<<(ostream& out, const RGWBulkDelete::acct_path_t &o) {
+ return out << o.bucket_name << "/" << o.obj_key;
+}
+
+
+class RGWBulkUploadOp : public RGWOp {
+ boost::optional<RGWSysObjectCtx> dir_ctx;
+
+protected:
+ class fail_desc_t {
+ public:
+ fail_desc_t(const int err, std::string path)
+ : err(err),
+ path(std::move(path)) {
+ }
+
+ const int err;
+ const std::string path;
+ };
+
+ static constexpr std::array<int, 2> terminal_errors = {
+ { -EACCES, -EPERM }
+ };
+
+ /* FIXME: boost::container::small_vector<fail_desc_t, 4> failures; */
+ std::vector<fail_desc_t> failures;
+ size_t num_created;
+
+ class StreamGetter;
+ class DecoratedStreamGetter;
+ class AlignedStreamGetter;
+
+ virtual std::unique_ptr<StreamGetter> create_stream() = 0;
+ virtual void send_response() override = 0;
+
+ boost::optional<std::pair<std::string, rgw_obj_key>>
+ parse_path(const boost::string_ref& path);
+
+ std::pair<std::string, std::string>
+ handle_upload_path(struct req_state *s);
+
+ bool handle_file_verify_permission(RGWBucketInfo& binfo,
+ const rgw_obj& obj,
+ std::map<std::string, ceph::bufferlist>& battrs,
+ ACLOwner& bucket_owner /* out */);
+ int handle_file(boost::string_ref path,
+ size_t size,
+ AlignedStreamGetter& body);
+
+ int handle_dir_verify_permission();
+ int handle_dir(boost::string_ref path);
+
+public:
+ RGWBulkUploadOp()
+ : num_created(0) {
+ }
+
+ void init(RGWRados* const store,
+ struct req_state* const s,
+ RGWHandler* const h) override;
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ const char* name() const override { return "bulk_upload"; }
+
+ RGWOpType get_type() override {
+ return RGW_OP_BULK_UPLOAD;
+ }
+
+ uint32_t op_mask() override {
+ return RGW_OP_TYPE_WRITE;
+ }
+ dmc::client_id dmclock_client() override { return dmc::client_id::data; }
+}; /* RGWBulkUploadOp */
+
+
+class RGWBulkUploadOp::StreamGetter {
+public:
+ StreamGetter() = default;
+ virtual ~StreamGetter() = default;
+
+ virtual ssize_t get_at_most(size_t want, ceph::bufferlist& dst) = 0;
+ virtual ssize_t get_exactly(size_t want, ceph::bufferlist& dst) = 0;
+}; /* End of nested subclass StreamGetter */
+
+
+class RGWBulkUploadOp::DecoratedStreamGetter : public StreamGetter {
+ StreamGetter& decoratee;
+
+protected:
+ StreamGetter& get_decoratee() {
+ return decoratee;
+ }
+
+public:
+ explicit DecoratedStreamGetter(StreamGetter& decoratee)
+ : decoratee(decoratee) {
+ }
+ virtual ~DecoratedStreamGetter() = default;
+
+ ssize_t get_at_most(const size_t want, ceph::bufferlist& dst) override {
+ return get_decoratee().get_at_most(want, dst);
+ }
+
+ ssize_t get_exactly(const size_t want, ceph::bufferlist& dst) override {
+ return get_decoratee().get_exactly(want, dst);
+ }
+}; /* RGWBulkUploadOp::DecoratedStreamGetter */
+
+
+class RGWBulkUploadOp::AlignedStreamGetter
+ : public RGWBulkUploadOp::DecoratedStreamGetter {
+ size_t position;
+ size_t length;
+ size_t alignment;
+
+public:
+ template <typename U>
+ AlignedStreamGetter(const size_t position,
+ const size_t length,
+ const size_t alignment,
+ U&& decoratee)
+ : DecoratedStreamGetter(std::forward<U>(decoratee)),
+ position(position),
+ length(length),
+ alignment(alignment) {
+ }
+ virtual ~AlignedStreamGetter();
+ ssize_t get_at_most(size_t want, ceph::bufferlist& dst) override;
+ ssize_t get_exactly(size_t want, ceph::bufferlist& dst) override;
+}; /* RGWBulkUploadOp::AlignedStreamGetter */
+
+
+struct RGWUsageStats {
+ uint64_t bytes_used = 0;
+ uint64_t bytes_used_rounded = 0;
+ uint64_t buckets_count = 0;
+ uint64_t objects_count = 0;
+};
+
+#define RGW_LIST_BUCKETS_LIMIT_MAX 10000
+
+class RGWListBuckets : public RGWOp {
+protected:
+ bool sent_data;
+ std::string marker;
+ std::string end_marker;
+ int64_t limit;
+ uint64_t limit_max;
+ std::map<std::string, ceph::bufferlist> attrs;
+ bool is_truncated;
+
+ RGWUsageStats global_stats;
+ std::map<std::string, RGWUsageStats> policies_stats;
+
+ virtual uint64_t get_default_max() const {
+ return 1000;
+ }
+
+public:
+ RGWListBuckets()
+ : sent_data(false),
+ limit(RGW_LIST_BUCKETS_LIMIT_MAX),
+ limit_max(RGW_LIST_BUCKETS_LIMIT_MAX),
+ is_truncated(false) {
+ }
+
+ int verify_permission() override;
+ void execute() override;
+
+ virtual int get_params() = 0;
+ virtual void handle_listing_chunk(RGWUserBuckets&& buckets) {
+ /* The default implementation, used by e.g. S3, just generates a new
+ * part of listing and sends it client immediately. Swift can behave
+ * differently: when the reverse option is requested, all incoming
+ * instances of RGWUserBuckets are buffered and finally reversed. */
+ return send_response_data(buckets);
+ }
+ virtual void send_response_begin(bool has_buckets) = 0;
+ virtual void send_response_data(RGWUserBuckets& buckets) = 0;
+ virtual void send_response_end() = 0;
+ void send_response() override {}
+
+ virtual bool should_get_stats() { return false; }
+ virtual bool supports_account_metadata() { return false; }
+
+ const char* name() const override { return "list_buckets"; }
+ RGWOpType get_type() override { return RGW_OP_LIST_BUCKETS; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+}; // class RGWListBuckets
+
+class RGWGetUsage : public RGWOp {
+protected:
+ bool sent_data;
+ string start_date;
+ string end_date;
+ int show_log_entries;
+ int show_log_sum;
+ map<string, bool> categories;
+ map<rgw_user_bucket, rgw_usage_log_entry> usage;
+ map<string, rgw_usage_log_entry> summary_map;
+ map<string, cls_user_bucket_entry> buckets_usage;
+ cls_user_header header;
+public:
+ RGWGetUsage() : sent_data(false), show_log_entries(true), show_log_sum(true){
+ }
+
+ int verify_permission() override;
+ void execute() override;
+
+ virtual int get_params() = 0;
+ void send_response() override {}
+
+ virtual bool should_get_stats() { return false; }
+
+ const char* name() const override { return "get_usage"; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWStatAccount : public RGWOp {
+protected:
+ RGWUsageStats global_stats;
+ std::map<std::string, RGWUsageStats> policies_stats;
+
+public:
+ RGWStatAccount() = default;
+
+ int verify_permission() override;
+ void execute() override;
+
+ void send_response() override = 0;
+ const char* name() const override { return "stat_account"; }
+ RGWOpType get_type() override { return RGW_OP_STAT_ACCOUNT; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWListBucket : public RGWOp {
+protected:
+ RGWBucketEnt bucket;
+ string prefix;
+ rgw_obj_key marker;
+ rgw_obj_key next_marker;
+ rgw_obj_key end_marker;
+ string max_keys;
+ string delimiter;
+ string encoding_type;
+ bool list_versions;
+ int max;
+ vector<rgw_bucket_dir_entry> objs;
+ map<string, bool> common_prefixes;
+
+ int default_max;
+ bool is_truncated;
+ bool allow_unordered;
+
+ int shard_id;
+
+ int parse_max_keys();
+
+public:
+ RGWListBucket() : list_versions(false), max(0),
+ default_max(0), is_truncated(false),
+ allow_unordered(false), shard_id(-1) {}
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_params() = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "list_bucket"; }
+ RGWOpType get_type() override { return RGW_OP_LIST_BUCKET; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+ virtual bool need_container_stats() { return false; }
+};
+
+class RGWGetBucketLogging : public RGWOp {
+public:
+ RGWGetBucketLogging() {}
+ int verify_permission() override;
+ void execute() override { }
+
+ void send_response() override = 0;
+ const char* name() const override { return "get_bucket_logging"; }
+ RGWOpType get_type() override { return RGW_OP_GET_BUCKET_LOGGING; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWGetBucketLocation : public RGWOp {
+public:
+ RGWGetBucketLocation() {}
+ ~RGWGetBucketLocation() override {}
+ int verify_permission() override;
+ void execute() override { }
+
+ void send_response() override = 0;
+ const char* name() const override { return "get_bucket_location"; }
+ RGWOpType get_type() override { return RGW_OP_GET_BUCKET_LOCATION; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWGetBucketVersioning : public RGWOp {
+protected:
+ bool versioned{false};
+ bool versioning_enabled{false};
+ bool mfa_enabled{false};
+public:
+ RGWGetBucketVersioning() = default;
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ void send_response() override = 0;
+ const char* name() const override { return "get_bucket_versioning"; }
+ RGWOpType get_type() override { return RGW_OP_GET_BUCKET_VERSIONING; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+enum BucketVersionStatus {
+ VersioningStatusInvalid = -1,
+ VersioningNotChanged = 0,
+ VersioningEnabled = 1,
+ VersioningSuspended =2,
+};
+
+class RGWSetBucketVersioning : public RGWOp {
+protected:
+ int versioning_status;
+ bool mfa_set_status{false};
+ bool mfa_status{false};
+ bufferlist in_data;
+public:
+ RGWSetBucketVersioning() : versioning_status(VersioningNotChanged) {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_params() { return 0; }
+
+ void send_response() override = 0;
+ const char* name() const override { return "set_bucket_versioning"; }
+ RGWOpType get_type() override { return RGW_OP_SET_BUCKET_VERSIONING; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWGetBucketWebsite : public RGWOp {
+public:
+ RGWGetBucketWebsite() {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ void send_response() override = 0;
+ const char* name() const override { return "get_bucket_website"; }
+ RGWOpType get_type() override { return RGW_OP_GET_BUCKET_WEBSITE; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWSetBucketWebsite : public RGWOp {
+protected:
+ bufferlist in_data;
+ RGWBucketWebsiteConf website_conf;
+public:
+ RGWSetBucketWebsite() {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_params() { return 0; }
+
+ void send_response() override = 0;
+ const char* name() const override { return "set_bucket_website"; }
+ RGWOpType get_type() override { return RGW_OP_SET_BUCKET_WEBSITE; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWDeleteBucketWebsite : public RGWOp {
+public:
+ RGWDeleteBucketWebsite() {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ void send_response() override = 0;
+ const char* name() const override { return "delete_bucket_website"; }
+ RGWOpType get_type() override { return RGW_OP_SET_BUCKET_WEBSITE; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWStatBucket : public RGWOp {
+protected:
+ RGWBucketEnt bucket;
+
+public:
+ RGWStatBucket() {}
+ ~RGWStatBucket() override {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ void send_response() override = 0;
+ const char* name() const override { return "stat_bucket"; }
+ RGWOpType get_type() override { return RGW_OP_STAT_BUCKET; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWCreateBucket : public RGWOp {
+protected:
+ RGWAccessControlPolicy policy;
+ string location_constraint;
+ rgw_placement_rule placement_rule;
+ RGWBucketInfo info;
+ obj_version ep_objv;
+ bool has_cors;
+ bool relaxed_region_enforcement;
+ bool obj_lock_enabled;
+ RGWCORSConfiguration cors_config;
+ boost::optional<std::string> swift_ver_location;
+ map<string, buffer::list> attrs;
+ set<string> rmattr_names;
+
+ bufferlist in_data;
+
+ virtual bool need_metadata_upload() const { return false; }
+
+public:
+ RGWCreateBucket() : has_cors(false), relaxed_region_enforcement(false), obj_lock_enabled(false) {}
+
+ void emplace_attr(std::string&& key, buffer::list&& bl) {
+ attrs.emplace(std::move(key), std::move(bl)); /* key and bl are r-value refs */
+ }
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+ void init(RGWRados *store, struct req_state *s, RGWHandler *h) override {
+ RGWOp::init(store, s, h);
+ policy.set_ctx(s->cct);
+ relaxed_region_enforcement =
+ s->cct->_conf.get_val<bool>("rgw_relaxed_region_enforcement");
+ }
+ virtual int get_params() { return 0; }
+ void send_response() override = 0;
+ const char* name() const override { return "create_bucket"; }
+ RGWOpType get_type() override { return RGW_OP_CREATE_BUCKET; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWDeleteBucket : public RGWOp {
+protected:
+ RGWObjVersionTracker objv_tracker;
+
+public:
+ RGWDeleteBucket() {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ void send_response() override = 0;
+ const char* name() const override { return "delete_bucket"; }
+ RGWOpType get_type() override { return RGW_OP_DELETE_BUCKET; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
+};
+
+struct rgw_slo_entry {
+ string path;
+ string etag;
+ uint64_t size_bytes;
+
+ rgw_slo_entry() : size_bytes(0) {}
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ encode(path, bl);
+ encode(etag, bl);
+ encode(size_bytes, bl);
+ ENCODE_FINISH(bl);
+ }
+
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START(1, bl);
+ decode(path, bl);
+ decode(etag, bl);
+ decode(size_bytes, bl);
+ DECODE_FINISH(bl);
+ }
+
+ void decode_json(JSONObj *obj);
+};
+WRITE_CLASS_ENCODER(rgw_slo_entry)
+
+struct RGWSLOInfo {
+ vector<rgw_slo_entry> entries;
+ uint64_t total_size;
+
+ /* in memory only */
+ bufferlist raw_data;
+
+ RGWSLOInfo() : total_size(0) {}
+ ~RGWSLOInfo() {}
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ encode(entries, bl);
+ encode(total_size, bl);
+ ENCODE_FINISH(bl);
+ }
+
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START(1, bl);
+ decode(entries, bl);
+ decode(total_size, bl);
+ DECODE_FINISH(bl);
+ }
+};
+WRITE_CLASS_ENCODER(RGWSLOInfo)
+
+class RGWPutObj : public RGWOp {
+protected:
+ seed torrent;
+ off_t ofs;
+ const char *supplied_md5_b64;
+ const char *supplied_etag;
+ const char *if_match;
+ const char *if_nomatch;
+ std::string copy_source;
+ const char *copy_source_range;
+ RGWBucketInfo copy_source_bucket_info;
+ string copy_source_tenant_name;
+ string copy_source_bucket_name;
+ string copy_source_object_name;
+ string copy_source_version_id;
+ off_t copy_source_range_fst;
+ off_t copy_source_range_lst;
+ string etag;
+ bool chunked_upload;
+ RGWAccessControlPolicy policy;
+ std::unique_ptr <RGWObjTags> obj_tags;
+ const char *dlo_manifest;
+ RGWSLOInfo *slo_info;
+ map<string, bufferlist> attrs;
+ ceph::real_time mtime;
+ uint64_t olh_epoch;
+ string version_id;
+ bufferlist bl_aux;
+ map<string, string> crypt_http_responses;
+ string user_data;
+
+ std::string multipart_upload_id;
+ std::string multipart_part_str;
+ int multipart_part_num = 0;
+
+ boost::optional<ceph::real_time> delete_at;
+ //append obj
+ bool append;
+ uint64_t position;
+ uint64_t cur_accounted_size;
+
+ //object lock
+ RGWObjectRetention *obj_retention;
+ RGWObjectLegalHold *obj_legal_hold;
+
+public:
+ RGWPutObj() : ofs(0),
+ supplied_md5_b64(NULL),
+ supplied_etag(NULL),
+ if_match(NULL),
+ if_nomatch(NULL),
+ copy_source_range(NULL),
+ copy_source_range_fst(0),
+ copy_source_range_lst(0),
+ chunked_upload(0),
+ dlo_manifest(NULL),
+ slo_info(NULL),
+ olh_epoch(0),
+ append(false),
+ position(0),
+ cur_accounted_size(0),
+ obj_retention(nullptr),
+ obj_legal_hold(nullptr) {}
+
+ ~RGWPutObj() override {
+ delete slo_info;
+ delete obj_retention;
+ delete obj_legal_hold;
+ }
+
+ void init(RGWRados *store, struct req_state *s, RGWHandler *h) override {
+ RGWOp::init(store, s, h);
+ policy.set_ctx(s->cct);
+ }
+
+ void emplace_attr(std::string&& key, buffer::list&& bl) {
+ attrs.emplace(std::move(key), std::move(bl)); /* key and bl are r-value refs */
+ }
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ /* this is for cases when copying data from other object */
+ virtual int get_decrypt_filter(std::unique_ptr<RGWGetObj_Filter>* filter,
+ RGWGetObj_Filter* cb,
+ map<string, bufferlist>& attrs,
+ bufferlist* manifest_bl) {
+ *filter = nullptr;
+ return 0;
+ }
+ virtual int get_encrypt_filter(std::unique_ptr<rgw::putobj::DataProcessor> *filter,
+ rgw::putobj::DataProcessor *cb) {
+ return 0;
+ }
+
+ int get_data_cb(bufferlist& bl, off_t bl_ofs, off_t bl_len);
+ int get_data(const off_t fst, const off_t lst, bufferlist& bl);
+
+ virtual int get_params() = 0;
+ virtual int get_data(bufferlist& bl) = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "put_obj"; }
+ RGWOpType get_type() override { return RGW_OP_PUT_OBJ; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+ dmc::client_id dmclock_client() override { return dmc::client_id::data; }
+};
+
+class RGWPostObj : public RGWOp {
+protected:
+ off_t min_len;
+ off_t max_len;
+ int len;
+ off_t ofs;
+ const char *supplied_md5_b64;
+ const char *supplied_etag;
+ string etag;
+ RGWAccessControlPolicy policy;
+ map<string, bufferlist> attrs;
+ boost::optional<ceph::real_time> delete_at;
+
+ /* Must be called after get_data() or the result is undefined. */
+ virtual std::string get_current_filename() const = 0;
+ virtual std::string get_current_content_type() const = 0;
+ virtual bool is_next_file_to_upload() {
+ return false;
+ }
+public:
+ RGWPostObj() : min_len(0),
+ max_len(LLONG_MAX),
+ len(0),
+ ofs(0),
+ supplied_md5_b64(nullptr),
+ supplied_etag(nullptr) {
+ }
+
+ void emplace_attr(std::string&& key, buffer::list&& bl) {
+ attrs.emplace(std::move(key), std::move(bl)); /* key and bl are r-value refs */
+ }
+
+ void init(RGWRados *store, struct req_state *s, RGWHandler *h) override {
+ RGWOp::init(store, s, h);
+ policy.set_ctx(s->cct);
+ }
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_encrypt_filter(std::unique_ptr<rgw::putobj::DataProcessor> *filter,
+ rgw::putobj::DataProcessor *cb) {
+ return 0;
+ }
+ virtual int get_params() = 0;
+ virtual int get_data(ceph::bufferlist& bl, bool& again) = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "post_obj"; }
+ RGWOpType get_type() override { return RGW_OP_POST_OBJ; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+ dmc::client_id dmclock_client() override { return dmc::client_id::data; }
+};
+
+class RGWPutMetadataAccount : public RGWOp {
+protected:
+ std::set<std::string> rmattr_names;
+ std::map<std::string, bufferlist> attrs, orig_attrs;
+ std::map<int, std::string> temp_url_keys;
+ RGWQuotaInfo new_quota;
+ bool new_quota_extracted;
+
+ RGWObjVersionTracker acct_op_tracker;
+
+ RGWAccessControlPolicy policy;
+ bool has_policy;
+
+public:
+ RGWPutMetadataAccount()
+ : new_quota_extracted(false),
+ has_policy(false) {
+ }
+
+ void init(RGWRados *store, struct req_state *s, RGWHandler *h) override {
+ RGWOp::init(store, s, h);
+ policy.set_ctx(s->cct);
+ }
+ int init_processing() override;
+ int verify_permission() override;
+ void pre_exec() override { }
+ void execute() override;
+
+ virtual int get_params() = 0;
+ void send_response() override = 0;
+ virtual void filter_out_temp_url(map<string, bufferlist>& add_attrs,
+ const set<string>& rmattr_names,
+ map<int, string>& temp_url_keys);
+ const char* name() const override { return "put_account_metadata"; }
+ RGWOpType get_type() override { return RGW_OP_PUT_METADATA_ACCOUNT; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWPutMetadataBucket : public RGWOp {
+protected:
+ map<string, buffer::list> attrs;
+ set<string> rmattr_names;
+ bool has_policy, has_cors;
+ uint32_t policy_rw_mask;
+ RGWAccessControlPolicy policy;
+ RGWCORSConfiguration cors_config;
+ rgw_placement_rule placement_rule;
+ boost::optional<std::string> swift_ver_location;
+
+public:
+ RGWPutMetadataBucket()
+ : has_policy(false), has_cors(false), policy_rw_mask(0)
+ {}
+
+ void emplace_attr(std::string&& key, buffer::list&& bl) {
+ attrs.emplace(std::move(key), std::move(bl)); /* key and bl are r-value refs */
+ }
+
+ void init(RGWRados *store, struct req_state *s, RGWHandler *h) override {
+ RGWOp::init(store, s, h);
+ policy.set_ctx(s->cct);
+ }
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_params() = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "put_bucket_metadata"; }
+ RGWOpType get_type() override { return RGW_OP_PUT_METADATA_BUCKET; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWPutMetadataObject : public RGWOp {
+protected:
+ RGWAccessControlPolicy policy;
+ boost::optional<ceph::real_time> delete_at;
+ const char *dlo_manifest;
+
+public:
+ RGWPutMetadataObject()
+ : dlo_manifest(NULL)
+ {}
+
+ void init(RGWRados *store, struct req_state *s, RGWHandler *h) override {
+ RGWOp::init(store, s, h);
+ policy.set_ctx(s->cct);
+ }
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_params() = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "put_obj_metadata"; }
+ RGWOpType get_type() override { return RGW_OP_PUT_METADATA_OBJECT; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+ virtual bool need_object_expiration() { return false; }
+};
+
+class RGWDeleteObj : public RGWOp {
+protected:
+ bool delete_marker;
+ bool multipart_delete;
+ string version_id;
+ ceph::real_time unmod_since; /* if unmodified since */
+ bool no_precondition_error;
+ std::unique_ptr<RGWBulkDelete::Deleter> deleter;
+ bool bypass_perm;
+ bool bypass_governance_mode;
+
+public:
+ RGWDeleteObj()
+ : delete_marker(false),
+ multipart_delete(false),
+ no_precondition_error(false),
+ deleter(nullptr),
+ bypass_perm(true),
+ bypass_governance_mode(false) {
+ }
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+ int handle_slo_manifest(bufferlist& bl);
+
+ virtual int get_params() { return 0; }
+ void send_response() override = 0;
+ const char* name() const override { return "delete_obj"; }
+ RGWOpType get_type() override { return RGW_OP_DELETE_OBJ; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
+ virtual bool need_object_expiration() { return false; }
+ dmc::client_id dmclock_client() override { return dmc::client_id::data; }
+};
+
+class RGWCopyObj : public RGWOp {
+protected:
+ RGWAccessControlPolicy dest_policy;
+ const char *if_mod;
+ const char *if_unmod;
+ const char *if_match;
+ const char *if_nomatch;
+ // Required or it is not a copy operation
+ std::string_view copy_source;
+ // Not actually required
+ std::optional<std::string_view> md_directive;
+
+ off_t ofs;
+ off_t len;
+ off_t end;
+ ceph::real_time mod_time;
+ ceph::real_time unmod_time;
+ ceph::real_time *mod_ptr;
+ ceph::real_time *unmod_ptr;
+ map<string, buffer::list> attrs;
+ string src_tenant_name, src_bucket_name;
+ rgw_bucket src_bucket;
+ rgw_obj_key src_object;
+ string dest_tenant_name, dest_bucket_name;
+ rgw_bucket dest_bucket;
+ string dest_object;
+ ceph::real_time src_mtime;
+ ceph::real_time mtime;
+ RGWRados::AttrsMod attrs_mod;
+ RGWBucketInfo src_bucket_info;
+ RGWBucketInfo dest_bucket_info;
+ string source_zone;
+ string etag;
+
+ off_t last_ofs;
+
+ string version_id;
+ uint64_t olh_epoch;
+
+ boost::optional<ceph::real_time> delete_at;
+ bool copy_if_newer;
+
+ bool need_to_check_storage_class = false;
+
+ int init_common();
+
+public:
+ RGWCopyObj() {
+ if_mod = NULL;
+ if_unmod = NULL;
+ if_match = NULL;
+ if_nomatch = NULL;
+ ofs = 0;
+ len = 0;
+ end = -1;
+ mod_ptr = NULL;
+ unmod_ptr = NULL;
+ attrs_mod = RGWRados::ATTRSMOD_NONE;
+ last_ofs = 0;
+ olh_epoch = 0;
+ copy_if_newer = false;
+ }
+
+ static bool parse_copy_location(const boost::string_view& src,
+ string& bucket_name,
+ rgw_obj_key& object);
+
+ void emplace_attr(std::string&& key, buffer::list&& bl) {
+ attrs.emplace(std::move(key), std::move(bl));
+ }
+
+ void init(RGWRados *store, struct req_state *s, RGWHandler *h) override {
+ RGWOp::init(store, s, h);
+ dest_policy.set_ctx(s->cct);
+ }
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+ void progress_cb(off_t ofs);
+
+ virtual int check_storage_class(const rgw_placement_rule& src_placement) {
+ return 0;
+ }
+
+ virtual int init_dest_policy() { return 0; }
+ virtual int get_params() = 0;
+ virtual void send_partial_response(off_t ofs) {}
+ void send_response() override = 0;
+ const char* name() const override { return "copy_obj"; }
+ RGWOpType get_type() override { return RGW_OP_COPY_OBJ; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+ dmc::client_id dmclock_client() override { return dmc::client_id::data; }
+};
+
+class RGWGetACLs : public RGWOp {
+protected:
+ string acls;
+
+public:
+ RGWGetACLs() {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ void send_response() override = 0;
+ const char* name() const override { return "get_acls"; }
+ RGWOpType get_type() override { return RGW_OP_GET_ACLS; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWPutACLs : public RGWOp {
+protected:
+ bufferlist data;
+ ACLOwner owner;
+
+public:
+ RGWPutACLs() {}
+ ~RGWPutACLs() override {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_policy_from_state(RGWRados *store, struct req_state *s, stringstream& ss) { return 0; }
+ virtual int get_params() = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "put_acls"; }
+ RGWOpType get_type() override { return RGW_OP_PUT_ACLS; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWGetLC : public RGWOp {
+protected:
+
+public:
+ RGWGetLC() { }
+ ~RGWGetLC() override { }
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override = 0;
+
+ void send_response() override = 0;
+ const char* name() const override { return "get_lifecycle"; }
+ RGWOpType get_type() override { return RGW_OP_GET_LC; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWPutLC : public RGWOp {
+protected:
+ bufferlist data;
+ const char *content_md5;
+ string cookie;
+
+public:
+ RGWPutLC() {
+ content_md5 = nullptr;
+ }
+ ~RGWPutLC() override {}
+
+ void init(RGWRados *store, struct req_state *s, RGWHandler *dialect_handler) override {
+#define COOKIE_LEN 16
+ char buf[COOKIE_LEN + 1];
+
+ RGWOp::init(store, s, dialect_handler);
+ gen_rand_alphanumeric(s->cct, buf, sizeof(buf) - 1);
+ cookie = buf;
+ }
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+// virtual int get_policy_from_state(RGWRados *store, struct req_state *s, stringstream& ss) { return 0; }
+ virtual int get_params() = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "put_lifecycle"; }
+ RGWOpType get_type() override { return RGW_OP_PUT_LC; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWDeleteLC : public RGWOp {
+protected:
+ size_t len;
+ char *data;
+
+public:
+ RGWDeleteLC() {
+ len = 0;
+ data = NULL;
+ }
+ ~RGWDeleteLC() override {
+ free(data);
+ }
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ void send_response() override = 0;
+ const char* name() const override { return "delete_lifecycle"; }
+ RGWOpType get_type() override { return RGW_OP_DELETE_LC; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWGetCORS : public RGWOp {
+protected:
+
+public:
+ RGWGetCORS() {}
+
+ int verify_permission() override;
+ void execute() override;
+
+ void send_response() override = 0;
+ const char* name() const override { return "get_cors"; }
+ RGWOpType get_type() override { return RGW_OP_GET_CORS; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWPutCORS : public RGWOp {
+protected:
+ bufferlist cors_bl;
+ bufferlist in_data;
+
+public:
+ RGWPutCORS() {}
+ ~RGWPutCORS() override {}
+
+ int verify_permission() override;
+ void execute() override;
+
+ virtual int get_params() = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "put_cors"; }
+ RGWOpType get_type() override { return RGW_OP_PUT_CORS; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWDeleteCORS : public RGWOp {
+protected:
+
+public:
+ RGWDeleteCORS() {}
+
+ int verify_permission() override;
+ void execute() override;
+
+ void send_response() override = 0;
+ const char* name() const override { return "delete_cors"; }
+ RGWOpType get_type() override { return RGW_OP_DELETE_CORS; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWOptionsCORS : public RGWOp {
+protected:
+ RGWCORSRule *rule;
+ const char *origin, *req_hdrs, *req_meth;
+
+public:
+ RGWOptionsCORS() : rule(NULL), origin(NULL),
+ req_hdrs(NULL), req_meth(NULL) {
+ }
+
+ int verify_permission() override {return 0;}
+ int validate_cors_request(RGWCORSConfiguration *cc);
+ void execute() override;
+ void get_response_params(string& allowed_hdrs, string& exp_hdrs, unsigned *max_age);
+ void send_response() override = 0;
+ const char* name() const override { return "options_cors"; }
+ RGWOpType get_type() override { return RGW_OP_OPTIONS_CORS; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWGetRequestPayment : public RGWOp {
+protected:
+ bool requester_pays;
+
+public:
+ RGWGetRequestPayment() : requester_pays(0) {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ void send_response() override = 0;
+ const char* name() const override { return "get_request_payment"; }
+ RGWOpType get_type() override { return RGW_OP_GET_REQUEST_PAYMENT; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWSetRequestPayment : public RGWOp {
+protected:
+ bool requester_pays;
+ bufferlist in_data;
+public:
+ RGWSetRequestPayment() : requester_pays(false) {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_params() { return 0; }
+
+ void send_response() override = 0;
+ const char* name() const override { return "set_request_payment"; }
+ RGWOpType get_type() override { return RGW_OP_SET_REQUEST_PAYMENT; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWInitMultipart : public RGWOp {
+protected:
+ string upload_id;
+ RGWAccessControlPolicy policy;
+
+public:
+ RGWInitMultipart() {}
+
+ void init(RGWRados *store, struct req_state *s, RGWHandler *h) override {
+ RGWOp::init(store, s, h);
+ policy.set_ctx(s->cct);
+ }
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_params() = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "init_multipart"; }
+ RGWOpType get_type() override { return RGW_OP_INIT_MULTIPART; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+ virtual int prepare_encryption(map<string, bufferlist>& attrs) { return 0; }
+};
+
+class RGWCompleteMultipart : public RGWOp {
+protected:
+ string upload_id;
+ string etag;
+ string version_id;
+ bufferlist data;
+
+ struct MPSerializer {
+ librados::IoCtx ioctx;
+ rados::cls::lock::Lock lock;
+ librados::ObjectWriteOperation op;
+ std::string oid;
+ bool locked;
+
+ MPSerializer() : lock("RGWCompleteMultipart"), locked(false)
+ {}
+
+ int try_lock(const std::string& oid, utime_t dur);
+
+ int unlock() {
+ return lock.unlock(&ioctx, oid);
+ }
+
+ void clear_locked() {
+ locked = false;
+ }
+ } serializer;
+
+public:
+ RGWCompleteMultipart() {}
+ ~RGWCompleteMultipart() override {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+ void complete() override;
+
+ virtual int get_params() = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "complete_multipart"; }
+ RGWOpType get_type() override { return RGW_OP_COMPLETE_MULTIPART; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWAbortMultipart : public RGWOp {
+public:
+ RGWAbortMultipart() {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ void send_response() override = 0;
+ const char* name() const override { return "abort_multipart"; }
+ RGWOpType get_type() override { return RGW_OP_ABORT_MULTIPART; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
+};
+
+class RGWListMultipart : public RGWOp {
+protected:
+ string upload_id;
+ map<uint32_t, RGWUploadPartInfo> parts;
+ int max_parts;
+ int marker;
+ RGWAccessControlPolicy policy;
+ bool truncated;
+
+public:
+ RGWListMultipart() {
+ max_parts = 1000;
+ marker = 0;
+ truncated = false;
+ }
+
+ void init(RGWRados *store, struct req_state *s, RGWHandler *h) override {
+ RGWOp::init(store, s, h);
+ policy = RGWAccessControlPolicy(s->cct);
+ }
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_params() = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "list_multipart"; }
+ RGWOpType get_type() override { return RGW_OP_LIST_MULTIPART; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+struct RGWMultipartUploadEntry {
+ rgw_bucket_dir_entry obj;
+ RGWMPObj mp;
+
+ friend std::ostream& operator<<(std::ostream& out,
+ const RGWMultipartUploadEntry& e) {
+ constexpr char quote = '"';
+ return out << "RGWMultipartUploadEntry{ obj.key=" <<
+ quote << e.obj.key << quote << " mp=" << e.mp << " }";
+ }
+};
+
+class RGWListBucketMultiparts : public RGWOp {
+protected:
+ string prefix;
+ RGWMPObj marker;
+ RGWMultipartUploadEntry next_marker;
+ int max_uploads;
+ string delimiter;
+ vector<RGWMultipartUploadEntry> uploads;
+ map<string, bool> common_prefixes;
+ bool is_truncated;
+ int default_max;
+
+public:
+ RGWListBucketMultiparts() {
+ max_uploads = 0;
+ is_truncated = false;
+ default_max = 0;
+ }
+
+ void init(RGWRados *store, struct req_state *s, RGWHandler *h) override {
+ RGWOp::init(store, s, h);
+ max_uploads = default_max;
+ }
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_params() = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "list_bucket_multiparts"; }
+ RGWOpType get_type() override { return RGW_OP_LIST_BUCKET_MULTIPARTS; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+
+class RGWGetCrossDomainPolicy : public RGWOp {
+public:
+ RGWGetCrossDomainPolicy() = default;
+ ~RGWGetCrossDomainPolicy() override = default;
+
+ int verify_permission() override {
+ return 0;
+ }
+
+ void execute() override {
+ op_ret = 0;
+ }
+
+ const char* name() const override { return "get_crossdomain_policy"; }
+
+ RGWOpType get_type() override {
+ return RGW_OP_GET_CROSS_DOMAIN_POLICY;
+ }
+
+ uint32_t op_mask() override {
+ return RGW_OP_TYPE_READ;
+ }
+};
+
+
+class RGWGetHealthCheck : public RGWOp {
+public:
+ RGWGetHealthCheck() = default;
+ ~RGWGetHealthCheck() override = default;
+
+ int verify_permission() override {
+ return 0;
+ }
+
+ void execute() override;
+
+ const char* name() const override { return "get_health_check"; }
+
+ RGWOpType get_type() override {
+ return RGW_OP_GET_HEALTH_CHECK;
+ }
+
+ uint32_t op_mask() override {
+ return RGW_OP_TYPE_READ;
+ }
+};
+
+
+class RGWDeleteMultiObj : public RGWOp {
+protected:
+ bufferlist data;
+ rgw_bucket bucket;
+ bool quiet;
+ bool status_dumped;
+ bool acl_allowed = false;
+
+public:
+ RGWDeleteMultiObj() {
+ quiet = false;
+ status_dumped = false;
+ }
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_params() = 0;
+ virtual void send_status() = 0;
+ virtual void begin_response() = 0;
+ virtual void send_partial_response(rgw_obj_key& key, bool delete_marker,
+ const string& marker_version_id, int ret) = 0;
+ virtual void end_response() = 0;
+ const char* name() const override { return "multi_object_delete"; }
+ RGWOpType get_type() override { return RGW_OP_DELETE_MULTI_OBJ; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
+};
+
+class RGWInfo: public RGWOp {
+public:
+ RGWInfo() = default;
+ ~RGWInfo() override = default;
+
+ int verify_permission() override { return 0; }
+ const char* name() const override { return "get info"; }
+ RGWOpType get_type() override { return RGW_OP_GET_INFO; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+extern int rgw_build_bucket_policies(RGWRados* store, struct req_state* s);
+extern int rgw_build_object_policies(RGWRados *store, struct req_state *s,
+ bool prefetch_data);
+extern void rgw_build_iam_environment(RGWRados* store,
+ struct req_state* s);
+extern vector<rgw::IAM::Policy> get_iam_user_policy_from_attr(CephContext* cct,
+ RGWRados* store,
+ map<string, bufferlist>& attrs,
+ const string& tenant);
+
+static inline int get_system_versioning_params(req_state *s,
+ uint64_t *olh_epoch,
+ string *version_id)
+{
+ if (!s->system_request) {
+ return 0;
+ }
+
+ if (olh_epoch) {
+ string epoch_str = s->info.args.get(RGW_SYS_PARAM_PREFIX "versioned-epoch");
+ if (!epoch_str.empty()) {
+ string err;
+ *olh_epoch = strict_strtol(epoch_str.c_str(), 10, &err);
+ if (!err.empty()) {
+ lsubdout(s->cct, rgw, 0) << "failed to parse versioned-epoch param"
+ << dendl;
+ return -EINVAL;
+ }
+ }
+ }
+
+ if (version_id) {
+ *version_id = s->info.args.get(RGW_SYS_PARAM_PREFIX "version-id");
+ }
+
+ return 0;
+} /* get_system_versioning_params */
+
+static inline void format_xattr(std::string &xattr)
+{
+ /* If the extended attribute is not valid UTF-8, we encode it using
+ * quoted-printable encoding.
+ */
+ if ((check_utf8(xattr.c_str(), xattr.length()) != 0) ||
+ (check_for_control_characters(xattr.c_str(), xattr.length()) != 0)) {
+ static const char MIME_PREFIX_STR[] = "=?UTF-8?Q?";
+ static const int MIME_PREFIX_LEN = sizeof(MIME_PREFIX_STR) - 1;
+ static const char MIME_SUFFIX_STR[] = "?=";
+ static const int MIME_SUFFIX_LEN = sizeof(MIME_SUFFIX_STR) - 1;
+ int mlen = mime_encode_as_qp(xattr.c_str(), NULL, 0);
+ char *mime = new char[MIME_PREFIX_LEN + mlen + MIME_SUFFIX_LEN + 1];
+ strcpy(mime, MIME_PREFIX_STR);
+ mime_encode_as_qp(xattr.c_str(), mime + MIME_PREFIX_LEN, mlen);
+ strcpy(mime + MIME_PREFIX_LEN + (mlen - 1), MIME_SUFFIX_STR);
+ xattr.assign(mime);
+ delete [] mime;
+ }
+} /* format_xattr */
+
+/**
+ * Get the HTTP request metadata out of the req_state as a
+ * map(<attr_name, attr_contents>, where attr_name is RGW_ATTR_PREFIX.HTTP_NAME)
+ * s: The request state
+ * attrs: will be filled up with attrs mapped as <attr_name, attr_contents>
+ * On success returns 0.
+ * On failure returns a negative error code.
+ *
+ */
+static inline int rgw_get_request_metadata(CephContext* const cct,
+ struct req_info& info,
+ std::map<std::string, ceph::bufferlist>& attrs,
+ const bool allow_empty_attrs = true)
+{
+ static const std::set<std::string> blacklisted_headers = {
+ "x-amz-server-side-encryption-customer-algorithm",
+ "x-amz-server-side-encryption-customer-key",
+ "x-amz-server-side-encryption-customer-key-md5",
+ "x-amz-storage-class"
+ };
+
+ size_t valid_meta_count = 0;
+ for (auto& kv : info.x_meta_map) {
+ const std::string& name = kv.first;
+ std::string& xattr = kv.second;
+
+ if (blacklisted_headers.count(name) == 1) {
+ lsubdout(cct, rgw, 10) << "skipping x>> " << name << dendl;
+ continue;
+ } else if (allow_empty_attrs || !xattr.empty()) {
+ lsubdout(cct, rgw, 10) << "x>> " << name << ":" << xattr << dendl;
+ format_xattr(xattr);
+
+ std::string attr_name(RGW_ATTR_PREFIX);
+ attr_name.append(name);
+
+ /* Check roughly whether we aren't going behind the limit on attribute
+ * name. Passing here doesn't guarantee that an OSD will accept that
+ * as ObjectStore::get_max_attr_name_length() can set the limit even
+ * lower than the "osd_max_attr_name_len" configurable. */
+ const auto max_attr_name_len = cct->_conf->rgw_max_attr_name_len;
+ if (max_attr_name_len && attr_name.length() > max_attr_name_len) {
+ return -ENAMETOOLONG;
+ }
+
+ /* Similar remarks apply to the check for value size. We're veryfing
+ * it early at the RGW's side as it's being claimed in /info. */
+ const auto max_attr_size = cct->_conf->rgw_max_attr_size;
+ if (max_attr_size && xattr.length() > max_attr_size) {
+ return -EFBIG;
+ }
+
+ /* Swift allows administrators to limit the number of metadats items
+ * send _in a single request_. */
+ const auto max_attrs_num_in_req = cct->_conf->rgw_max_attrs_num_in_req;
+ if (max_attrs_num_in_req &&
+ ++valid_meta_count > max_attrs_num_in_req) {
+ return -E2BIG;
+ }
+
+ auto rval = attrs.emplace(std::move(attr_name), ceph::bufferlist());
+ /* At the moment the value of the freshly created attribute key-value
+ * pair is an empty bufferlist. */
+
+ ceph::bufferlist& bl = rval.first->second;
+ bl.append(xattr.c_str(), xattr.size() + 1);
+ }
+ }
+
+ return 0;
+} /* rgw_get_request_metadata */
+
+static inline void encode_delete_at_attr(boost::optional<ceph::real_time> delete_at,
+ map<string, bufferlist>& attrs)
+{
+ if (delete_at == boost::none) {
+ return;
+ }
+
+ bufferlist delatbl;
+ encode(*delete_at, delatbl);
+ attrs[RGW_ATTR_DELETE_AT] = delatbl;
+} /* encode_delete_at_attr */
+
+static inline void encode_obj_tags_attr(RGWObjTags* obj_tags, map<string, bufferlist>& attrs)
+{
+ if (obj_tags == nullptr){
+ // we assume the user submitted a tag format which we couldn't parse since
+ // this wouldn't be parsed later by get/put obj tags, lets delete if the
+ // attr was populated
+ return;
+ }
+
+ bufferlist tagsbl;
+ obj_tags->encode(tagsbl);
+ attrs[RGW_ATTR_TAGS] = tagsbl;
+}
+
+static inline int encode_dlo_manifest_attr(const char * const dlo_manifest,
+ map<string, bufferlist>& attrs)
+{
+ string dm = dlo_manifest;
+
+ if (dm.find('/') == string::npos) {
+ return -EINVAL;
+ }
+
+ bufferlist manifest_bl;
+ manifest_bl.append(dlo_manifest, strlen(dlo_manifest) + 1);
+ attrs[RGW_ATTR_USER_MANIFEST] = manifest_bl;
+
+ return 0;
+} /* encode_dlo_manifest_attr */
+
+static inline void complete_etag(MD5& hash, string *etag)
+{
+ char etag_buf[CEPH_CRYPTO_MD5_DIGESTSIZE];
+ char etag_buf_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 16];
+
+ hash.Final((unsigned char *)etag_buf);
+ buf_to_hex((const unsigned char *)etag_buf, CEPH_CRYPTO_MD5_DIGESTSIZE,
+ etag_buf_str);
+
+ *etag = etag_buf_str;
+} /* complete_etag */
+
+class RGWSetAttrs : public RGWOp {
+protected:
+ map<string, buffer::list> attrs;
+
+public:
+ RGWSetAttrs() {}
+ ~RGWSetAttrs() override {}
+
+ void emplace_attr(std::string&& key, buffer::list&& bl) {
+ attrs.emplace(std::move(key), std::move(bl));
+ }
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_params() = 0;
+ void send_response() override = 0;
+ const char* name() const override { return "set_attrs"; }
+ RGWOpType get_type() override { return RGW_OP_SET_ATTRS; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWGetObjLayout : public RGWOp {
+protected:
+ RGWObjManifest *manifest{nullptr};
+ rgw_raw_obj head_obj;
+
+public:
+ RGWGetObjLayout() {
+ }
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("admin", RGW_CAP_READ);
+ }
+ int verify_permission() override {
+ return check_caps(s->user->caps);
+ }
+ void pre_exec() override;
+ void execute() override;
+
+ const char* name() const override { return "get_obj_layout"; }
+ virtual RGWOpType get_type() override { return RGW_OP_GET_OBJ_LAYOUT; }
+ virtual uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWPutBucketPolicy : public RGWOp {
+ bufferlist data;
+public:
+ RGWPutBucketPolicy() = default;
+ ~RGWPutBucketPolicy() {
+ }
+ void send_response() override;
+ int verify_permission() override;
+ uint32_t op_mask() override {
+ return RGW_OP_TYPE_WRITE;
+ }
+ void execute() override;
+ int get_params();
+ const char* name() const override { return "put_bucket_policy"; }
+ RGWOpType get_type() override {
+ return RGW_OP_PUT_BUCKET_POLICY;
+ }
+};
+
+class RGWGetBucketPolicy : public RGWOp {
+ buffer::list policy;
+public:
+ RGWGetBucketPolicy() = default;
+ void send_response() override;
+ int verify_permission() override;
+ uint32_t op_mask() override {
+ return RGW_OP_TYPE_READ;
+ }
+ void execute() override;
+ const char* name() const override { return "get_bucket_policy"; }
+ RGWOpType get_type() override {
+ return RGW_OP_GET_BUCKET_POLICY;
+ }
+};
+
+class RGWDeleteBucketPolicy : public RGWOp {
+public:
+ RGWDeleteBucketPolicy() = default;
+ void send_response() override;
+ int verify_permission() override;
+ uint32_t op_mask() override {
+ return RGW_OP_TYPE_WRITE;
+ }
+ void execute() override;
+ int get_params();
+ const char* name() const override { return "delete_bucket_policy"; }
+ RGWOpType get_type() override {
+ return RGW_OP_DELETE_BUCKET_POLICY;
+ }
+};
+
+class RGWPutBucketObjectLock : public RGWOp {
+protected:
+ bufferlist data;
+ bufferlist obj_lock_bl;
+ RGWObjectLock obj_lock;
+public:
+ RGWPutBucketObjectLock() = default;
+ ~RGWPutBucketObjectLock() {}
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+ virtual void send_response() = 0;
+ virtual int get_params() = 0;
+ const char* name() const override { return "put_bucket_object_lock"; }
+ RGWOpType get_type() override { return RGW_OP_PUT_BUCKET_OBJ_LOCK; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWGetBucketObjectLock : public RGWOp {
+public:
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+ virtual void send_response() = 0;
+ const char* name() const override {return "get_bucket_object_lock"; }
+ RGWOpType get_type() override { return RGW_OP_GET_BUCKET_OBJ_LOCK; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWPutObjRetention : public RGWOp {
+protected:
+ bufferlist data;
+ RGWObjectRetention obj_retention;
+ bool bypass_perm;
+ bool bypass_governance_mode;
+public:
+ RGWPutObjRetention():bypass_perm(true), bypass_governance_mode(false) {}
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+ virtual void send_response() override = 0;
+ virtual int get_params() = 0;
+ const char* name() const override { return "put_obj_retention"; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+ RGWOpType get_type() override { return RGW_OP_PUT_OBJ_RETENTION; }
+};
+
+class RGWGetObjRetention : public RGWOp {
+protected:
+ RGWObjectRetention obj_retention;
+public:
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+ virtual void send_response() = 0;
+ const char* name() const override {return "get_obj_retention"; }
+ RGWOpType get_type() override { return RGW_OP_GET_OBJ_RETENTION; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWPutObjLegalHold : public RGWOp {
+protected:
+ bufferlist data;
+ RGWObjectLegalHold obj_legal_hold;
+public:
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+ virtual void send_response() override = 0;
+ virtual int get_params() = 0;
+ const char* name() const override { return "put_obj_legal_hold"; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+ RGWOpType get_type() override { return RGW_OP_PUT_OBJ_LEGAL_HOLD; }
+};
+
+class RGWGetObjLegalHold : public RGWOp {
+protected:
+ RGWObjectLegalHold obj_legal_hold;
+public:
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+ virtual void send_response() = 0;
+ const char* name() const override {return "get_obj_legal_hold"; }
+ RGWOpType get_type() override { return RGW_OP_GET_OBJ_LEGAL_HOLD; }
+ uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+
+class RGWConfigBucketMetaSearch : public RGWOp {
+protected:
+ std::map<std::string, uint32_t> mdsearch_config;
+public:
+ RGWConfigBucketMetaSearch() {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ virtual int get_params() = 0;
+ const char* name() const override { return "config_bucket_meta_search"; }
+ virtual RGWOpType get_type() override { return RGW_OP_CONFIG_BUCKET_META_SEARCH; }
+ virtual uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWGetBucketMetaSearch : public RGWOp {
+public:
+ RGWGetBucketMetaSearch() {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override {}
+
+ const char* name() const override { return "get_bucket_meta_search"; }
+ virtual RGWOpType get_type() override { return RGW_OP_GET_BUCKET_META_SEARCH; }
+ virtual uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+};
+
+class RGWDelBucketMetaSearch : public RGWOp {
+public:
+ RGWDelBucketMetaSearch() {}
+
+ int verify_permission() override;
+ void pre_exec() override;
+ void execute() override;
+
+ const char* name() const override { return "delete_bucket_meta_search"; }
+ virtual RGWOpType delete_type() { return RGW_OP_DEL_BUCKET_META_SEARCH; }
+ virtual uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
+};
+
+class RGWGetClusterStat : public RGWOp {
+protected:
+ struct rados_cluster_stat_t stats_op;
+public:
+ RGWGetClusterStat() {}
+
+ void init(RGWRados *store, struct req_state *s, RGWHandler *h) override {
+ RGWOp::init(store, s, h);
+ }
+ int verify_permission() override {return 0;}
+ virtual void send_response() override = 0;
+ virtual int get_params() = 0;
+ void execute() override;
+ const char* name() const override { return "get_cluster_stat"; }
+ dmc::client_id dmclock_client() override { return dmc::client_id::admin; }
+};
+
+static inline int parse_value_and_bound(
+ const string &input,
+ int &output,
+ const long lower_bound,
+ const long upper_bound,
+ const long default_val)
+{
+ if (!input.empty()) {
+ char *endptr;
+ output = strtol(input.c_str(), &endptr, 10);
+ if (endptr) {
+ if (endptr == input.c_str()) return -EINVAL;
+ while (*endptr && isspace(*endptr)) // ignore white space
+ endptr++;
+ if (*endptr) {
+ return -EINVAL;
+ }
+ }
+ if(output > upper_bound) {
+ output = upper_bound;
+ }
+ if(output < lower_bound) {
+ output = lower_bound;
+ }
+ } else {
+ output = default_val;
+ }
+
+ return 0;
+}
+
+
+#endif /* CEPH_RGW_OP_H */