X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Frgw%2Frgw_op.h;fp=src%2Fceph%2Fsrc%2Frgw%2Frgw_op.h;h=68b83a45f13388d6d3e7bba5cc6406d882a6914a;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/rgw/rgw_op.h b/src/ceph/src/rgw/rgw_op.h new file mode 100644 index 0000000..68b83a4 --- /dev/null +++ b/src/ceph/src/rgw/rgw_op.h @@ -0,0 +1,2194 @@ +// -*- 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "common/armor.h" +#include "common/mime.h" +#include "common/utf8.h" +#include "common/ceph_json.h" +#include "common/utf8.h" +#include "common/ceph_time.h" + +#include "rgw_common.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_lc.h" +#include "rgw_torrent.h" +#include "rgw_tag.h" +#include "cls/lock/cls_lock_client.h" +#include "cls/rgw/cls_rgw_client.h" + +#include "include/assert.h" + +using ceph::crypto::SHA1; + +struct req_state; +class RGWOp; + + +namespace rgw { +namespace auth { +namespace registry { + +class StrategyRegistry; + +} +} +} + + +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() = 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 {} +}; + + + +void rgw_bucket_object_pre_exec(struct req_state *s); + +/** + * Provide the base class for all ops. + */ +class RGWOp { +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() { + 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(); + } + 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 string name() = 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); +}; + +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 attrs; + bool get_data; + bool partial_content; + 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; + + 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; + } + + 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 read_user_manifest_part( + rgw_bucket& bucket, + const rgw_bucket_dir_entry& ent, + RGWAccessControlPolicy * const bucket_acl, + const boost::optional& bucket_policy, + const off_t start_ofs, + const off_t end_ofs); + 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 string name() 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* filter, RGWGetDataCB* cb, bufferlist* manifest_bl) { + *filter = nullptr; + return 0; + } +}; + +class RGWGetObj_CB : public RGWGetDataCB +{ + 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 RGWGetObj_Filter : public RGWGetDataCB +{ +protected: + RGWGetDataCB* next; +public: + RGWGetObj_Filter(RGWGetDataCB* 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 { + return next->handle_data(bl, bl_ofs, bl_len); + } + /** + * Flushes any cached data. Used by RGWGetObjFilter. + * Return logic same as handle_data. + */ + int flush() override { + return next->flush(); + } + /** + * Allows filter to extend range required for successful filtering + */ + int fixup_range(off_t& ofs, off_t& end) override { + return next->fixup_range(ofs, end); + } +}; + +class RGWGetObjTags : public RGWOp { + protected: + bufferlist tags_bl; + bool has_tags{false}; + public: + int verify_permission(); + void execute(); + void pre_exec(); + + virtual void send_response_data(bufferlist& bl) = 0; + virtual const string name() noexcept override { return "get_obj_tags"; } + virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } + RGWOpType get_type() { return RGW_OP_GET_OBJ_TAGGING; } + +}; + +class RGWPutObjTags : public RGWOp { + protected: + bufferlist tags_bl; + public: + int verify_permission(); + void execute(); + + virtual void send_response() = 0; + virtual int get_params() = 0; + virtual const string name() { return "put_obj_tags"; } + virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } + RGWOpType get_type() { return RGW_OP_PUT_OBJ_TAGGING; } + +}; + +class RGWDeleteObjTags: public RGWOp { + public: + void pre_exec(); + int verify_permission(); + void execute(); + + virtual void send_response() = 0; + virtual const string name() { return "delete_obj_tags"; } + virtual uint32_t op_mask() { return RGW_OP_TYPE_DELETE; } + RGWOpType get_type() { 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: + unsigned int num_deleted; + unsigned int num_unfound; + std::list failures; + + RGWRados * const store; + req_state * const s; + + public: + Deleter(RGWRados * const str, req_state * const s) + : 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 get_failures() const { + return failures; + } + + bool verify_permission(RGWBucketInfo& binfo, + map& battrs, + ACLOwner& bucket_owner /* out */); + bool delete_single(const acct_path_t& path); + bool delete_chunk(const std::list& paths); + }; + /* End of Deleter subclass */ + + static const size_t MAX_CHUNK_ENTRIES = 1024; + +protected: + std::unique_ptr deleter; + +public: + RGWBulkDelete() + : deleter(nullptr) { + } + + int verify_permission() override; + void pre_exec() override; + void execute() override; + + virtual int get_data(std::list& items, + bool * is_truncated) = 0; + void send_response() override = 0; + + const string name() override { return "bulk_delete"; } + RGWOpType get_type() override { return RGW_OP_BULK_DELETE; } + uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; } +}; + +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 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 terminal_errors = { + { -EACCES, -EPERM } + }; + + /* FIXME: boost::container::small_vector failures; */ + std::vector failures; + size_t num_created; + + class StreamGetter; + class DecoratedStreamGetter; + class AlignedStreamGetter; + + virtual std::unique_ptr create_stream() = 0; + virtual void send_response() = 0; + + boost::optional> + parse_path(const boost::string_ref& path); + + std::pair + handle_upload_path(struct req_state *s); + + bool handle_file_verify_permission(RGWBucketInfo& binfo, + const rgw_obj& obj, + std::map& 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 { + RGWOp::init(store, s, h); + dir_ctx.emplace(store); + } + + int verify_permission() override; + void pre_exec() override; + void execute() override; + + const std::string name() override { + return "bulk_upload"; + } + + RGWOpType get_type() override { + return RGW_OP_BULK_UPLOAD; + } + + uint32_t op_mask() override { + return RGW_OP_TYPE_WRITE; + } +}; /* 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: + 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 + AlignedStreamGetter(const size_t position, + const size_t length, + const size_t alignment, + U&& decoratee) + : DecoratedStreamGetter(std::forward(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 attrs; + bool is_truncated; + + RGWUsageStats global_stats; + std::map 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 string name() override { return "list_buckets"; } + RGWOpType get_type() override { return RGW_OP_LIST_BUCKETS; } + uint32_t op_mask() override { return RGW_OP_TYPE_READ; } +}; + +class RGWGetUsage : public RGWOp { +protected: + bool sent_data; + string start_date; + string end_date; + int show_log_entries; + int show_log_sum; + map categories; + map usage; + map summary_map; + map 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 string name() override { return "get_usage"; } + uint32_t op_mask() override { return RGW_OP_TYPE_READ; } +}; + +class RGWStatAccount : public RGWOp { +protected: + RGWUsageStats global_stats; + std::map policies_stats; + +public: + RGWStatAccount() = default; + + int verify_permission() override; + void execute() override; + + void send_response() override = 0; + const std::string name() 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 objs; + map common_prefixes; + + int default_max; + bool is_truncated; + + int shard_id; + + int parse_max_keys(); + +public: + RGWListBucket() : list_versions(false), max(0), + default_max(0), is_truncated(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 string name() 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 string name() 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 string name() 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; + bool versioning_enabled; +public: + RGWGetBucketVersioning() : versioned(false), versioning_enabled(false) {} + + int verify_permission() override; + void pre_exec() override; + void execute() override; + + void send_response() override = 0; + const string name() 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; } +}; + +class RGWSetBucketVersioning : public RGWOp { +protected: + bool enable_versioning; + bufferlist in_data; +public: + RGWSetBucketVersioning() : enable_versioning(false) {} + + int verify_permission() override; + void pre_exec() override; + void execute() override; + + virtual int get_params() { return 0; } + + void send_response() override = 0; + const string name() 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 string name() 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 string name() 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 string name() 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 string name() 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; + string placement_rule; + RGWBucketInfo info; + obj_version ep_objv; + bool has_cors; + RGWCORSConfiguration cors_config; + boost::optional swift_ver_location; + map attrs; + set rmattr_names; + + bufferlist in_data; + + virtual bool need_metadata_upload() const { return false; } + +public: + RGWCreateBucket() : has_cors(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); + } + virtual int get_params() { return 0; } + void send_response() override = 0; + const string name() 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 string name() 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::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 entries; + uint64_t total_size; + + /* in memory only */ + char *raw_data; + int raw_data_len; + + RGWSLOInfo() : total_size(0), raw_data(NULL), raw_data_len(0) {} + ~RGWSLOInfo() { + free(raw_data); + } + + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + ::encode(entries, bl); + ::encode(total_size, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::iterator& bl) { + DECODE_START(1, bl); + ::decode(entries, bl); + ::decode(total_size, bl); + DECODE_FINISH(bl); + } +}; +WRITE_CLASS_ENCODER(RGWSLOInfo) + +class RGWPutObj : public RGWOp { + + friend class RGWPutObjProcessor; + +protected: + seed torrent; + off_t ofs; + const char *supplied_md5_b64; + const char *supplied_etag; + const char *if_match; + const char *if_nomatch; + const char *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 obj_tags; + const char *dlo_manifest; + RGWSLOInfo *slo_info; + map attrs; + ceph::real_time mtime; + uint64_t olh_epoch; + string version_id; + bufferlist bl_aux; + map crypt_http_responses; + string user_data; + + boost::optional delete_at; + +public: + RGWPutObj() : ofs(0), + supplied_md5_b64(NULL), + supplied_etag(NULL), + if_match(NULL), + if_nomatch(NULL), + copy_source(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) {} + + ~RGWPutObj() override { + delete slo_info; + } + + 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 */ + } + + virtual RGWPutObjProcessor *select_processor(RGWObjectCtx& obj_ctx, bool *is_multipart); + void dispose_processor(RGWPutObjDataProcessor *processor); + + 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* filter, + RGWGetDataCB* cb, + map& attrs, + bufferlist* manifest_bl) { + *filter = nullptr; + return 0; + } + virtual int get_encrypt_filter(std::unique_ptr *filter, RGWPutObjDataProcessor* cb) { + *filter = nullptr; + 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 string name() override { return "put_obj"; } + RGWOpType get_type() override { return RGW_OP_PUT_OBJ; } + uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; } +}; + +class RGWPutObj_Filter : public RGWPutObjDataProcessor +{ +protected: + RGWPutObjDataProcessor* next; +public: + RGWPutObj_Filter(RGWPutObjDataProcessor* next) : + next(next){} + ~RGWPutObj_Filter() override {} + int handle_data(bufferlist& bl, off_t ofs, void **phandle, rgw_raw_obj *pobj, bool *again) override { + return next->handle_data(bl, ofs, phandle, pobj, again); + } + int throttle_data(void *handle, const rgw_raw_obj& obj, uint64_t size, bool need_to_wait) override { + return next->throttle_data(handle, obj, size, need_to_wait); + } +}; /* RGWPutObj_Filter */ + +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 attrs; + boost::optional 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 *filter, RGWPutObjDataProcessor* cb) { + *filter = nullptr; + return 0; + } + virtual int get_params() = 0; + virtual int get_data(ceph::bufferlist& bl, bool& again) = 0; + void send_response() override = 0; + const std::string name() override { return "post_obj"; } + RGWOpType get_type() override { return RGW_OP_POST_OBJ; } + uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; } +}; + +class RGWPutMetadataAccount : public RGWOp { +protected: + std::set rmattr_names; + std::map attrs, orig_attrs; + std::map 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& add_attrs, + const set& rmattr_names, + map& temp_url_keys); + const string name() 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 attrs; + set rmattr_names; + bool has_policy, has_cors; + uint32_t policy_rw_mask; + RGWAccessControlPolicy policy; + RGWCORSConfiguration cors_config; + string placement_rule; + boost::optional 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 string name() 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; + string placement_rule; + boost::optional 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 string name() 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 deleter; + +public: + RGWDeleteObj() + : delete_marker(false), + multipart_delete(false), + no_precondition_error(false), + deleter(nullptr) { + } + + 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 string name() 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; } +}; + +class RGWCopyObj : public RGWOp { +protected: + RGWAccessControlPolicy dest_policy; + const char *if_mod; + const char *if_unmod; + const char *if_match; + const char *if_nomatch; + 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 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 client_id; + string op_id; + ceph::buffer::list etag; + + off_t last_ofs; + + string version_id; + uint64_t olh_epoch; + + boost::optional delete_at; + bool copy_if_newer; + + 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 string& 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 init_dest_policy() { return 0; } + virtual int get_params() = 0; + virtual void send_partial_response(off_t ofs) {} + void send_response() override = 0; + const string name() override { return "copy_obj"; } + RGWOpType get_type() override { return RGW_OP_COPY_OBJ; } + uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; } +}; + +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 string name() 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: + int len; + char *data; + ACLOwner owner; + +public: + RGWPutACLs() { + len = 0; + data = NULL; + } + ~RGWPutACLs() override { + free(data); + } + + 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 string name() 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 string name() 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: + int len; + char *data; + string cookie; + +public: + RGWPutLC() { + len = 0; + data = NULL; + } + ~RGWPutLC() override { + free(data); + } + + 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 string name() 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 string name() 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 string name() 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 string name() 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 string name() 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 string name() 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 string name() 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; +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 string name() 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 string name() 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& attrs) { return 0; } +}; + +class RGWCompleteMultipart : public RGWOp { +protected: + string upload_id; + string etag; + char *data; + int len; + + 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() { + data = NULL; + len = 0; + } + ~RGWCompleteMultipart() override { + free(data); + } + + 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 string name() 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 string name() 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 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 string name() 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; +}; + +class RGWListBucketMultiparts : public RGWOp { +protected: + string prefix; + RGWMPObj marker; + RGWMultipartUploadEntry next_marker; + int max_uploads; + string delimiter; + vector uploads; + map 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 string name() 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 string name() 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 string name() 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: + int max_to_delete; + int len; + char *data; + rgw_bucket bucket; + bool quiet; + bool status_dumped; + bool acl_allowed = false; + +public: + RGWDeleteMultiObj() { + max_to_delete = 1000; + len = 0; + data = NULL; + 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 string name() 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 string name() 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 rgw::IAM::Environment rgw_build_iam_environment(RGWRados* store, + struct req_state* s); + +static inline int put_data_and_throttle(RGWPutObjDataProcessor *processor, + bufferlist& data, off_t ofs, + bool need_to_wait) +{ + bool again = false; + do { + void *handle = nullptr; + rgw_raw_obj obj; + + uint64_t size = data.length(); + + int ret = processor->handle_data(data, ofs, &handle, &obj, &again); + if (ret < 0) + return ret; + if (handle != nullptr) + { + ret = processor->throttle_data(handle, obj, size, need_to_wait); + if (ret < 0) + return ret; + } + else + break; + need_to_wait = false; /* the need to wait only applies to the first + * iteration */ + } while (again); + + return 0; +} /* put_data_and_throttle */ + + + + + +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(, where attr_name is RGW_ATTR_PREFIX.HTTP_NAME) + * s: The request state + * attrs: will be filled up with attrs mapped as + * 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& attrs, + const bool allow_empty_attrs = true) +{ + static const std::set blacklisted_headers = { + "x-amz-server-side-encryption-customer-algorithm", + "x-amz-server-side-encryption-customer-key", + "x-amz-server-side-encryption-customer-key-md5" + }; + + 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 size_t max_attr_name_len = \ + cct->_conf->get_val("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 size_t max_attr_size = \ + cct->_conf->get_val("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 rgw_max_attrs_num_in_req = \ + cct->_conf->get_val("rgw_max_attrs_num_in_req"); + if (rgw_max_attrs_num_in_req && + ++valid_meta_count > rgw_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 delete_at, + map& 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& 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& 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((byte *)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 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 string name() 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() { + return check_caps(s->user->caps); + } + void pre_exec(); + void execute(); + + virtual void send_response() = 0; + virtual const string name() { return "get_obj_layout"; } + virtual RGWOpType get_type() { return RGW_OP_GET_OBJ_LAYOUT; } + virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } +}; + +class RGWPutBucketPolicy : public RGWOp { + int len; + char *data = nullptr; +public: + RGWPutBucketPolicy() = default; + ~RGWPutBucketPolicy() { + if (data) { + free(static_cast(data)); + } + } + 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 std::string name() 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 std::string name() 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 std::string name() override { + return "delete_bucket_policy"; + } + RGWOpType get_type() override { + return RGW_OP_DELETE_BUCKET_POLICY; + } +}; + + +class RGWConfigBucketMetaSearch : public RGWOp { +protected: + std::map mdsearch_config; +public: + RGWConfigBucketMetaSearch() {} + + int verify_permission(); + void pre_exec(); + void execute(); + + virtual int get_params() = 0; + virtual void send_response() = 0; + virtual const string name() { return "config_bucket_meta_search"; } + virtual RGWOpType get_type() { return RGW_OP_CONFIG_BUCKET_META_SEARCH; } + virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } +}; + +class RGWGetBucketMetaSearch : public RGWOp { +public: + RGWGetBucketMetaSearch() {} + + int verify_permission(); + void pre_exec(); + void execute() {} + + virtual void send_response() = 0; + virtual const string name() { return "get_bucket_meta_search"; } + virtual RGWOpType get_type() { return RGW_OP_GET_BUCKET_META_SEARCH; } + virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } +}; + +class RGWDelBucketMetaSearch : public RGWOp { +public: + RGWDelBucketMetaSearch() {} + + int verify_permission(); + void pre_exec(); + void execute(); + + virtual void send_response() = 0; + virtual const string name() { return "delete_bucket_meta_search"; } + virtual RGWOpType delete_type() { return RGW_OP_DEL_BUCKET_META_SEARCH; } + virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } +}; + +#endif /* CEPH_RGW_OP_H */