X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Frgw%2Frgw_rest.h;fp=src%2Fceph%2Fsrc%2Frgw%2Frgw_rest.h;h=515057dfcd679c8b622603477ed3f23022903239;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/rgw/rgw_rest.h b/src/ceph/src/rgw/rgw_rest.h new file mode 100644 index 0000000..515057d --- /dev/null +++ b/src/ceph/src/rgw/rgw_rest.h @@ -0,0 +1,754 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_RGW_REST_H +#define CEPH_RGW_REST_H + +#define TIME_BUF_SIZE 128 + +#include +#include +#include "common/sstring.hh" +#include "common/ceph_json.h" +#include "include/assert.h" /* needed because of common/ceph_json.h */ +#include "rgw_op.h" +#include "rgw_formats.h" +#include "rgw_client_io.h" + +extern std::map rgw_to_http_attrs; + +extern string camelcase_dash_http_attr(const string& orig); +extern string lowercase_dash_http_attr(const string& orig); + +extern void rgw_rest_init(CephContext *cct, RGWRados *store, RGWZoneGroup& zone_group); + +extern void rgw_flush_formatter_and_reset(struct req_state *s, + ceph::Formatter *formatter); + +extern void rgw_flush_formatter(struct req_state *s, + ceph::Formatter *formatter); + +extern int rgw_rest_read_all_input(struct req_state *s, char **data, int *plen, + uint64_t max_len, bool allow_chunked=true); + +template +int rgw_rest_get_json_input(CephContext *cct, req_state *s, T& out, + uint64_t max_len, bool *empty) +{ + int rv, data_len; + char *data; + + if (empty) + *empty = false; + + if ((rv = rgw_rest_read_all_input(s, &data, &data_len, max_len)) < 0) { + return rv; + } + + if (!data_len) { + if (empty) { + *empty = true; + } + + return -EINVAL; + } + + JSONParser parser; + + if (!parser.parse(data, data_len)) { + free(data); + return -EINVAL; + } + + free(data); + + try { + decode_json_obj(out, &parser); + } catch (JSONDecoder::err& e) { + return -EINVAL; + } + + return 0; +} + +template +int rgw_rest_get_json_input_keep_data(CephContext *cct, req_state *s, T& out, uint64_t max_len, char **pdata, int *len) +{ + int rv, data_len; + char *data; + + if ((rv = rgw_rest_read_all_input(s, &data, &data_len, max_len)) < 0) { + return rv; + } + + if (!data_len) { + return -EINVAL; + } + + *len = data_len; + + JSONParser parser; + + if (!parser.parse(data, data_len)) { + free(data); + return -EINVAL; + } + + try { + decode_json_obj(out, &parser); + } catch (JSONDecoder::err& e) { + free(data); + return -EINVAL; + } + + *pdata = data; + return 0; +} + +class RESTArgs { +public: + static int get_string(struct req_state *s, const string& name, + const string& def_val, string *val, + bool *existed = NULL); + static int get_uint64(struct req_state *s, const string& name, + uint64_t def_val, uint64_t *val, bool *existed = NULL); + static int get_int64(struct req_state *s, const string& name, + int64_t def_val, int64_t *val, bool *existed = NULL); + static int get_uint32(struct req_state *s, const string& name, + uint32_t def_val, uint32_t *val, bool *existed = NULL); + static int get_int32(struct req_state *s, const string& name, + int32_t def_val, int32_t *val, bool *existed = NULL); + static int get_time(struct req_state *s, const string& name, + const utime_t& def_val, utime_t *val, + bool *existed = NULL); + static int get_epoch(struct req_state *s, const string& name, + uint64_t def_val, uint64_t *epoch, + bool *existed = NULL); + static int get_bool(struct req_state *s, const string& name, bool def_val, + bool *val, bool *existed = NULL); +}; + +class RGWRESTFlusher : public RGWFormatterFlusher { + struct req_state *s; + RGWOp *op; +protected: + void do_flush() override; + void do_start(int ret) override; +public: + RGWRESTFlusher(struct req_state *_s, RGWOp *_op) : + RGWFormatterFlusher(_s->formatter), s(_s), op(_op) {} + RGWRESTFlusher() : RGWFormatterFlusher(NULL), s(NULL), op(NULL) {} + + void init(struct req_state *_s, RGWOp *_op) { + s = _s; + op = _op; + set_formatter(s->formatter); + } +}; + +class RGWGetObj_ObjStore : public RGWGetObj +{ +protected: + bool sent_header; +public: + RGWGetObj_ObjStore() : sent_header(false) {} + + void init(RGWRados *store, struct req_state *s, RGWHandler *h) override { + RGWGetObj::init(store, s, h); + sent_header = false; + } + + int get_params() override; +}; + +class RGWGetObjTags_ObjStore : public RGWGetObjTags { +public: + RGWGetObjTags_ObjStore() {}; + ~RGWGetObjTags_ObjStore() {}; +}; + +class RGWPutObjTags_ObjStore: public RGWPutObjTags { +public: + RGWPutObjTags_ObjStore() {}; + ~RGWPutObjTags_ObjStore() {}; +}; + +class RGWListBuckets_ObjStore : public RGWListBuckets { +public: + RGWListBuckets_ObjStore() {} + ~RGWListBuckets_ObjStore() override {} +}; + +class RGWGetUsage_ObjStore : public RGWGetUsage { +public: + RGWGetUsage_ObjStore() {} + ~RGWGetUsage_ObjStore() override {} +}; + +class RGWListBucket_ObjStore : public RGWListBucket { +public: + RGWListBucket_ObjStore() {} + ~RGWListBucket_ObjStore() override {} +}; + +class RGWStatAccount_ObjStore : public RGWStatAccount { +public: + RGWStatAccount_ObjStore() {} + ~RGWStatAccount_ObjStore() override {} +}; + +class RGWStatBucket_ObjStore : public RGWStatBucket { +public: + RGWStatBucket_ObjStore() {} + ~RGWStatBucket_ObjStore() override {} +}; + +class RGWCreateBucket_ObjStore : public RGWCreateBucket { +public: + RGWCreateBucket_ObjStore() {} + ~RGWCreateBucket_ObjStore() override {} +}; + +class RGWDeleteBucket_ObjStore : public RGWDeleteBucket { +public: + RGWDeleteBucket_ObjStore() {} + ~RGWDeleteBucket_ObjStore() override {} +}; + +class RGWPutObj_ObjStore : public RGWPutObj +{ +public: + RGWPutObj_ObjStore() {} + ~RGWPutObj_ObjStore() override {} + + int verify_params() override; + int get_params() override; + int get_data(bufferlist& bl) override; +}; + +class RGWPostObj_ObjStore : public RGWPostObj +{ + std::string boundary; + +public: + struct post_part_field { + std::string val; + std::map params; + }; + + struct post_form_part { + std::string name; + std::map fields; + ceph::bufferlist data; + }; + +protected: + using parts_collection_t = \ + std::map; + + std::string err_msg; + ceph::bufferlist in_data; + + int read_with_boundary(ceph::bufferlist& bl, + uint64_t max, + bool check_eol, + bool& reached_boundary, + bool& done); + + int read_line(ceph::bufferlist& bl, + uint64_t max, + bool& reached_boundary, + bool& done); + + int read_data(ceph::bufferlist& bl, + uint64_t max, + bool& reached_boundary, + bool& done); + + int read_form_part_header(struct post_form_part *part, bool& done); + + int get_params() override; + + static int parse_part_field(const std::string& line, + std::string& field_name, /* out */ + post_part_field& field); /* out */ + + static void parse_boundary_params(const std::string& params_str, + std::string& first, + std::map& params); + + static bool part_str(parts_collection_t& parts, + const std::string& name, + std::string *val); + + static std::string get_part_str(parts_collection_t& parts, + const std::string& name, + const std::string& def_val = std::string()); + + static bool part_bl(parts_collection_t& parts, + const std::string& name, + ceph::bufferlist *pbl); + +public: + RGWPostObj_ObjStore() {} + ~RGWPostObj_ObjStore() override {} + + int verify_params() override; +}; + + +class RGWPutMetadataAccount_ObjStore : public RGWPutMetadataAccount +{ +public: + RGWPutMetadataAccount_ObjStore() {} + ~RGWPutMetadataAccount_ObjStore() override {} +}; + +class RGWPutMetadataBucket_ObjStore : public RGWPutMetadataBucket +{ +public: + RGWPutMetadataBucket_ObjStore() {} + ~RGWPutMetadataBucket_ObjStore() override {} +}; + +class RGWPutMetadataObject_ObjStore : public RGWPutMetadataObject +{ +public: + RGWPutMetadataObject_ObjStore() {} + ~RGWPutMetadataObject_ObjStore() override {} +}; + +class RGWDeleteObj_ObjStore : public RGWDeleteObj { +public: + RGWDeleteObj_ObjStore() {} + ~RGWDeleteObj_ObjStore() override {} +}; + +class RGWGetCrossDomainPolicy_ObjStore : public RGWGetCrossDomainPolicy { +public: + RGWGetCrossDomainPolicy_ObjStore() = default; + ~RGWGetCrossDomainPolicy_ObjStore() override = default; +}; + +class RGWGetHealthCheck_ObjStore : public RGWGetHealthCheck { +public: + RGWGetHealthCheck_ObjStore() = default; + ~RGWGetHealthCheck_ObjStore() override = default; +}; + +class RGWCopyObj_ObjStore : public RGWCopyObj { +public: + RGWCopyObj_ObjStore() {} + ~RGWCopyObj_ObjStore() override {} +}; + +class RGWGetACLs_ObjStore : public RGWGetACLs { +public: + RGWGetACLs_ObjStore() {} + ~RGWGetACLs_ObjStore() override {} +}; + +class RGWPutACLs_ObjStore : public RGWPutACLs { +public: + RGWPutACLs_ObjStore() {} + ~RGWPutACLs_ObjStore() override {} + + int get_params() override; +}; + +class RGWGetLC_ObjStore : public RGWGetLC { +public: + RGWGetLC_ObjStore() {} + ~RGWGetLC_ObjStore() override {} +}; + +class RGWPutLC_ObjStore : public RGWPutLC { +public: + RGWPutLC_ObjStore() {} + ~RGWPutLC_ObjStore() override {} + + int get_params() override; +}; + +class RGWDeleteLC_ObjStore : public RGWDeleteLC { +public: + RGWDeleteLC_ObjStore() {} + ~RGWDeleteLC_ObjStore() override {} + +}; + +class RGWGetCORS_ObjStore : public RGWGetCORS { +public: + RGWGetCORS_ObjStore() {} + ~RGWGetCORS_ObjStore() override {} +}; + +class RGWPutCORS_ObjStore : public RGWPutCORS { +public: + RGWPutCORS_ObjStore() {} + ~RGWPutCORS_ObjStore() override {} +}; + +class RGWDeleteCORS_ObjStore : public RGWDeleteCORS { +public: + RGWDeleteCORS_ObjStore() {} + ~RGWDeleteCORS_ObjStore() override {} +}; + +class RGWOptionsCORS_ObjStore : public RGWOptionsCORS { +public: + RGWOptionsCORS_ObjStore() {} + ~RGWOptionsCORS_ObjStore() override {} +}; + +class RGWInitMultipart_ObjStore : public RGWInitMultipart { +public: + RGWInitMultipart_ObjStore() {} + ~RGWInitMultipart_ObjStore() override {} +}; + +class RGWCompleteMultipart_ObjStore : public RGWCompleteMultipart { +public: + RGWCompleteMultipart_ObjStore() {} + ~RGWCompleteMultipart_ObjStore() override {} + + int get_params() override; +}; + +class RGWAbortMultipart_ObjStore : public RGWAbortMultipart { +public: + RGWAbortMultipart_ObjStore() {} + ~RGWAbortMultipart_ObjStore() override {} +}; + +class RGWListMultipart_ObjStore : public RGWListMultipart { +public: + RGWListMultipart_ObjStore() {} + ~RGWListMultipart_ObjStore() override {} + + int get_params() override; +}; + +class RGWListBucketMultiparts_ObjStore : public RGWListBucketMultiparts { +public: + RGWListBucketMultiparts_ObjStore() {} + ~RGWListBucketMultiparts_ObjStore() override {} + + int get_params() override; +}; + +class RGWBulkDelete_ObjStore : public RGWBulkDelete { +public: + RGWBulkDelete_ObjStore() {} + ~RGWBulkDelete_ObjStore() override {} +}; + +class RGWBulkUploadOp_ObjStore : public RGWBulkUploadOp { +public: + RGWBulkUploadOp_ObjStore() = default; + ~RGWBulkUploadOp_ObjStore() = default; +}; + +class RGWDeleteMultiObj_ObjStore : public RGWDeleteMultiObj { +public: + RGWDeleteMultiObj_ObjStore() {} + ~RGWDeleteMultiObj_ObjStore() override {} + + int get_params() override; +}; + +class RGWInfo_ObjStore : public RGWInfo { +public: + RGWInfo_ObjStore() = default; + ~RGWInfo_ObjStore() override = default; +}; + +class RGWRESTOp : public RGWOp { +protected: + int http_ret; + RGWRESTFlusher flusher; +public: + RGWRESTOp() : http_ret(0) {} + void init(RGWRados *store, struct req_state *s, + RGWHandler *dialect_handler) override { + RGWOp::init(store, s, dialect_handler); + flusher.init(s, this); + } + void send_response() override; + virtual int check_caps(RGWUserCaps& caps) + { return -EPERM; } /* should to be implemented! */ + int verify_permission() override; +}; + +class RGWHandler_REST : public RGWHandler { +protected: + + virtual bool is_obj_update_op() { return false; } + virtual RGWOp *op_get() { return NULL; } + virtual RGWOp *op_put() { return NULL; } + virtual RGWOp *op_delete() { return NULL; } + virtual RGWOp *op_head() { return NULL; } + virtual RGWOp *op_post() { return NULL; } + virtual RGWOp *op_copy() { return NULL; } + virtual RGWOp *op_options() { return NULL; } + + static int allocate_formatter(struct req_state *s, int default_formatter, + bool configurable); +public: + static constexpr int MAX_BUCKET_NAME_LEN = 255; + static constexpr int MAX_OBJ_NAME_LEN = 1024; + + RGWHandler_REST() {} + ~RGWHandler_REST() override {} + + static int validate_bucket_name(const string& bucket); + static int validate_object_name(const string& object); + + int init_permissions(RGWOp* op) override; + int read_permissions(RGWOp* op) override; + + virtual RGWOp* get_op(RGWRados* store); + virtual void put_op(RGWOp* op); +}; + +class RGWHandler_REST_SWIFT; +class RGWHandler_SWIFT_Auth; +class RGWHandler_REST_S3; + +namespace rgw { +namespace auth { + +class StrategyRegistry; + +} +} + +class RGWRESTMgr { + bool should_log; + +protected: + std::map resource_mgrs; + std::multimap resources_by_size; + RGWRESTMgr* default_mgr; + + virtual RGWRESTMgr* get_resource_mgr(struct req_state* s, + const std::string& uri, + std::string* out_uri); + + virtual RGWRESTMgr* get_resource_mgr_as_default(struct req_state* const s, + const std::string& uri, + std::string* our_uri) { + return this; + } + +public: + RGWRESTMgr() + : should_log(false), + default_mgr(nullptr) { + } + virtual ~RGWRESTMgr(); + + void register_resource(std::string resource, RGWRESTMgr* mgr); + void register_default_mgr(RGWRESTMgr* mgr); + + virtual RGWRESTMgr* get_manager(struct req_state* const s, + /* Prefix to be concatenated with @uri + * during the lookup. */ + const std::string& frontend_prefix, + const std::string& uri, + std::string* out_uri) final { + return get_resource_mgr(s, frontend_prefix + uri, out_uri); + } + + virtual RGWHandler_REST* get_handler( + struct req_state* const s, + const rgw::auth::StrategyRegistry& auth_registry, + const std::string& frontend_prefix + ) { + return nullptr; + } + + virtual void put_handler(RGWHandler_REST* const handler) { + delete handler; + } + + void set_logging(bool _should_log) { + should_log = _should_log; + } + + bool get_logging() const { + return should_log; + } +}; + +class RGWLibIO; +class RGWRestfulIO; + +class RGWREST { + using x_header = basic_sstring; + boost::container::flat_set x_headers; + RGWRESTMgr mgr; + + static int preprocess(struct req_state *s, rgw::io::BasicClient* rio); +public: + RGWREST() {} + RGWHandler_REST *get_handler(RGWRados *store, + struct req_state *s, + const rgw::auth::StrategyRegistry& auth_registry, + const std::string& frontend_prefix, + RGWRestfulIO *rio, + RGWRESTMgr **pmgr, + int *init_error); +#if 0 + RGWHandler *get_handler(RGWRados *store, struct req_state *s, + RGWLibIO *io, RGWRESTMgr **pmgr, + int *init_error); +#endif + + void put_handler(RGWHandler_REST *handler) { + mgr.put_handler(handler); + } + + void register_resource(string resource, RGWRESTMgr *m, + bool register_empty = false) { + if (!register_empty && resource.empty()) + return; + + mgr.register_resource(resource, m); + } + + void register_default_mgr(RGWRESTMgr *m) { + mgr.register_default_mgr(m); + } + + void register_x_headers(const std::string& headers); + + bool log_x_headers(void) { + return (x_headers.size() > 0); + } + + bool log_x_header(const std::string& header) { + return (x_headers.find(header) != x_headers.end()); + } +}; + +static constexpr int64_t NO_CONTENT_LENGTH = -1; +static constexpr int64_t CHUNKED_TRANSFER_ENCODING = -2; + +extern void dump_errno(int http_ret, string& out); +extern void dump_errno(const struct rgw_err &err, string& out); +extern void dump_errno(struct req_state *s); +extern void dump_errno(struct req_state *s, int http_ret); +extern void end_header(struct req_state *s, + RGWOp* op = nullptr, + const char *content_type = nullptr, + const int64_t proposed_content_length = + NO_CONTENT_LENGTH, + bool force_content_type = false, + bool force_no_error = false); +extern void dump_start(struct req_state *s); +extern void list_all_buckets_start(struct req_state *s); +extern void dump_owner(struct req_state *s, const rgw_user& id, string& name, + const char *section = NULL); +extern void dump_header(struct req_state* s, + const boost::string_ref& name, + const boost::string_ref& val); +extern void dump_header(struct req_state* s, + const boost::string_ref& name, + ceph::buffer::list& bl); +extern void dump_header(struct req_state* s, + const boost::string_ref& name, + long long val); +extern void dump_header(struct req_state* s, + const boost::string_ref& name, + const utime_t& val); + +template +static inline void dump_header_prefixed(struct req_state* s, + const boost::string_ref& name_prefix, + const boost::string_ref& name, + Args&&... args) { + char full_name_buf[name_prefix.size() + name.size() + 1]; + const auto len = snprintf(full_name_buf, sizeof(full_name_buf), "%.*s%.*s", + static_cast(name_prefix.length()), + name_prefix.data(), + static_cast(name.length()), + name.data()); + boost::string_ref full_name(full_name_buf, len); + return dump_header(s, std::move(full_name), std::forward(args)...); +} + +template +static inline void dump_header_infixed(struct req_state* s, + const boost::string_ref& prefix, + const boost::string_ref& infix, + const boost::string_ref& sufix, + Args&&... args) { + char full_name_buf[prefix.size() + infix.size() + sufix.size() + 1]; + const auto len = snprintf(full_name_buf, sizeof(full_name_buf), "%.*s%.*s%.*s", + static_cast(prefix.length()), + prefix.data(), + static_cast(infix.length()), + infix.data(), + static_cast(sufix.length()), + sufix.data()); + boost::string_ref full_name(full_name_buf, len); + return dump_header(s, std::move(full_name), std::forward(args)...); +} + +template +static inline void dump_header_quoted(struct req_state* s, + const boost::string_ref& name, + const boost::string_ref& val) { + /* We need two extra bytes for quotes. */ + char qvalbuf[val.size() + 2 + 1]; + const auto len = snprintf(qvalbuf, sizeof(qvalbuf), "\"%.*s\"", + static_cast(val.length()), val.data()); + return dump_header(s, name, boost::string_ref(qvalbuf, len)); +} + +template +static inline void dump_header_if_nonempty(struct req_state* s, + const boost::string_ref& name, + const ValueT& value) { + if (name.length() > 0 && value.length() > 0) { + return dump_header(s, name, value); + } +} + +extern void dump_content_length(struct req_state *s, uint64_t len); +extern int64_t parse_content_length(const char *content_length); +extern void dump_etag(struct req_state *s, + const boost::string_ref& etag, + bool quoted = false); +extern void dump_etag(struct req_state *s, + ceph::buffer::list& bl_etag, + bool quoted = false); +extern void dump_epoch_header(struct req_state *s, const char *name, real_time t); +extern void dump_time_header(struct req_state *s, const char *name, real_time t); +extern void dump_last_modified(struct req_state *s, real_time t); +extern void abort_early(struct req_state* s, RGWOp* op, int err, + RGWHandler* handler); +extern void dump_range(struct req_state* s, uint64_t ofs, uint64_t end, + uint64_t total_size); +extern void dump_continue(struct req_state *s); +extern void list_all_buckets_end(struct req_state *s); +extern void dump_time(struct req_state *s, const char *name, real_time *t); +extern std::string dump_time_to_str(const real_time& t); +extern void dump_bucket_from_state(struct req_state *s); +extern void dump_uri_from_state(struct req_state *s); +extern void dump_redirect(struct req_state *s, const string& redirect); +extern bool is_valid_url(const char *url); +extern void dump_access_control(struct req_state *s, const char *origin, + const char *meth, + const char *hdr, const char *exp_hdr, + uint32_t max_age); +extern void dump_access_control(req_state *s, RGWOp *op); + +extern int dump_body(struct req_state* s, const char* buf, size_t len); +extern int dump_body(struct req_state* s, /* const */ ceph::buffer::list& bl); +extern int dump_body(struct req_state* s, const std::string& str); + +extern int recv_body(struct req_state* s, char* buf, size_t max); + +#endif /* CEPH_RGW_REST_H */