initial code repo
[stor4nfv.git] / src / ceph / src / rgw / rgw_op.h
diff --git a/src/ceph/src/rgw/rgw_op.h b/src/ceph/src/rgw/rgw_op.h
new file mode 100644 (file)
index 0000000..68b83a4
--- /dev/null
@@ -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 <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/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<string, bufferlist> 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<rgw::IAM::Policy>& 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<RGWGetDataCB>* 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<fail_desc_t> 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<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 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<RGWObjectCtx> 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() = 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 {
+    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 <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 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<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 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<std::string, RGWUsageStats> 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<rgw_bucket_dir_entry> objs;
+  map<string, bool> 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<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) {}
+
+  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<rgw_slo_entry> 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 <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;
+
+  boost::optional<ceph::real_time> 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<RGWGetDataCB>* filter,
+                                 RGWGetDataCB* cb,
+                                 map<string, bufferlist>& attrs,
+                                 bufferlist* manifest_bl) {
+    *filter = nullptr;
+    return 0;
+  }
+  virtual int get_encrypt_filter(std::unique_ptr<RGWPutObjDataProcessor> *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<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<RGWPutObjDataProcessor> *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<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 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<string, buffer::list> attrs;
+  set<string> rmattr_names;
+  bool has_policy, has_cors;
+  uint32_t policy_rw_mask;
+  RGWAccessControlPolicy policy;
+  RGWCORSConfiguration cors_config;
+  string 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 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<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 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<RGWBulkDelete::Deleter> 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<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 client_id;
+  string op_id;
+  ceph::buffer::list etag;
+
+  off_t last_ofs;
+
+  string version_id;
+  uint64_t olh_epoch;
+
+  boost::optional<ceph::real_time> 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<string, bufferlist>& 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<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 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<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 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(<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"
+  };
+
+  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<size_t>("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<size_t>("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<size_t>("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<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((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<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 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<void*>(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<std::string, uint32_t> 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 */