-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab ft=cpp
/*
*
* This is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
+ * License version 2.1, as published by the Free Software
* Foundation. See file COPYING.
- *
+ *
*/
#pragma once
#include <atomic>
#include <unordered_map>
+#include <fmt/format.h>
+
#include "common/ceph_crypto.h"
#include "common/random_string.h"
#include "rgw_acl.h"
#include "rgw_bucket_layout.h"
#include "rgw_cors.h"
+#include "rgw_basic_types.h"
#include "rgw_iam_policy.h"
-#include "rgw_quota.h"
+#include "rgw_quota_types.h"
#include "rgw_string.h"
#include "common/async/yield_context.h"
#include "rgw_website.h"
#include "include/rados/librados.hpp"
#include "rgw_public_access.h"
#include "common/tracer.h"
+#include "rgw_sal_fwd.h"
namespace ceph {
class Formatter;
}
namespace rgw::sal {
- class User;
- class Bucket;
- class Object;
using Attrs = std::map<std::string, ceph::buffer::list>;
}
+namespace rgw::lua {
+ class Background;
+}
+
+struct RGWProcessEnv;
+
using ceph::crypto::MD5;
#define RGW_ATTR_PREFIX "user.rgw."
#define RGW_ATTR_APPEND_PART_NUM RGW_ATTR_PREFIX "append_part_num"
+/* Attrs to store cloudtier config information. These are used internally
+ * for the replication of cloudtiered objects but not stored as xattrs in
+ * the head object. */
+#define RGW_ATTR_CLOUD_TIER_TYPE RGW_ATTR_PREFIX "cloud_tier_type"
+#define RGW_ATTR_CLOUD_TIER_CONFIG RGW_ATTR_PREFIX "cloud_tier_config"
+
+#define RGW_ATTR_OBJ_REPLICATION_STATUS RGW_ATTR_PREFIX "amz-replication-status"
+#define RGW_ATTR_OBJ_REPLICATION_TRACE RGW_ATTR_PREFIX "replication-trace"
+
/* IAM Policy */
#define RGW_ATTR_IAM_POLICY RGW_ATTR_PREFIX "iam-policy"
#define RGW_ATTR_USER_POLICY RGW_ATTR_PREFIX "user-policy"
#define RGW_ATTR_TRACE RGW_ATTR_PREFIX "trace"
-#define RGW_FORMAT_PLAIN 0
-#define RGW_FORMAT_XML 1
-#define RGW_FORMAT_JSON 2
-#define RGW_FORMAT_HTML 3
+enum class RGWFormat : int8_t {
+ BAD_FORMAT = -1,
+ PLAIN = 0,
+ XML,
+ JSON,
+ HTML,
+};
+
+static inline const char* to_mime_type(const RGWFormat f)
+{
+ switch (f) {
+ case RGWFormat::XML:
+ return "application/xml";
+ break;
+ case RGWFormat::JSON:
+ return "application/json";
+ break;
+ case RGWFormat::HTML:
+ return "text/html";
+ break;
+ case RGWFormat::PLAIN:
+ return "text/plain";
+ break;
+ default:
+ return "invalid format";
+ }
+}
#define RGW_CAP_READ 0x1
#define RGW_CAP_WRITE 0x2
#define RGW_REST_WEBSITE 0x8
#define RGW_REST_STS 0x10
#define RGW_REST_IAM 0x20
+#define RGW_REST_SNS 0x30
#define RGW_SUSPENDED_USER_AUID (uint64_t)-2
#define UINT32_MAX (0xffffffffu)
#endif
-struct req_state;
-
typedef void *RGWAccessHandle;
-enum RGWIntentEvent {
- DEL_OBJ = 0,
- DEL_DIR = 1,
-};
-
-enum HostStyle {
- PathStyle = 0,
- VirtualStyle = 1,
-};
-
-/** Store error returns for output at a different point in the program */
-struct rgw_err {
- rgw_err();
- void clear();
- bool is_clear() const;
- bool is_err() const;
- friend std::ostream& operator<<(std::ostream& oss, const rgw_err &err);
-
- int http_ret;
- int ret;
- std::string err_code;
- std::string message;
-};
-
-
/* Helper class used for RGWHTTPArgs parsing */
class NameVal
{
class RGWAccessControlPolicy;
class JSONObj;
-struct RGWAccessKey {
- std::string id; // AccessKey
- std::string key; // SecretKey
- std::string subuser;
-
- RGWAccessKey() {}
- RGWAccessKey(std::string _id, std::string _key)
- : id(std::move(_id)), key(std::move(_key)) {}
-
- void encode(bufferlist& bl) const {
- ENCODE_START(2, 2, bl);
- encode(id, bl);
- encode(key, bl);
- encode(subuser, bl);
- ENCODE_FINISH(bl);
- }
-
- void decode(bufferlist::const_iterator& bl) {
- DECODE_START_LEGACY_COMPAT_LEN_32(2, 2, 2, bl);
- decode(id, bl);
- decode(key, bl);
- decode(subuser, bl);
- DECODE_FINISH(bl);
- }
- void dump(Formatter *f) const;
- void dump_plain(Formatter *f) const;
- void dump(Formatter *f, const std::string& user, bool swift) const;
- static void generate_test_instances(std::list<RGWAccessKey*>& o);
-
- void decode_json(JSONObj *obj);
- void decode_json(JSONObj *obj, bool swift);
-};
-WRITE_CLASS_ENCODER(RGWAccessKey)
-
-struct RGWSubUser {
- std::string name;
- uint32_t perm_mask;
-
- RGWSubUser() : perm_mask(0) {}
- void encode(bufferlist& bl) const {
- ENCODE_START(2, 2, bl);
- encode(name, bl);
- encode(perm_mask, bl);
- ENCODE_FINISH(bl);
- }
-
- void decode(bufferlist::const_iterator& bl) {
- DECODE_START_LEGACY_COMPAT_LEN_32(2, 2, 2, bl);
- decode(name, bl);
- decode(perm_mask, bl);
- DECODE_FINISH(bl);
- }
- void dump(Formatter *f) const;
- void dump(Formatter *f, const std::string& user) const;
- static void generate_test_instances(std::list<RGWSubUser*>& o);
-
- void decode_json(JSONObj *obj);
-};
-WRITE_CLASS_ENCODER(RGWSubUser)
-
-class RGWUserCaps
-{
- std::map<std::string, uint32_t> caps;
-
- int get_cap(const std::string& cap, std::string& type, uint32_t *perm);
- int add_cap(const std::string& cap);
- int remove_cap(const std::string& cap);
-public:
- static int parse_cap_perm(const std::string& str, uint32_t *perm);
- int add_from_string(const std::string& str);
- int remove_from_string(const std::string& str);
-
- void encode(bufferlist& bl) const {
- ENCODE_START(1, 1, bl);
- encode(caps, bl);
- ENCODE_FINISH(bl);
- }
- void decode(bufferlist::const_iterator& bl) {
- DECODE_START(1, bl);
- decode(caps, bl);
- DECODE_FINISH(bl);
- }
- int check_cap(const std::string& cap, uint32_t perm) const;
- bool is_valid_cap_type(const std::string& tp);
- void dump(Formatter *f) const;
- void dump(Formatter *f, const char *name) const;
-
- void decode_json(JSONObj *obj);
-};
-WRITE_CLASS_ENCODER(RGWUserCaps)
-
void encode_json(const char *name, const obj_version& v, Formatter *f);
void encode_json(const char *name, const RGWUserCaps& val, Formatter *f);
void decode_json_obj(obj_version& v, JSONObj *obj);
-
-
enum RGWIdentityType
{
TYPE_NONE=0,
TYPE_WEB=5,
};
-static std::string RGW_STORAGE_CLASS_STANDARD = "STANDARD";
-
-struct rgw_placement_rule {
- std::string name;
- std::string storage_class;
-
- rgw_placement_rule() {}
- rgw_placement_rule(const std::string& _n, const std::string& _sc) : name(_n), storage_class(_sc) {}
- rgw_placement_rule(const rgw_placement_rule& _r, const std::string& _sc) : name(_r.name) {
- if (!_sc.empty()) {
- storage_class = _sc;
- } else {
- storage_class = _r.storage_class;
- }
- }
-
- bool empty() const {
- return name.empty() && storage_class.empty();
- }
-
- void inherit_from(const rgw_placement_rule& r) {
- if (name.empty()) {
- name = r.name;
- }
- if (storage_class.empty()) {
- storage_class = r.storage_class;
- }
- }
-
- void clear() {
- name.clear();
- storage_class.clear();
- }
-
- void init(const std::string& n, const std::string& c) {
- name = n;
- storage_class = c;
- }
-
- static const std::string& get_canonical_storage_class(const std::string& storage_class) {
- if (storage_class.empty()) {
- return RGW_STORAGE_CLASS_STANDARD;
- }
- return storage_class;
- }
-
- const std::string& get_storage_class() const {
- return get_canonical_storage_class(storage_class);
- }
-
- int compare(const rgw_placement_rule& r) const {
- int c = name.compare(r.name);
- if (c != 0) {
- return c;
- }
- return get_storage_class().compare(r.get_storage_class());
- }
-
- bool operator==(const rgw_placement_rule& r) const {
- return (name == r.name &&
- get_storage_class() == r.get_storage_class());
- }
-
- bool operator!=(const rgw_placement_rule& r) const {
- return !(*this == r);
- }
-
- void encode(bufferlist& bl) const {
- /* no ENCODE_START/END due to backward compatibility */
- std::string s = to_str();
- ceph::encode(s, bl);
- }
-
- void decode(bufferlist::const_iterator& bl) {
- std::string s;
- ceph::decode(s, bl);
- from_str(s);
- }
-
- std::string to_str() const {
- if (standard_storage_class()) {
- return name;
- }
- return to_str_explicit();
- }
-
- std::string to_str_explicit() const {
- return name + "/" + storage_class;
- }
-
- void from_str(const std::string& s) {
- size_t pos = s.find("/");
- if (pos == std::string::npos) {
- name = s;
- storage_class.clear();
- return;
- }
- name = s.substr(0, pos);
- storage_class = s.substr(pos + 1);
- }
-
- bool standard_storage_class() const {
- return storage_class.empty() || storage_class == RGW_STORAGE_CLASS_STANDARD;
- }
-};
-WRITE_CLASS_ENCODER(rgw_placement_rule)
-
void encode_json(const char *name, const rgw_placement_rule& val, ceph::Formatter *f);
void decode_json_obj(rgw_placement_rule& v, JSONObj *obj);
__u8 system;
rgw_placement_rule default_placement;
std::list<std::string> placement_tags;
- RGWQuotaInfo bucket_quota;
std::map<int, std::string> temp_url_keys;
- RGWQuotaInfo user_quota;
+ RGWQuota quota;
uint32_t type;
std::set<std::string> mfa_ids;
- std::string assumed_role_arn;
RGWUserInfo()
: suspended(0),
encode(system, bl);
encode(default_placement, bl);
encode(placement_tags, bl);
- encode(bucket_quota, bl);
+ encode(quota.bucket_quota, bl);
encode(temp_url_keys, bl);
- encode(user_quota, bl);
+ encode(quota.user_quota, bl);
encode(user_id.tenant, bl);
encode(admin, bl);
encode(type, bl);
encode(mfa_ids, bl);
- encode(assumed_role_arn, bl);
+ {
+ std::string assumed_role_arn; // removed
+ encode(assumed_role_arn, bl);
+ }
encode(user_id.ns, bl);
ENCODE_FINISH(bl);
}
decode(placement_tags, bl); /* tags of allowed placement rules */
}
if (struct_v >= 14) {
- decode(bucket_quota, bl);
+ decode(quota.bucket_quota, bl);
}
if (struct_v >= 15) {
decode(temp_url_keys, bl);
}
if (struct_v >= 16) {
- decode(user_quota, bl);
+ decode(quota.user_quota, bl);
}
if (struct_v >= 17) {
decode(user_id.tenant, bl);
decode(mfa_ids, bl);
}
if (struct_v >= 21) {
+ std::string assumed_role_arn; // removed
decode(assumed_role_arn, bl);
}
if (struct_v >= 22) {
};
WRITE_CLASS_ENCODER(RGWUserInfo)
-struct rgw_raw_obj {
- rgw_pool pool;
- std::string oid;
- std::string loc;
-
- rgw_raw_obj() {}
- rgw_raw_obj(const rgw_pool& _pool, const std::string& _oid) {
- init(_pool, _oid);
- }
- rgw_raw_obj(const rgw_pool& _pool, const std::string& _oid, const std::string& _loc) : loc(_loc) {
- init(_pool, _oid);
- }
-
- void init(const rgw_pool& _pool, const std::string& _oid) {
- pool = _pool;
- oid = _oid;
- }
-
- bool empty() const {
- return oid.empty();
- }
-
- void encode(bufferlist& bl) const {
- ENCODE_START(6, 6, bl);
- encode(pool, bl);
- encode(oid, bl);
- encode(loc, bl);
- ENCODE_FINISH(bl);
- }
-
- void decode_from_rgw_obj(bufferlist::const_iterator& bl);
-
- void decode(bufferlist::const_iterator& bl) {
- unsigned ofs = bl.get_off();
- DECODE_START(6, bl);
- if (struct_v < 6) {
- /*
- * this object was encoded as rgw_obj, prior to rgw_raw_obj been split out of it,
- * let's decode it as rgw_obj and convert it
- */
- bl.seek(ofs);
- decode_from_rgw_obj(bl);
- return;
- }
- decode(pool, bl);
- decode(oid, bl);
- decode(loc, bl);
- DECODE_FINISH(bl);
- }
-
- bool operator<(const rgw_raw_obj& o) const {
- int r = pool.compare(o.pool);
- if (r == 0) {
- r = oid.compare(o.oid);
- if (r == 0) {
- r = loc.compare(o.loc);
- }
- }
- return (r < 0);
- }
-
- bool operator==(const rgw_raw_obj& o) const {
- return (pool == o.pool && oid == o.oid && loc == o.loc);
- }
-
- void dump(Formatter *f) const;
- void decode_json(JSONObj *obj);
-};
-WRITE_CLASS_ENCODER(rgw_raw_obj)
-
-inline std::ostream& operator<<(std::ostream& out, const rgw_raw_obj& o) {
- out << o.pool << ":" << o.oid;
- return out;
-}
-
-struct rgw_bucket_placement {
- rgw_placement_rule placement_rule;
- rgw_bucket bucket;
-
- void dump(Formatter *f) const;
-};
-
+/// `RGWObjVersionTracker`
+/// ======================
+///
+/// What and why is this?
+/// ---------------------
+///
+/// This is a wrapper around `cls_version` functionality. If two RGWs
+/// (or two non-synchronized threads in the same RGW) are accessing
+/// the same object, they may race and overwrite each other's work.
+///
+/// This class solves this issue by tracking and recording an object's
+/// version in the extended attributes. Operations are failed with
+/// ECANCELED if the version is not what we expect.
+///
+/// How to Use It
+/// -------------
+///
+/// When preparing a read operation, call `prepare_op_for_read`.
+/// For a write, call `prepare_op_for_write` when preparing the
+/// operation, and `apply_write` after it succeeds.
+///
+/// Adhere to the following guidelines:
+///
+/// - Each RGWObjVersionTracker should be used with only one object.
+///
+/// - If you receive `ECANCELED`, throw away whatever you were doing
+/// based on the content of the versioned object, re-read, and
+/// restart as appropriate.
+///
+/// - If one code path uses RGWObjVersionTracker, then they all
+/// should. In a situation where a writer should unconditionally
+/// overwrite an object, call `generate_new_write_ver` on a default
+/// constructed `RGWObjVersionTracker`.
+///
+/// - If we have a version from a previous read, we will check against
+/// it and fail the read if it doesn't match. Thus, if we want to
+/// re-read a new version of the object, call `clear()` on the
+/// `RGWObjVersionTracker`.
+///
+/// - This type is not thread-safe. Every thread must have its own
+/// instance.
+///
struct RGWObjVersionTracker {
- obj_version read_version;
- obj_version write_version;
-
- obj_version *version_for_read() {
+ obj_version read_version; //< The version read from an object. If
+ // set, this value is used to check the
+ // stored version.
+ obj_version write_version; //< Set the object to this version on
+ // write, if set.
+
+ /// Pointer to the read version.
+ obj_version* version_for_read() {
return &read_version;
}
- obj_version *version_for_write() {
+ /// If we have a write version, return a pointer to it. Otherwise
+ /// return null. This is used in `prepare_op_for_write` to treat the
+ /// `write_version` as effectively an `option` type.
+ obj_version* version_for_write() {
if (write_version.ver == 0)
- return NULL;
+ return nullptr;
return &write_version;
}
- obj_version *version_for_check() {
+ /// If read_version is non-empty, return a pointer to it, otherwise
+ /// null. This is used internally by `prepare_op_for_read` and
+ /// `prepare_op_for_write` to treat the `read_version` as
+ /// effectively an `option` type.
+ obj_version* version_for_check() {
if (read_version.ver == 0)
- return NULL;
+ return nullptr;
return &read_version;
}
- void prepare_op_for_read(librados::ObjectReadOperation *op);
- void prepare_op_for_write(librados::ObjectWriteOperation *op);
-
+ /// This function is to be called on any read operation. If we have
+ /// a non-empty `read_version`, assert on the OSD that the object
+ /// has the same version. Also reads the version into `read_version`.
+ ///
+ /// This function is defined in `rgw_rados.cc` rather than `rgw_common.cc`.
+ void prepare_op_for_read(librados::ObjectReadOperation* op);
+
+ /// This function is to be called on any write operation. If we have
+ /// a non-empty read operation, assert on the OSD that the object
+ /// has the same version. If we have a non-empty `write_version`,
+ /// set the object to it. Otherwise increment the version on the OSD.
+ ///
+ /// This function is defined in `rgw_rados.cc` rather than
+ /// `rgw_common.cc`.
+ void prepare_op_for_write(librados::ObjectWriteOperation* op);
+
+ /// This function is to be called after the completion of any write
+ /// operation on which `prepare_op_for_write` was called. If we did
+ /// not set the write version explicitly, it increments
+ /// `read_version`. If we did, it sets `read_version` to
+ /// `write_version`. In either case, it clears `write_version`.
+ ///
+ /// RADOS write operations, at least those not using the relatively
+ /// new RETURNVEC flag, cannot return more information than an error
+ /// code. Thus, write operations can't simply fill in the read
+ /// version the way read operations can, so prepare_op_for_write`
+ /// instructs the OSD to increment the object as stored in RADOS and
+ /// `apply_write` increments our `read_version` in RAM.
+ ///
+ /// This function is defined in `rgw_rados.cc` rather than
+ /// `rgw_common.cc`.
void apply_write();
+ /// Clear `read_version` and `write_version`, making the instance
+ /// identical to a default-constructed instance.
void clear() {
read_version = obj_version();
write_version = obj_version();
}
- void generate_new_write_ver(CephContext *cct);
+ /// Set `write_version` to a new, unique version.
+ ///
+ /// An `obj_version` contains an opaque, random tag and a
+ /// sequence. If the tags of two `obj_version`s don't match, the
+ /// versions are unordered and unequal. This function creates a
+ /// version with a new tag, ensuring that any other process
+ /// operating on the object will receive `ECANCELED` and will know
+ /// to re-read the object and restart whatever it was doing.
+ void generate_new_write_ver(CephContext* cct);
};
inline std::ostream& operator<<(std::ostream& out, const obj_version &v)
// layout of bucket index objects
rgw::BucketLayout layout;
- // Represents the number of bucket index object shards:
- // - value of 0 indicates there is no sharding (this is by default
- // before this feature is implemented).
- // - value of UINT32_T::MAX indicates this is a blind bucket.
-
// Represents the shard number for blind bucket.
const static uint32_t NUM_SHARDS_BLIND_BUCKET;
bool empty_sync_policy() const;
+ bool is_indexless() const {
+ return rgw::is_layout_indexless(layout.current_index);
+ }
+ const rgw::bucket_index_layout_generation& get_current_index() const {
+ return layout.current_index;
+ }
+ rgw::bucket_index_layout_generation& get_current_index() {
+ return layout.current_index;
+ }
+
RGWBucketInfo();
~RGWBucketInfo();
};
void init_meta_info(const DoutPrefixProvider *dpp, bool *found_bad_meta);
};
-typedef cls_rgw_obj_key rgw_obj_index_key;
-
-struct rgw_obj_key {
- std::string name;
- std::string instance;
- std::string ns;
-
- rgw_obj_key() {}
- // cppcheck-suppress noExplicitConstructor
- rgw_obj_key(const std::string& n) : name(n) {}
- rgw_obj_key(const std::string& n, const std::string& i) : name(n), instance(i) {}
- rgw_obj_key(const std::string& n, const std::string& i, const std::string& _ns) : name(n), instance(i), ns(_ns) {}
-
- rgw_obj_key(const rgw_obj_index_key& k) {
- parse_index_key(k.name, &name, &ns);
- instance = k.instance;
- }
-
- static void parse_index_key(const std::string& key, std::string *name, std::string *ns) {
- if (key[0] != '_') {
- *name = key;
- ns->clear();
- return;
- }
- if (key[1] == '_') {
- *name = key.substr(1);
- ns->clear();
- return;
- }
- ssize_t pos = key.find('_', 1);
- if (pos < 0) {
- /* shouldn't happen, just use key */
- *name = key;
- ns->clear();
- return;
- }
-
- *name = key.substr(pos + 1);
- *ns = key.substr(1, pos -1);
- }
-
- void set(const std::string& n) {
- name = n;
- instance.clear();
- ns.clear();
- }
-
- void set(const std::string& n, const std::string& i) {
- name = n;
- instance = i;
- ns.clear();
- }
-
- void set(const std::string& n, const std::string& i, const std::string& _ns) {
- name = n;
- instance = i;
- ns = _ns;
- }
-
- bool set(const rgw_obj_index_key& index_key) {
- if (!parse_raw_oid(index_key.name, this)) {
- return false;
- }
- instance = index_key.instance;
- return true;
- }
-
- void set_instance(const std::string& i) {
- instance = i;
- }
-
- const std::string& get_instance() const {
- return instance;
- }
-
- void set_ns(const std::string& _ns) {
- ns = _ns;
- }
-
- const std::string& get_ns() const {
- return ns;
- }
-
- std::string get_index_key_name() const {
- if (ns.empty()) {
- if (name.size() < 1 || name[0] != '_') {
- return name;
- }
- return std::string("_") + name;
- };
-
- char buf[ns.size() + 16];
- snprintf(buf, sizeof(buf), "_%s_", ns.c_str());
- return std::string(buf) + name;
- };
-
- void get_index_key(rgw_obj_index_key *key) const {
- key->name = get_index_key_name();
- key->instance = instance;
- }
-
- std::string get_loc() const {
- /*
- * For backward compatibility. Older versions used to have object locator on all objects,
- * however, the name was the effective object locator. This had the same effect as not
- * having object locator at all for most objects but the ones that started with underscore as
- * these were escaped.
- */
- if (name[0] == '_' && ns.empty()) {
- return name;
- }
-
- return {};
- }
-
- bool empty() const {
- return name.empty();
- }
-
- bool have_null_instance() const {
- return instance == "null";
- }
-
- bool have_instance() const {
- return !instance.empty();
- }
-
- bool need_to_encode_instance() const {
- return have_instance() && !have_null_instance();
- }
-
- std::string get_oid() const {
- if (ns.empty() && !need_to_encode_instance()) {
- if (name.size() < 1 || name[0] != '_') {
- return name;
- }
- return std::string("_") + name;
- }
-
- std::string oid = "_";
- oid.append(ns);
- if (need_to_encode_instance()) {
- oid.append(std::string(":") + instance);
- }
- oid.append("_");
- oid.append(name);
- return oid;
- }
-
- bool operator==(const rgw_obj_key& k) const {
- return (name.compare(k.name) == 0) &&
- (instance.compare(k.instance) == 0);
- }
-
- bool operator<(const rgw_obj_key& k) const {
- int r = name.compare(k.name);
- if (r == 0) {
- r = instance.compare(k.instance);
- }
- return (r < 0);
- }
-
- bool operator<=(const rgw_obj_key& k) const {
- return !(k < *this);
- }
-
- static void parse_ns_field(std::string& ns, std::string& instance) {
- int pos = ns.find(':');
- if (pos >= 0) {
- instance = ns.substr(pos + 1);
- ns = ns.substr(0, pos);
- } else {
- instance.clear();
- }
- }
-
- // takes an oid and parses out the namespace (ns), name, and
- // instance
- static bool parse_raw_oid(const std::string& oid, rgw_obj_key *key) {
- key->instance.clear();
- key->ns.clear();
- if (oid[0] != '_') {
- key->name = oid;
- return true;
- }
-
- if (oid.size() >= 2 && oid[1] == '_') {
- key->name = oid.substr(1);
- return true;
- }
-
- if (oid.size() < 3) // for namespace, min size would be 3: _x_
- return false;
-
- size_t pos = oid.find('_', 2); // oid must match ^_[^_].+$
- if (pos == std::string::npos)
- return false;
-
- key->ns = oid.substr(1, pos - 1);
- parse_ns_field(key->ns, key->instance);
-
- key->name = oid.substr(pos + 1);
- return true;
- }
-
- /**
- * Translate a namespace-mangled object name to the user-facing name
- * existing in the given namespace.
- *
- * If the object is part of the given namespace, it returns true
- * and cuts down the name to the unmangled version. If it is not
- * part of the given namespace, it returns false.
- */
- static bool oid_to_key_in_ns(const std::string& oid, rgw_obj_key *key, const std::string& ns) {
- bool ret = parse_raw_oid(oid, key);
- if (!ret) {
- return ret;
- }
-
- return (ns == key->ns);
- }
-
- /**
- * Given a mangled object name and an empty namespace std::string, this
- * function extracts the namespace into the std::string and sets the object
- * name to be the unmangled version.
- *
- * It returns true after successfully doing so, or
- * false if it fails.
- */
- static bool strip_namespace_from_name(std::string& name, std::string& ns, std::string& instance) {
- ns.clear();
- instance.clear();
- if (name[0] != '_') {
- return true;
- }
-
- size_t pos = name.find('_', 1);
- if (pos == std::string::npos) {
- return false;
- }
-
- if (name[1] == '_') {
- name = name.substr(1);
- return true;
- }
-
- size_t period_pos = name.find('.');
- if (period_pos < pos) {
- return false;
- }
-
- ns = name.substr(1, pos-1);
- name = name.substr(pos+1, std::string::npos);
-
- parse_ns_field(ns, instance);
- return true;
- }
-
- void encode(bufferlist& bl) const {
- ENCODE_START(2, 1, bl);
- encode(name, bl);
- encode(instance, bl);
- encode(ns, bl);
- ENCODE_FINISH(bl);
- }
- void decode(bufferlist::const_iterator& bl) {
- DECODE_START(2, bl);
- decode(name, bl);
- decode(instance, bl);
- if (struct_v >= 2) {
- decode(ns, bl);
- }
- DECODE_FINISH(bl);
- }
- void dump(Formatter *f) const;
- void decode_json(JSONObj *obj);
-
- std::string to_str() const {
- if (instance.empty()) {
- return name;
- }
- char buf[name.size() + instance.size() + 16];
- snprintf(buf, sizeof(buf), "%s[%s]", name.c_str(), instance.c_str());
- return buf;
- }
-};
-WRITE_CLASS_ENCODER(rgw_obj_key)
-
-inline std::ostream& operator<<(std::ostream& out, const rgw_obj_key &o) {
- return out << o.to_str();
-}
-
struct req_init_state {
/* Keeps [[tenant]:]bucket until we parse the token. */
std::string url_bucket;
#include "rgw_auth.h"
class RGWObjectCtx;
-class RGWSysObjectCtx;
/** Store all the state necessary to complete and respond to an HTTP request*/
struct req_state : DoutPrefixProvider {
CephContext *cct;
+ const RGWProcessEnv& penv;
rgw::io::BasicClient *cio{nullptr};
http_op op{OP_UNKNOWN};
RGWOpType op_type{};
std::string ratelimit_bucket_marker;
std::string ratelimit_user_name;
bool content_started{false};
- int format{0};
+ RGWFormat format{RGWFormat::PLAIN};
ceph::Formatter *formatter{nullptr};
std::string decoded_uri;
std::string relative_uri;
Clock::duration time_elapsed() const { return Clock::now() - time; }
- RGWObjectCtx *obj_ctx{nullptr};
std::string dialect;
std::string req_id;
std::string trans_id;
std::vector<rgw::IAM::Policy> session_policies;
jspan trace;
+ bool trace_enabled = false;
//Principal tags that come in as part of AssumeRoleWithWebIdentity
std::vector<std::pair<std::string, std::string>> principal_tags;
- req_state(CephContext* _cct, RGWEnv* e, uint64_t id);
+ req_state(CephContext* _cct, const RGWProcessEnv& penv, RGWEnv* e, uint64_t id);
~req_state();
unsigned get_subsys() const override { return ceph_subsys_rgw; }
};
-void set_req_state_err(struct req_state*, int);
-void set_req_state_err(struct req_state*, int, const std::string&);
+void set_req_state_err(req_state*, int);
+void set_req_state_err(req_state*, int, const std::string&);
void set_req_state_err(struct rgw_err&, int, const int);
-void dump(struct req_state*);
+void dump(req_state*);
/** Store basic data on bucket */
struct RGWBucketEnt {
};
WRITE_CLASS_ENCODER(RGWBucketEnt)
-struct rgw_obj {
- rgw_bucket bucket;
- rgw_obj_key key;
-
- bool in_extra_data{false}; /* in-memory only member, does not serialize */
-
- // Represents the hash index source for this object once it is set (non-empty)
- std::string index_hash_source;
-
- rgw_obj() {}
- rgw_obj(const rgw_bucket& b, const std::string& name) : bucket(b), key(name) {}
- rgw_obj(const rgw_bucket& b, const rgw_obj_key& k) : bucket(b), key(k) {}
- rgw_obj(const rgw_bucket& b, const rgw_obj_index_key& k) : bucket(b), key(k) {}
-
- void init(const rgw_bucket& b, const std::string& name) {
- bucket = b;
- key.set(name);
- }
- void init(const rgw_bucket& b, const std::string& name, const std::string& i, const std::string& n) {
- bucket = b;
- key.set(name, i, n);
- }
- void init_ns(const rgw_bucket& b, const std::string& name, const std::string& n) {
- bucket = b;
- key.name = name;
- key.instance.clear();
- key.ns = n;
- }
-
- bool empty() const {
- return key.empty();
- }
-
- void set_key(const rgw_obj_key& k) {
- key = k;
- }
-
- std::string get_oid() const {
- return key.get_oid();
- }
-
- const std::string& get_hash_object() const {
- return index_hash_source.empty() ? key.name : index_hash_source;
- }
-
- void set_in_extra_data(bool val) {
- in_extra_data = val;
- }
-
- bool is_in_extra_data() const {
- return in_extra_data;
- }
-
- void encode(bufferlist& bl) const {
- ENCODE_START(6, 6, bl);
- encode(bucket, bl);
- encode(key.ns, bl);
- encode(key.name, bl);
- encode(key.instance, bl);
-// encode(placement_id, bl);
- ENCODE_FINISH(bl);
- }
- void decode(bufferlist::const_iterator& bl) {
- DECODE_START_LEGACY_COMPAT_LEN(6, 3, 3, bl);
- if (struct_v < 6) {
- std::string s;
- decode(bucket.name, bl); /* bucket.name */
- decode(s, bl); /* loc */
- decode(key.ns, bl);
- decode(key.name, bl);
- if (struct_v >= 2)
- decode(bucket, bl);
- if (struct_v >= 4)
- decode(key.instance, bl);
- if (key.ns.empty() && key.instance.empty()) {
- if (key.name[0] == '_') {
- key.name = key.name.substr(1);
- }
- } else {
- if (struct_v >= 5) {
- decode(key.name, bl);
- } else {
- ssize_t pos = key.name.find('_', 1);
- if (pos < 0) {
- throw buffer::malformed_input();
- }
- key.name = key.name.substr(pos + 1);
- }
- }
- } else {
- decode(bucket, bl);
- decode(key.ns, bl);
- decode(key.name, bl);
- decode(key.instance, bl);
-// decode(placement_id, bl);
- }
- DECODE_FINISH(bl);
- }
- void dump(Formatter *f) const;
- static void generate_test_instances(std::list<rgw_obj*>& o);
-
- bool operator==(const rgw_obj& o) const {
- return (key == o.key) &&
- (bucket == o.bucket);
- }
- bool operator<(const rgw_obj& o) const {
- int r = key.name.compare(o.key.name);
- if (r == 0) {
- r = bucket.bucket_id.compare(o.bucket.bucket_id); /* not comparing bucket.name, if bucket_id is equal so will be bucket.name */
- if (r == 0) {
- r = key.ns.compare(o.key.ns);
- if (r == 0) {
- r = key.instance.compare(o.key.instance);
- }
- }
- }
-
- return (r < 0);
- }
-
- const rgw_pool& get_explicit_data_pool() {
- if (!in_extra_data || bucket.explicit_placement.data_extra_pool.empty()) {
- return bucket.explicit_placement.data_pool;
- }
- return bucket.explicit_placement.data_extra_pool;
- }
-};
-WRITE_CLASS_ENCODER(rgw_obj)
-
struct rgw_cache_entry_info {
std::string cache_locator;
uint64_t gen;
extern boost::optional<std::pair<std::string_view,std::string_view>>
parse_key_value(const std::string_view& in_str);
+struct rgw_name_to_flag {
+ const char *type_name;
+ uint32_t flag;
+};
/** time parsing */
extern int parse_time(const char *time_str, real_time *time);
/** Check if the req_state's user has the necessary permissions
* to do the requested action */
-rgw::IAM::Effect eval_identity_or_session_policies(const std::vector<rgw::IAM::Policy>& user_policies,
+rgw::IAM::Effect eval_identity_or_session_policies(const DoutPrefixProvider* dpp,
+ const std::vector<rgw::IAM::Policy>& user_policies,
const rgw::IAM::Environment& env,
const uint64_t op,
const rgw::ARN& arn);
bool verify_user_permission(const DoutPrefixProvider* dpp,
- struct req_state * const s,
+ req_state * const s,
RGWAccessControlPolicy * const user_acl,
const std::vector<rgw::IAM::Policy>& user_policies,
const std::vector<rgw::IAM::Policy>& session_policies,
const rgw::ARN& res,
- const uint64_t op);
+ const uint64_t op,
+ bool mandatory_policy=true);
bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp,
- struct req_state * const s,
+ req_state * const s,
RGWAccessControlPolicy * const user_acl,
const int perm);
bool verify_user_permission(const DoutPrefixProvider* dpp,
- struct req_state * const s,
+ req_state * const s,
const rgw::ARN& res,
- const uint64_t op);
+ const uint64_t op,
+ bool mandatory_policy=true);
bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp,
- struct req_state * const s,
+ req_state * const s,
int perm);
bool verify_bucket_permission(
const DoutPrefixProvider* dpp,
- struct req_state * const s,
+ req_state * const s,
const rgw_bucket& bucket,
RGWAccessControlPolicy * const user_acl,
RGWAccessControlPolicy * const bucket_acl,
const std::vector<rgw::IAM::Policy>& identity_policies,
const std::vector<rgw::IAM::Policy>& session_policies,
const uint64_t op);
-bool verify_bucket_permission(const DoutPrefixProvider* dpp, struct req_state * const s, const uint64_t op);
+bool verify_bucket_permission(const DoutPrefixProvider* dpp, req_state * const s, const uint64_t op);
bool verify_bucket_permission_no_policy(
const DoutPrefixProvider* dpp,
- struct req_state * const s,
+ req_state * const s,
RGWAccessControlPolicy * const user_acl,
RGWAccessControlPolicy * const bucket_acl,
const int perm);
bool verify_bucket_permission_no_policy(const DoutPrefixProvider* dpp,
- struct req_state * const s,
+ req_state * const s,
const int perm);
-int verify_bucket_owner_or_policy(struct req_state* const s,
+int verify_bucket_owner_or_policy(req_state* const s,
const uint64_t op);
extern bool verify_object_permission(
const DoutPrefixProvider* dpp,
- struct req_state * const s,
+ req_state * const s,
const rgw_obj& obj,
RGWAccessControlPolicy * const user_acl,
RGWAccessControlPolicy * const bucket_acl,
const std::vector<rgw::IAM::Policy>& identity_policies,
const std::vector<rgw::IAM::Policy>& session_policies,
const uint64_t op);
-extern bool verify_object_permission(const DoutPrefixProvider* dpp, struct req_state *s, uint64_t op);
+extern bool verify_object_permission(const DoutPrefixProvider* dpp, req_state *s, uint64_t op);
extern bool verify_object_permission_no_policy(
const DoutPrefixProvider* dpp,
- struct req_state * const s,
+ req_state * const s,
RGWAccessControlPolicy * const user_acl,
RGWAccessControlPolicy * const bucket_acl,
RGWAccessControlPolicy * const object_acl,
int perm);
-extern bool verify_object_permission_no_policy(const DoutPrefixProvider* dpp, struct req_state *s,
+extern bool verify_object_permission_no_policy(const DoutPrefixProvider* dpp, req_state *s,
int perm);
extern int verify_object_lock(
const DoutPrefixProvider* dpp,
}
return 0;
}
+
+extern int rgw_bucket_parse_bucket_instance(const std::string& bucket_instance, std::string *bucket_name, std::string *bucket_id, int *shard_id);
+
+boost::intrusive_ptr<CephContext>
+rgw_global_init(const std::map<std::string,std::string> *defaults,
+ std::vector < const char* >& args,
+ uint32_t module_type, code_environment_t code_env,
+ int flags);