]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/rgw/rgw_rest_swift.cc
import ceph 15.2.14
[ceph.git] / ceph / src / rgw / rgw_rest_swift.cc
index a3ccdca781a634bb58c2fa1d7ed52ec1e9db3636..db3bb717014d699411cdb98969657b992e35235a 100644 (file)
@@ -1,11 +1,12 @@
 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
+// vim: ts=8 sw=2 smarttab ft=cpp
 
 #include <boost/algorithm/string/predicate.hpp>
+#include <boost/format.hpp>
 #include <boost/optional.hpp>
 #include <boost/utility/in_place_factory.hpp>
 
-#include "include/assert.h"
+#include "include/ceph_assert.h"
 #include "ceph_ver.h"
 
 #include "common/Formatter.h"
@@ -17,6 +18,7 @@
 #include "rgw_cors_swift.h"
 #include "rgw_formats.h"
 #include "rgw_client_io.h"
+#include "rgw_compression.h"
 
 #include "rgw_auth.h"
 #include "rgw_swift_auth.h"
 #include "rgw_request.h"
 #include "rgw_process.h"
 
+#include "rgw_zone.h"
+
+#include "services/svc_zone.h"
+
 #include <array>
 #include <sstream>
 #include <memory>
@@ -38,10 +44,15 @@ int RGWListBuckets_ObjStore_SWIFT::get_params()
   prefix = s->info.args.get("prefix");
   marker = s->info.args.get("marker");
   end_marker = s->info.args.get("end_marker");
+  wants_reversed = s->info.args.exists("reverse");
+
+  if (wants_reversed) {
+    std::swap(marker, end_marker);
+  }
 
-  string limit_str = s->info.args.get("limit");
+  std::string limit_str = s->info.args.get("limit");
   if (!limit_str.empty()) {
-    string err;
+    std::string err;
     long l = strict_strtol(limit_str.c_str(), 10, &err);
     if (!err.empty()) {
       return -EINVAL;
@@ -54,7 +65,7 @@ int RGWListBuckets_ObjStore_SWIFT::get_params()
     limit = (uint64_t)l;
   }
 
-  if (need_stats) {
+  if (s->cct->_conf->rgw_swift_need_stats) {
     bool stats, exists;
     int r = s->info.args.get_bool("stats", &stats, &exists);
 
@@ -65,16 +76,16 @@ int RGWListBuckets_ObjStore_SWIFT::get_params()
     if (exists) {
       need_stats = stats;
     }
+  } else {
+    need_stats = false;
   }
 
   return 0;
 }
 
 static void dump_account_metadata(struct req_state * const s,
-                                  const uint32_t buckets_count,
-                                  const uint64_t buckets_object_count,
-                                  const uint64_t buckets_size,
-                                  const uint64_t buckets_size_rounded,
+                                  const RGWUsageStats& global_stats,
+                                  const std::map<std::string, RGWUsageStats> &policies_stats,
                                   /* const */map<string, bufferlist>& attrs,
                                   const RGWQuotaInfo& quota,
                                   const RGWAccessControlPolicy_SWIFTAcct &policy)
@@ -82,20 +93,34 @@ static void dump_account_metadata(struct req_state * const s,
   /* Adding X-Timestamp to keep align with Swift API */
   dump_header(s, "X-Timestamp", ceph_clock_now());
 
-  dump_header(s, "X-Account-Container-Count", buckets_count);
-  dump_header(s, "X-Account-Object-Count", buckets_object_count);
-  dump_header(s, "X-Account-Bytes-Used", buckets_size);
-  dump_header(s, "X-Account-Bytes-Used-Actual", buckets_size_rounded);
+  dump_header(s, "X-Account-Container-Count", global_stats.buckets_count);
+  dump_header(s, "X-Account-Object-Count", global_stats.objects_count);
+  dump_header(s, "X-Account-Bytes-Used", global_stats.bytes_used);
+  dump_header(s, "X-Account-Bytes-Used-Actual", global_stats.bytes_used_rounded);
+
+  for (const auto& kv : policies_stats) {
+    const auto& policy_name = camelcase_dash_http_attr(kv.first);
+    const auto& policy_stats = kv.second;
+
+    dump_header_infixed(s, "X-Account-Storage-Policy-", policy_name,
+                        "-Container-Count", policy_stats.buckets_count);
+    dump_header_infixed(s, "X-Account-Storage-Policy-", policy_name,
+                        "-Object-Count", policy_stats.objects_count);
+    dump_header_infixed(s, "X-Account-Storage-Policy-", policy_name,
+                        "-Bytes-Used", policy_stats.bytes_used);
+    dump_header_infixed(s, "X-Account-Storage-Policy-", policy_name,
+                        "-Bytes-Used-Actual", policy_stats.bytes_used_rounded);
+  }
 
   /* Dump TempURL-related stuff */
   if (s->perm_mask == RGW_PERM_FULL_CONTROL) {
-    auto iter = s->user->temp_url_keys.find(0);
-    if (iter != std::end(s->user->temp_url_keys) && ! iter->second.empty()) {
+    auto iter = s->user->get_info().temp_url_keys.find(0);
+    if (iter != std::end(s->user->get_info().temp_url_keys) && ! iter->second.empty()) {
       dump_header(s, "X-Account-Meta-Temp-Url-Key", iter->second);
     }
 
-    iter = s->user->temp_url_keys.find(1);
-    if (iter != std::end(s->user->temp_url_keys) && ! iter->second.empty()) {
+    iter = s->user->get_info().temp_url_keys.find(1);
+    if (iter != std::end(s->user->get_info().temp_url_keys) && ! iter->second.empty()) {
       dump_header(s, "X-Account-Meta-Temp-Url-Key-2", iter->second);
     }
   }
@@ -130,10 +155,9 @@ static void dump_account_metadata(struct req_state * const s,
   }
 
   /* Dump account ACLs */
-  string acct_acl;
-  policy.to_str(acct_acl);
-  if (acct_acl.size()) {
-    dump_header(s, "X-Account-Access-Control", std::move(acct_acl));
+  auto account_acls = policy.to_str();
+  if (account_acls) {
+    dump_header(s, "X-Account-Access-Control", std::move(*account_acls));
   }
 }
 
@@ -149,27 +173,37 @@ void RGWListBuckets_ObjStore_SWIFT::send_response_begin(bool has_buckets)
   if (! s->cct->_conf->rgw_swift_enforce_content_length) {
     /* Adding account stats in the header to keep align with Swift API */
     dump_account_metadata(s,
-            buckets_count,
-            buckets_objcount,
-            buckets_size,
-            buckets_size_rounded,
+            global_stats,
+            policies_stats,
             attrs,
-            user_quota,
+            s->user->get_info().user_quota,
             static_cast<RGWAccessControlPolicy_SWIFTAcct&>(*s->user_acl));
     dump_errno(s);
+    dump_header(s, "Accept-Ranges", "bytes");
     end_header(s, NULL, NULL, NO_CONTENT_LENGTH, true);
   }
 
   if (! op_ret) {
     dump_start(s);
     s->formatter->open_array_section_with_attrs("account",
-            FormatterAttrs("name", s->user->display_name.c_str(), NULL));
+            FormatterAttrs("name", s->user->get_display_name().c_str(), NULL));
 
     sent_data = true;
   }
 }
 
-void RGWListBuckets_ObjStore_SWIFT::send_response_data(RGWUserBuckets& buckets)
+void RGWListBuckets_ObjStore_SWIFT::handle_listing_chunk(rgw::sal::RGWBucketList&& buckets)
+{
+  if (wants_reversed) {
+    /* Just store in the reversal buffer. Its content will be handled later,
+     * in send_response_end(). */
+    reverse_buffer.emplace(std::begin(reverse_buffer), std::move(buckets));
+  } else {
+    return send_response_data(buckets);
+  }
+}
+
+void RGWListBuckets_ObjStore_SWIFT::send_response_data(rgw::sal::RGWBucketList& buckets)
 {
   if (! sent_data) {
     return;
@@ -179,27 +213,65 @@ void RGWListBuckets_ObjStore_SWIFT::send_response_data(RGWUserBuckets& buckets)
    * in applying the filter earlier as we really need to go through all
    * entries regardless of it (the headers like X-Account-Container-Count
    * aren't affected by specifying prefix). */
-  const std::map<std::string, RGWBucketEnt>& m = buckets.get_buckets();
+  const std::map<std::string, rgw::sal::RGWBucket*>& m = buckets.get_buckets();
   for (auto iter = m.lower_bound(prefix);
        iter != m.end() && boost::algorithm::starts_with(iter->first, prefix);
        ++iter) {
-    const RGWBucketEnt& obj = iter->second;
+    dump_bucket_entry(*iter->second);
+  }
+}
 
-    s->formatter->open_object_section("container");
-    s->formatter->dump_string("name", obj.bucket.name);
-    if (need_stats) {
-      s->formatter->dump_int("count", obj.count);
-      s->formatter->dump_int("bytes", obj.size);
-    }
-    s->formatter->close_section();
-    if (! s->cct->_conf->rgw_swift_enforce_content_length) {
-      rgw_flush_formatter(s, s->formatter);
-    }
+void RGWListBuckets_ObjStore_SWIFT::dump_bucket_entry(const rgw::sal::RGWBucket& obj)
+{
+  s->formatter->open_object_section("container");
+  s->formatter->dump_string("name", obj.get_name());
+
+  if (need_stats) {
+    s->formatter->dump_int("count", obj.get_count());
+    s->formatter->dump_int("bytes", obj.get_size());
+  }
+
+  s->formatter->close_section();
+
+  if (! s->cct->_conf->rgw_swift_enforce_content_length) {
+    rgw_flush_formatter(s, s->formatter);
+  }
+}
+
+void RGWListBuckets_ObjStore_SWIFT::send_response_data_reversed(rgw::sal::RGWBucketList& buckets)
+{
+  if (! sent_data) {
+    return;
+  }
+
+  /* Take care of the prefix parameter of Swift API. There is no business
+   * in applying the filter earlier as we really need to go through all
+   * entries regardless of it (the headers like X-Account-Container-Count
+   * aren't affected by specifying prefix). */
+  std::map<std::string, rgw::sal::RGWBucket*>& m = buckets.get_buckets();
+
+  auto iter = m.rbegin();
+  for (/* initialized above */;
+       iter != m.rend() && !boost::algorithm::starts_with(iter->first, prefix);
+       ++iter) {
+    /* NOP */;
+  }
+
+  for (/* iter carried */;
+       iter != m.rend() && boost::algorithm::starts_with(iter->first, prefix);
+       ++iter) {
+    dump_bucket_entry(*iter->second);
   }
 }
 
 void RGWListBuckets_ObjStore_SWIFT::send_response_end()
 {
+  if (wants_reversed) {
+    for (auto& buckets : reverse_buffer) {
+      send_response_data_reversed(buckets);
+    }
+  }
+
   if (sent_data) {
     s->formatter->close_section();
   }
@@ -207,15 +279,13 @@ void RGWListBuckets_ObjStore_SWIFT::send_response_end()
   if (s->cct->_conf->rgw_swift_enforce_content_length) {
     /* Adding account stats in the header to keep align with Swift API */
     dump_account_metadata(s,
-            buckets_count,
-            buckets_objcount,
-            buckets_size,
-            buckets_size_rounded,
+            global_stats,
+            policies_stats,
             attrs,
-            user_quota,
+            s->user->get_info().user_quota,
             static_cast<RGWAccessControlPolicy_SWIFTAcct&>(*s->user_acl));
     dump_errno(s);
-    end_header(s, NULL, NULL, s->formatter->get_len(), true);
+    end_header(s, nullptr, nullptr, s->formatter->get_len(), true);
   }
 
   if (sent_data || s->cct->_conf->rgw_swift_enforce_content_length) {
@@ -229,15 +299,21 @@ int RGWListBucket_ObjStore_SWIFT::get_params()
   marker = s->info.args.get("marker");
   end_marker = s->info.args.get("end_marker");
   max_keys = s->info.args.get("limit");
+
+  // non-standard
+  s->info.args.get_bool("allow_unordered", &allow_unordered, false);
+
+  delimiter = s->info.args.get("delimiter");
+
   op_ret = parse_max_keys();
   if (op_ret < 0) {
     return op_ret;
   }
+  // S3 behavior is to silently cap the max-keys.
+  // Swift behavior is to abort.
   if (max > default_max)
     return -ERR_PRECONDITION_FAILED;
 
-  delimiter = s->info.args.get("delimiter");
-
   string path_args;
   if (s->info.args.exists("path")) { // should handle empty path
     path_args = s->info.args.get("path");
@@ -264,7 +340,7 @@ int RGWListBucket_ObjStore_SWIFT::get_params()
 }
 
 static void dump_container_metadata(struct req_state *,
-                                    const RGWBucketEnt&,
+                                    const rgw::sal::RGWBucket*,
                                     const RGWQuotaInfo&,
                                     const RGWBucketWebsiteConf&);
 
@@ -277,7 +353,10 @@ void RGWListBucket_ObjStore_SWIFT::send_response()
   dump_container_metadata(s, bucket, bucket_quota,
                           s->bucket_info.website_conf);
 
-  s->formatter->open_array_section_with_attrs("container", FormatterAttrs("name", s->bucket.name.c_str(), NULL));
+  s->formatter->open_array_section_with_attrs("container",
+                                             FormatterAttrs("name",
+                                                            s->bucket.name.c_str(),
+                                                            NULL));
 
   while (iter != objs.end() || pref_iter != common_prefixes.end()) {
     bool do_pref = false;
@@ -298,7 +377,7 @@ void RGWListBucket_ObjStore_SWIFT::send_response()
     else
       do_pref = true;
 
-    if (do_objs && (marker.empty() || marker < key)) {
+    if (do_objs && (allow_unordered || marker.empty() || marker < key)) {
       if (key.name.compare(path) == 0)
         goto next;
 
@@ -368,22 +447,23 @@ next:
   }
 
   rgw_flush_formatter_and_reset(s, s->formatter);
-}
+} // RGWListBucket_ObjStore_SWIFT::send_response
 
 static void dump_container_metadata(struct req_state *s,
-                                    const RGWBucketEnt& bucket,
+                                    const rgw::sal::RGWBucket* bucket,
                                     const RGWQuotaInfo& quota,
                                     const RGWBucketWebsiteConf& ws_conf)
 {
   /* Adding X-Timestamp to keep align with Swift API */
   dump_header(s, "X-Timestamp", utime_t(s->bucket_info.creation_time));
 
-  dump_header(s, "X-Container-Object-Count", bucket.count);
-  dump_header(s, "X-Container-Bytes-Used", bucket.size);
-  dump_header(s, "X-Container-Bytes-Used-Actual", bucket.size_rounded);
+  dump_header(s, "X-Container-Object-Count", bucket->get_count());
+  dump_header(s, "X-Container-Bytes-Used", bucket->get_size());
+  dump_header(s, "X-Container-Bytes-Used-Actual", bucket->get_size_rounded());
 
   if (s->object.empty()) {
-    auto swift_policy = static_cast<RGWAccessControlPolicy_SWIFT*>(s->bucket_acl);
+    auto swift_policy = \
+      static_cast<RGWAccessControlPolicy_SWIFT*>(s->bucket_acl.get());
     std::string read_acl, write_acl;
     swift_policy->to_str(read_acl, write_acl);
 
@@ -393,9 +473,10 @@ static void dump_container_metadata(struct req_state *s,
     if (write_acl.size()) {
       dump_header(s, "X-Container-Write", write_acl);
     }
-    if (!s->bucket_info.placement_rule.empty()) {
-      dump_header(s, "X-Storage-Policy", s->bucket_info.placement_rule);
+    if (!s->bucket_info.placement_rule.name.empty()) {
+      dump_header(s, "X-Storage-Policy", s->bucket_info.placement_rule.name);
     }
+    dump_header(s, "X-Storage-Class", s->bucket_info.placement_rule.get_storage_class());
 
     /* Dump user-defined metadata items and generic attrs. */
     const size_t PREFIX_LEN = sizeof(RGW_ATTR_META_PREFIX) - 1;
@@ -455,12 +536,16 @@ static void dump_container_metadata(struct req_state *s,
   if (ws_conf.listing_enabled) {
     dump_header(s, "X-Container-Meta-Web-Listings", "true");
   }
+
+  /* Dump bucket's modification time. Compliance with the Swift API really
+   * needs that. */
+  dump_last_modified(s, s->bucket_mtime);
 }
 
 void RGWStatAccount_ObjStore_SWIFT::execute()
 {
   RGWStatAccount_ObjStore::execute();
-  op_ret = rgw_get_user_attrs_by_uid(store, s->user->user_id, attrs);
+  op_ret = store->ctl()->user->get_attrs_by_uid(s->user->get_id(), &attrs, s->yield);
 }
 
 void RGWStatAccount_ObjStore_SWIFT::send_response()
@@ -468,12 +553,10 @@ void RGWStatAccount_ObjStore_SWIFT::send_response()
   if (op_ret >= 0) {
     op_ret = STATUS_NO_CONTENT;
     dump_account_metadata(s,
-            buckets_count,
-            buckets_objcount,
-            buckets_size,
-            buckets_size_rounded,
+            global_stats,
+            policies_stats,
             attrs,
-            user_quota,
+            s->user->get_info().user_quota,
             static_cast<RGWAccessControlPolicy_SWIFTAcct&>(*s->user_acl));
   }
 
@@ -501,31 +584,23 @@ void RGWStatBucket_ObjStore_SWIFT::send_response()
 }
 
 static int get_swift_container_settings(req_state * const s,
-                                        RGWRados * const store,
+                                        rgw::sal::RGWRadosStore * const store,
                                         RGWAccessControlPolicy * const policy,
                                         bool * const has_policy,
                                         uint32_t * rw_mask,
                                         RGWCORSConfiguration * const cors_config,
                                         bool * const has_cors)
 {
-  string read_list, write_list;
-
-  const char * const read_attr = s->info.env->get("HTTP_X_CONTAINER_READ");
-  if (read_attr) {
-    read_list = read_attr;
-  }
-  const char * const write_attr = s->info.env->get("HTTP_X_CONTAINER_WRITE");
-  if (write_attr) {
-    write_list = write_attr;
-  }
+  const char * const read_list = s->info.env->get("HTTP_X_CONTAINER_READ");
+  const char * const write_list = s->info.env->get("HTTP_X_CONTAINER_WRITE");
 
   *has_policy = false;
 
-  if (read_attr || write_attr) {
+  if (read_list || write_list) {
     RGWAccessControlPolicy_SWIFT swift_policy(s->cct);
-    const auto r = swift_policy.create(store,
-                                       s->user->user_id,
-                                       s->user->display_name,
+    const auto r = swift_policy.create(store->ctl()->user,
+                                       s->user->get_id(),
+                                       s->user->get_display_name(),
                                        read_list,
                                        write_list,
                                        *rw_mask);
@@ -633,24 +708,52 @@ int RGWCreateBucket_ObjStore_SWIFT::get_params()
   }
 
   if (!has_policy) {
-    policy.create_default(s->user->user_id, s->user->display_name);
+    policy.create_default(s->user->get_id(), s->user->get_display_name());
   }
 
-  location_constraint = store->get_zonegroup().api_name;
+  location_constraint = store->svc()->zone->get_zonegroup().api_name;
   get_rmattrs_from_headers(s, CONT_PUT_ATTR_PREFIX,
                            CONT_REMOVE_ATTR_PREFIX, rmattr_names);
-  placement_rule = s->info.env->get("HTTP_X_STORAGE_POLICY", "");
+  placement_rule.init(s->info.env->get("HTTP_X_STORAGE_POLICY", ""), s->info.storage_class);
 
   return get_swift_versioning_settings(s, swift_ver_location);
 }
 
+static inline int handle_metadata_errors(req_state* const s, const int op_ret)
+{
+  if (op_ret == -EFBIG) {
+    /* Handle the custom error message of exceeding maximum custom attribute
+     * (stored as xattr) size. */
+    const auto error_message = boost::str(
+      boost::format("Metadata value longer than %lld")
+        % s->cct->_conf.get_val<Option::size_t>("rgw_max_attr_size"));
+    set_req_state_err(s, EINVAL, error_message);
+    return -EINVAL;
+  } else if (op_ret == -E2BIG) {
+    const auto error_message = boost::str(
+      boost::format("Too many metadata items; max %lld")
+        % s->cct->_conf.get_val<uint64_t>("rgw_max_attrs_num_in_req"));
+    set_req_state_err(s, EINVAL, error_message);
+    return -EINVAL;
+  }
+
+  return op_ret;
+}
+
 void RGWCreateBucket_ObjStore_SWIFT::send_response()
 {
-  if (! op_ret)
-    op_ret = STATUS_CREATED;
-  else if (op_ret == -ERR_BUCKET_EXISTS)
-    op_ret = STATUS_ACCEPTED;
-  set_req_state_err(s, op_ret);
+  const auto meta_ret = handle_metadata_errors(s, op_ret);
+  if (meta_ret != op_ret) {
+    op_ret = meta_ret;
+  } else {
+    if (!op_ret) {
+      op_ret = STATUS_CREATED;
+    } else if (op_ret == -ERR_BUCKET_EXISTS) {
+      op_ret = STATUS_ACCEPTED;
+    }
+    set_req_state_err(s, op_ret);
+  }
+
   dump_errno(s);
   /* Propose ending HTTP header with 0 Content-Length header. */
   end_header(s, NULL, NULL, 0);
@@ -721,6 +824,95 @@ int RGWPutObj_ObjStore_SWIFT::verify_permission()
   }
 }
 
+int RGWPutObj_ObjStore_SWIFT::update_slo_segment_size(rgw_slo_entry& entry) {
+
+  int r = 0;
+  const string& path = entry.path;
+
+  /* If the path starts with slashes, strip them all. */
+  const size_t pos_init = path.find_first_not_of('/');
+
+  if (pos_init == string::npos) {
+    return -EINVAL;
+  }
+
+  const size_t pos_sep = path.find('/', pos_init);
+  if (pos_sep == string::npos) {
+    return -EINVAL;
+  }
+
+  string bucket_name = path.substr(pos_init, pos_sep - pos_init);
+  string obj_name = path.substr(pos_sep + 1);
+
+  rgw_bucket bucket;
+
+  RGWBucketInfo *pbucket_info = nullptr;
+  RGWBucketInfo bucket_info;
+  if (bucket_name.compare(s->bucket.name) != 0) {
+    map<string, bufferlist> bucket_attrs;
+    r = store->getRados()->get_bucket_info(store->svc(), s->user->get_id().tenant,
+                              bucket_name, bucket_info, nullptr,
+                              s->yield, &bucket_attrs);
+    if (r < 0) {
+      ldpp_dout(this, 0) << "could not get bucket info for bucket="
+                        << bucket_name << dendl;
+      return r;
+    }
+    bucket = bucket_info.bucket;
+    pbucket_info = &bucket_info;
+  } else {
+    bucket = s->bucket;
+    pbucket_info = &s->bucket_info;
+  }
+
+  /* fetch the stored size of the seg (or error if not valid) */
+  rgw_obj_key slo_key(obj_name);
+  rgw_obj slo_seg(bucket, slo_key);
+
+  /* no prefetch */
+  RGWObjectCtx obj_ctx(store);
+  obj_ctx.set_atomic(slo_seg);
+
+  RGWRados::Object op_target(store->getRados(), *pbucket_info, obj_ctx, slo_seg);
+  RGWRados::Object::Read read_op(&op_target);
+
+  bool compressed;
+  RGWCompressionInfo cs_info;
+  map<std::string, buffer::list> attrs;
+  uint64_t size_bytes{0};
+
+  read_op.params.attrs = &attrs;
+  read_op.params.obj_size = &size_bytes;
+
+  r = read_op.prepare(s->yield);
+  if (r < 0) {
+    return r;
+  }
+
+  r = rgw_compression_info_from_attrset(attrs, compressed, cs_info);
+  if (r < 0) {
+    return -EIO;
+  }
+
+  if (compressed) {
+    size_bytes = cs_info.orig_size;
+  }
+
+  /* "When the PUT operation sees the multipart-manifest=put query
+   * parameter, it reads the request body and verifies that each
+   * segment object exists and that the sizes and ETags match. If
+   * there is a mismatch, the PUT operation fails."
+   */
+  if (entry.size_bytes &&
+      (entry.size_bytes != size_bytes)) {
+    return -EINVAL;
+  }
+
+  entry.size_bytes = size_bytes;
+
+  return 0;
+} /* RGWPutObj_ObjStore_SWIFT::update_slo_segment_sizes */
+
 int RGWPutObj_ObjStore_SWIFT::get_params()
 {
   if (s->has_bad_meta) {
@@ -730,7 +922,7 @@ int RGWPutObj_ObjStore_SWIFT::get_params()
   if (!s->length) {
     const char *encoding = s->info.env->get("HTTP_TRANSFER_ENCODING");
     if (!encoding || strcmp(encoding, "chunked") != 0) {
-      ldout(s->cct, 20) << "neither length nor chunked encoding" << dendl;
+      ldpp_dout(this, 20) << "neither length nor chunked encoding" << dendl;
       return -ERR_LENGTH_REQUIRED;
     }
 
@@ -740,7 +932,7 @@ int RGWPutObj_ObjStore_SWIFT::get_params()
   supplied_etag = s->info.env->get("HTTP_ETAG");
 
   if (!s->generic_attrs.count(RGW_ATTR_CONTENT_TYPE)) {
-    ldout(s->cct, 5) << "content type wasn't provided, trying to guess" << dendl;
+    ldpp_dout(this, 5) << "content type wasn't provided, trying to guess" << dendl;
     const char *suffix = strrchr(s->object.name.c_str(), '.');
     if (suffix) {
       suffix++;
@@ -754,11 +946,11 @@ int RGWPutObj_ObjStore_SWIFT::get_params()
     }
   }
 
-  policy.create_default(s->user->user_id, s->user->display_name);
+  policy.create_default(s->user->get_id(), s->user->get_display_name());
 
   int r = get_delete_at_param(s, delete_at);
   if (r < 0) {
-    ldout(s->cct, 5) << "ERROR: failed to get Delete-At param" << dendl;
+    ldpp_dout(this, 5) << "ERROR: failed to get Delete-At param" << dendl;
     return r;
   }
 
@@ -774,7 +966,7 @@ int RGWPutObj_ObjStore_SWIFT::get_params()
   string multipart_manifest = s->info.args.get("multipart-manifest", &exists);
   if (exists) {
     if (multipart_manifest != "put") {
-      ldout(s->cct, 5) << "invalid multipart-manifest http param: " << multipart_manifest << dendl;
+      ldpp_dout(this, 5) << "invalid multipart-manifest http param: " << multipart_manifest << dendl;
       return -EINVAL;
     }
 
@@ -783,25 +975,38 @@ int RGWPutObj_ObjStore_SWIFT::get_params()
     
     slo_info = new RGWSLOInfo;
     
-    int r = rgw_rest_get_json_input_keep_data(s->cct, s, slo_info->entries, max_len, &slo_info->raw_data, &slo_info->raw_data_len);
+    int r = 0;
+    std::tie(r, slo_info->raw_data) = rgw_rest_get_json_input_keep_data(s->cct, s, slo_info->entries, max_len);
     if (r < 0) {
-      ldout(s->cct, 5) << "failed to read input for slo r=" << r << dendl;
+      ldpp_dout(this, 5) << "failed to read input for slo r=" << r << dendl;
       return r;
     }
 
     if ((int64_t)slo_info->entries.size() > s->cct->_conf->rgw_max_slo_entries) {
-      ldout(s->cct, 5) << "too many entries in slo request: " << slo_info->entries.size() << dendl;
+      ldpp_dout(this, 5) << "too many entries in slo request: " << slo_info->entries.size() << dendl;
       return -EINVAL;
     }
 
     MD5 etag_sum;
     uint64_t total_size = 0;
-    for (const auto& entry : slo_info->entries) {
-      etag_sum.Update((const byte *)entry.etag.c_str(),
+    for (auto& entry : slo_info->entries) {
+      etag_sum.Update((const unsigned char *)entry.etag.c_str(),
                       entry.etag.length());
+
+      /* if size_bytes == 0, it should be replaced with the
+       * real segment size (which could be 0);  this follows from the
+       * fact that Swift requires all segments to exist, but permits
+       * the size_bytes element to be omitted from the SLO manifest, see
+       * https://docs.openstack.org/swift/latest/api/large_objects.html
+       */
+      r = update_slo_segment_size(entry);
+      if (r < 0) {
+       return r;
+      }
+
       total_size += entry.size_bytes;
 
-      ldout(s->cct, 20) << "slo_part: " << entry.path
+      ldpp_dout(this, 20) << "slo_part: " << entry.path
                         << " size=" << entry.size_bytes
                         << " etag=" << entry.etag
                         << dendl;
@@ -809,7 +1014,7 @@ int RGWPutObj_ObjStore_SWIFT::get_params()
     complete_etag(etag_sum, &lo_etag);
     slo_info->total_size = total_size;
 
-    ofs = slo_info->raw_data_len;
+    ofs = slo_info->raw_data.length();
   }
 
   return RGWPutObj_ObjStore::get_params();
@@ -817,8 +1022,14 @@ int RGWPutObj_ObjStore_SWIFT::get_params()
 
 void RGWPutObj_ObjStore_SWIFT::send_response()
 {
-  if (! op_ret) {
-    op_ret = STATUS_CREATED;
+  const auto meta_ret = handle_metadata_errors(s, op_ret);
+  if (meta_ret) {
+    op_ret = meta_ret;
+  } else {
+    if (!op_ret) {
+      op_ret = STATUS_CREATED;
+    }
+    set_req_state_err(s, op_ret);
   }
 
   if (! lo_etag.empty()) {
@@ -843,7 +1054,7 @@ void RGWPutObj_ObjStore_SWIFT::send_response()
 }
 
 static int get_swift_account_settings(req_state * const s,
-                                      RGWRados * const store,
+                                      rgw::sal::RGWRadosStore * const store,
                                       RGWAccessControlPolicy_SWIFTAcct * const policy,
                                       bool * const has_policy)
 {
@@ -852,9 +1063,9 @@ static int get_swift_account_settings(req_state * const s,
   const char * const acl_attr = s->info.env->get("HTTP_X_ACCOUNT_ACCESS_CONTROL");
   if (acl_attr) {
     RGWAccessControlPolicy_SWIFTAcct swift_acct_policy(s->cct);
-    const bool r = swift_acct_policy.create(store,
-                                     s->user->user_id,
-                                     s->user->display_name,
+    const bool r = swift_acct_policy.create(store->ctl()->user,
+                                     s->user->get_id(),
+                                     s->user->get_display_name(),
                                      string(acl_attr));
     if (r != true) {
       return -EINVAL;
@@ -890,10 +1101,16 @@ int RGWPutMetadataAccount_ObjStore_SWIFT::get_params()
 
 void RGWPutMetadataAccount_ObjStore_SWIFT::send_response()
 {
-  if (! op_ret) {
-    op_ret = STATUS_NO_CONTENT;
+  const auto meta_ret = handle_metadata_errors(s, op_ret);
+  if (meta_ret != op_ret) {
+    op_ret = meta_ret;
+  } else {
+    if (!op_ret) {
+      op_ret = STATUS_NO_CONTENT;
+    }
+    set_req_state_err(s, op_ret);
   }
-  set_req_state_err(s, op_ret);
+
   dump_errno(s);
   end_header(s, this);
   rgw_flush_formatter_and_reset(s, s->formatter);
@@ -913,17 +1130,23 @@ int RGWPutMetadataBucket_ObjStore_SWIFT::get_params()
 
   get_rmattrs_from_headers(s, CONT_PUT_ATTR_PREFIX, CONT_REMOVE_ATTR_PREFIX,
                           rmattr_names);
-  placement_rule = s->info.env->get("HTTP_X_STORAGE_POLICY", "");
+  placement_rule.init(s->info.env->get("HTTP_X_STORAGE_POLICY", ""), s->info.storage_class);
 
   return get_swift_versioning_settings(s, swift_ver_location);
 }
 
 void RGWPutMetadataBucket_ObjStore_SWIFT::send_response()
 {
-  if (!op_ret && (op_ret != -EINVAL)) {
-    op_ret = STATUS_NO_CONTENT;
+  const auto meta_ret = handle_metadata_errors(s, op_ret);
+  if (meta_ret != op_ret) {
+    op_ret = meta_ret;
+  } else {
+    if (!op_ret && (op_ret != -EINVAL)) {
+      op_ret = STATUS_NO_CONTENT;
+    }
+    set_req_state_err(s, op_ret);
   }
-  set_req_state_err(s, op_ret);
+
   dump_errno(s);
   end_header(s, this);
   rgw_flush_formatter_and_reset(s, s->formatter);
@@ -938,11 +1161,10 @@ int RGWPutMetadataObject_ObjStore_SWIFT::get_params()
   /* Handle Swift object expiration. */
   int r = get_delete_at_param(s, delete_at);
   if (r < 0) {
-    ldout(s->cct, 5) << "ERROR: failed to get Delete-At param" << dendl;
+    ldpp_dout(this, 5) << "ERROR: failed to get Delete-At param" << dendl;
     return r;
   }
 
-  placement_rule = s->info.env->get("HTTP_X_STORAGE_POLICY", "");
   dlo_manifest = s->info.env->get("HTTP_X_OBJECT_MANIFEST");
 
   return 0;
@@ -950,13 +1172,20 @@ int RGWPutMetadataObject_ObjStore_SWIFT::get_params()
 
 void RGWPutMetadataObject_ObjStore_SWIFT::send_response()
 {
-  if (! op_ret) {
-    op_ret = STATUS_ACCEPTED;
+  const auto meta_ret = handle_metadata_errors(s, op_ret);
+  if (meta_ret != op_ret) {
+    op_ret = meta_ret;
+  } else {
+    if (!op_ret) {
+      op_ret = STATUS_ACCEPTED;
+    }
+    set_req_state_err(s, op_ret);
   }
-  set_req_state_err(s, op_ret);
+
   if (!s->is_err()) {
     dump_content_length(s, 0);
   }
+
   dump_errno(s);
   end_header(s, this);
   rgw_flush_formatter_and_reset(s, s->formatter);
@@ -1088,12 +1317,12 @@ static void get_contype_from_attrs(map<string, bufferlist>& attrs,
 {
   map<string, bufferlist>::iterator iter = attrs.find(RGW_ATTR_CONTENT_TYPE);
   if (iter != attrs.end()) {
-    content_type = iter->second.c_str();
+    content_type = rgw_bl_str(iter->second);
   }
 }
 
-static void dump_object_metadata(struct req_state * const s,
-                                map<string, bufferlist> attrs)
+static void dump_object_metadata(const DoutPrefixProvider* dpp, struct req_state * const s,
+                                const map<string, bufferlist>& attrs)
 {
   map<string, string> response_attrs;
 
@@ -1102,9 +1331,9 @@ static void dump_object_metadata(struct req_state * const s,
     const auto aiter = rgw_to_http_attrs.find(name);
 
     if (aiter != std::end(rgw_to_http_attrs)) {
-      response_attrs[aiter->second] = kv.second.c_str();
+      response_attrs[aiter->second] = rgw_bl_str(kv.second);
     } else if (strcmp(name, RGW_ATTR_SLO_UINDICATOR) == 0) {
-      // this attr has an extra length prefix from ::encode() in prior versions
+      // this attr has an extra length prefix from encode() in prior versions
       dump_header(s, "X-Object-Meta-Static-Large-Object", "True");
     } else if (strncmp(name, RGW_ATTR_META_PREFIX,
                       sizeof(RGW_ATTR_META_PREFIX)-1) == 0) {
@@ -1136,12 +1365,12 @@ static void dump_object_metadata(struct req_state * const s,
   if (iter != std::end(attrs)) {
     utime_t delete_at;
     try {
-      ::decode(delete_at, iter->second);
+      decode(delete_at, iter->second);
       if (!delete_at.is_zero()) {
         dump_header(s, "X-Delete-At", delete_at.sec());
       }
     } catch (buffer::error& err) {
-      ldout(s->cct, 0) << "ERROR: cannot decode object's " RGW_ATTR_DELETE_AT
+      ldpp_dout(dpp, 0) << "ERROR: cannot decode object's " RGW_ATTR_DELETE_AT
                           " attr, ignoring"
                        << dendl;
     }
@@ -1150,7 +1379,7 @@ static void dump_object_metadata(struct req_state * const s,
 
 int RGWCopyObj_ObjStore_SWIFT::init_dest_policy()
 {
-  dest_policy.create_default(s->user->user_id, s->user->display_name);
+  dest_policy.create_default(s->user->get_id(), s->user->get_display_name());
 
   return 0;
 }
@@ -1178,7 +1407,7 @@ int RGWCopyObj_ObjStore_SWIFT::get_params()
 
   int r = get_delete_at_param(s, delete_at);
   if (r < 0) {
-    ldout(s->cct, 5) << "ERROR: failed to get Delete-At param" << dendl;
+    ldpp_dout(this, 5) << "ERROR: failed to get Delete-At param" << dendl;
     return r;
   }
 
@@ -1215,7 +1444,7 @@ void RGWCopyObj_ObjStore_SWIFT::dump_copy_info()
 
   /* Dump X-Copied-From-Account. */
   /* XXX tenant */
-  dump_header(s, "X-Copied-From-Account", url_encode(s->user->user_id.id));
+  dump_header(s, "X-Copied-From-Account", url_encode(s->user->get_id().id));
 
   /* Dump X-Copied-From-Last-Modified. */
   dump_time_header(s, "X-Copied-From-Last-Modified", src_mtime);
@@ -1233,7 +1462,7 @@ void RGWCopyObj_ObjStore_SWIFT::send_response()
     dump_last_modified(s, mtime);
     dump_copy_info();
     get_contype_from_attrs(attrs, content_type);
-    dump_object_metadata(s, attrs);
+    dump_object_metadata(this, s, attrs);
     end_header(s, this, !content_type.empty() ? content_type.c_str()
               : "binary/octet-stream");
   } else {
@@ -1324,12 +1553,12 @@ int RGWGetObj_ObjStore_SWIFT::send_response_data(bufferlist& bl,
     } else {
       auto iter = attrs.find(RGW_ATTR_ETAG);
       if (iter != attrs.end()) {
-        dump_etag(s, iter->second);
+        dump_etag(s, iter->second.to_str());
       }
     }
 
     get_contype_from_attrs(attrs, content_type);
-    dump_object_metadata(s, attrs);
+    dump_object_metadata(this, s, attrs);
   }
 
   end_header(s, this, !content_type.empty() ? content_type.c_str()
@@ -1384,7 +1613,7 @@ int RGWBulkDelete_ObjStore_SWIFT::get_data(
   while (cioin.getline(buf, sizeof(buf))) {
     string path_str(buf);
 
-    ldout(s->cct, 20) << "extracted Bulk Delete entry: " << path_str << dendl;
+    ldpp_dout(this, 20) << "extracted Bulk Delete entry: " << path_str << dendl;
 
     RGWBulkDelete::acct_path_t path;
 
@@ -1439,13 +1668,15 @@ std::unique_ptr<RGWBulkUploadOp::StreamGetter>
 RGWBulkUploadOp_ObjStore_SWIFT::create_stream()
 {
   class SwiftStreamGetter : public StreamGetter {
+    const DoutPrefixProvider* dpp;
     const size_t conlen;
     size_t curpos;
     req_state* const s;
 
   public:
-    SwiftStreamGetter(req_state* const s, const size_t conlen)
-      : conlen(conlen),
+    SwiftStreamGetter(const DoutPrefixProvider* dpp, req_state* const s, const size_t conlen)
+      : dpp(dpp),
+        conlen(conlen),
         curpos(0),
         s(s) {
     }
@@ -1458,7 +1689,7 @@ RGWBulkUploadOp_ObjStore_SWIFT::create_stream()
         static_cast<size_t>(s->cct->_conf->rgw_max_chunk_size);
       const size_t max_to_read = std::min({ want, conlen - curpos, max_chunk_size });
 
-      ldout(s->cct, 20) << "bulk_upload: get_at_most max_to_read="
+      ldpp_dout(dpp, 20) << "bulk_upload: get_at_most max_to_read="
                         << max_to_read
                         << ", dst.c_str()=" << reinterpret_cast<intptr_t>(dst.c_str()) << dendl;
 
@@ -1476,11 +1707,11 @@ RGWBulkUploadOp_ObjStore_SWIFT::create_stream()
     }
 
     ssize_t get_exactly(size_t want, ceph::bufferlist& dst) override {
-      ldout(s->cct, 20) << "bulk_upload: get_exactly want=" << want << dendl;
+      ldpp_dout(dpp, 20) << "bulk_upload: get_exactly want=" << want << dendl;
 
       /* FIXME: do this in a loop. */
       const auto ret = get_at_most(want, dst);
-      ldout(s->cct, 20) << "bulk_upload: get_exactly ret=" << ret << dendl;
+      ldpp_dout(dpp, 20) << "bulk_upload: get_exactly ret=" << ret << dendl;
       if (ret < 0) {
         return ret;
       } else if (static_cast<size_t>(ret) != want) {
@@ -1495,11 +1726,11 @@ RGWBulkUploadOp_ObjStore_SWIFT::create_stream()
     op_ret = -EINVAL;
     return nullptr;
   } else {
-    ldout(s->cct, 20) << "bulk upload: create_stream for length="
+    ldpp_dout(this, 20) << "bulk upload: create_stream for length="
                       << s->length << dendl;
 
     const size_t conlen = atoll(s->length);
-    return std::unique_ptr<SwiftStreamGetter>(new SwiftStreamGetter(s, conlen));
+    return std::unique_ptr<SwiftStreamGetter>(new SwiftStreamGetter(this, s, conlen));
   }
 }
 
@@ -1576,7 +1807,7 @@ void RGWGetCrossDomainPolicy_ObjStore_SWIFT::send_response()
      << R"(<!DOCTYPE cross-domain-policy SYSTEM )"
      << R"("http://www.adobe.com/xml/dtds/cross-domain-policy.dtd" >)" << "\n"
      << R"(<cross-domain-policy>)" << "\n"
-     << g_conf->rgw_cross_domain_policy << "\n"
+     << g_conf()->rgw_cross_domain_policy << "\n"
      << R"(</cross-domain-policy>)";
 
   dump_body(s, ss.str());
@@ -1603,7 +1834,7 @@ const vector<pair<string, RGWInfo_ObjStore_SWIFT::info>> RGWInfo_ObjStore_SWIFT:
     {"slo", {false, RGWInfo_ObjStore_SWIFT::list_slo_data}},
     {"account_quotas", {false, nullptr}},
     {"staticweb", {false, nullptr}},
-    {"tempauth", {false, nullptr}},
+    {"tempauth", {false, RGWInfo_ObjStore_SWIFT::list_tempauth_data}},
 };
 
 void RGWInfo_ObjStore_SWIFT::execute()
@@ -1615,7 +1846,7 @@ void RGWInfo_ObjStore_SWIFT::execute()
 
   if (!swiftinfo_sig.empty() &&
       !swiftinfo_expires.empty() &&
-      !is_expired(swiftinfo_expires, s->cct)) {
+      !is_expired(swiftinfo_expires, this)) {
     is_admin_info_enabled = true;
   }
 
@@ -1630,7 +1861,7 @@ void RGWInfo_ObjStore_SWIFT::execute()
       s->formatter->close_section();
     }
     else {
-      pair.second.list_data(*(s->formatter), *(s->cct->_conf), *store);
+      pair.second.list_data(*(s->formatter), s->cct->_conf, *store->getRados());
     }
   }
 
@@ -1649,23 +1880,41 @@ void RGWInfo_ObjStore_SWIFT::send_response()
 }
 
 void RGWInfo_ObjStore_SWIFT::list_swift_data(Formatter& formatter,
-                                              const md_config_t& config,
+                                              const ConfigProxy& config,
                                               RGWRados& store)
 {
   formatter.open_object_section("swift");
-  formatter.dump_int("max_file_size", config.rgw_max_put_size);
+  formatter.dump_int("max_file_size", config->rgw_max_put_size);
   formatter.dump_int("container_listing_limit", RGW_LIST_BUCKETS_LIMIT_MAX);
 
   string ceph_version(CEPH_GIT_NICE_VER);
   formatter.dump_string("version", ceph_version);
-  formatter.dump_int("max_meta_name_length", 81);
+
+  const size_t max_attr_name_len = \
+    g_conf().get_val<Option::size_t>("rgw_max_attr_name_len");
+  if (max_attr_name_len) {
+    const size_t meta_name_limit = \
+      max_attr_name_len - strlen(RGW_ATTR_PREFIX RGW_AMZ_META_PREFIX);
+    formatter.dump_int("max_meta_name_length", meta_name_limit);
+  }
+
+  const size_t meta_value_limit = g_conf().get_val<Option::size_t>("rgw_max_attr_size");
+  if (meta_value_limit) {
+    formatter.dump_int("max_meta_value_length", meta_value_limit);
+  }
+
+  const size_t meta_num_limit = \
+    g_conf().get_val<uint64_t>("rgw_max_attrs_num_in_req");
+  if (meta_num_limit) {
+    formatter.dump_int("max_meta_count", meta_num_limit);
+  }
 
   formatter.open_array_section("policies");
-  RGWZoneGroup& zonegroup = store.get_zonegroup();
+  const RGWZoneGroup& zonegroup = store.svc.zone->get_zonegroup();
 
   for (const auto& placement_targets : zonegroup.placement_targets) {
     formatter.open_object_section("policy");
-    if (placement_targets.second.name.compare(zonegroup.default_placement) == 0)
+    if (placement_targets.second.name.compare(zonegroup.default_placement.name) == 0)
       formatter.dump_bool("default", true);
     formatter.dump_string("name", placement_targets.second.name.c_str());
     formatter.close_section();
@@ -1678,8 +1927,16 @@ void RGWInfo_ObjStore_SWIFT::list_swift_data(Formatter& formatter,
   formatter.close_section();
 }
 
+void RGWInfo_ObjStore_SWIFT::list_tempauth_data(Formatter& formatter,
+                                                 const ConfigProxy& config,
+                                                 RGWRados& store)
+{
+  formatter.open_object_section("tempauth");
+  formatter.dump_bool("account_acls", true);
+  formatter.close_section();
+}
 void RGWInfo_ObjStore_SWIFT::list_tempurl_data(Formatter& formatter,
-                                                const md_config_t& config,
+                                                const ConfigProxy& config,
                                                 RGWRados& store)
 {
   formatter.open_object_section("tempurl");
@@ -1694,27 +1951,27 @@ void RGWInfo_ObjStore_SWIFT::list_tempurl_data(Formatter& formatter,
 }
 
 void RGWInfo_ObjStore_SWIFT::list_slo_data(Formatter& formatter,
-                                            const md_config_t& config,
+                                            const ConfigProxy& config,
                                             RGWRados& store)
 {
   formatter.open_object_section("slo");
-  formatter.dump_int("max_manifest_segments", config.rgw_max_slo_entries);
+  formatter.dump_int("max_manifest_segments", config->rgw_max_slo_entries);
   formatter.close_section();
 }
 
-bool RGWInfo_ObjStore_SWIFT::is_expired(const std::string& expires, CephContext* cct)
+bool RGWInfo_ObjStore_SWIFT::is_expired(const std::string& expires, const DoutPrefixProvider *dpp)
 {
   string err;
   const utime_t now = ceph_clock_now();
   const uint64_t expiration = (uint64_t)strict_strtoll(expires.c_str(),
                                                        10, &err);
   if (!err.empty()) {
-    ldout(cct, 5) << "failed to parse siginfo_expires: " << err << dendl;
+    ldpp_dout(dpp, 5) << "failed to parse siginfo_expires: " << err << dendl;
     return true;
   }
 
   if (expiration <= (uint64_t)now.sec()) {
-    ldout(cct, 5) << "siginfo expired: " << expiration << " <= " << now.sec() << dendl;
+    ldpp_dout(dpp, 5) << "siginfo expired: " << expiration << " <= " << now.sec() << dendl;
     return true;
   }
 
@@ -1722,7 +1979,7 @@ bool RGWInfo_ObjStore_SWIFT::is_expired(const std::string& expires, CephContext*
 }
 
 
-void RGWFormPost::init(RGWRados* const store,
+void RGWFormPost::init(rgw::sal::RGWRadosStore* const store,
                        req_state* const s,
                        RGWHandler* const dialect_handler)
 {
@@ -1741,7 +1998,7 @@ std::size_t RGWFormPost::get_max_file_size() /*const*/
     static_cast<uint64_t>(strict_strtoll(max_str.c_str(), 10, &err));
 
   if (! err.empty()) {
-    ldout(s->cct, 5) << "failed to parse FormPost's max_file_size: " << err
+    ldpp_dout(this, 5) << "failed to parse FormPost's max_file_size: " << err
                      << dendl;
     return 0;
   }
@@ -1758,13 +2015,13 @@ bool RGWFormPost::is_non_expired()
     static_cast<uint64_t>(strict_strtoll(expires.c_str(), 10, &err));
 
   if (! err.empty()) {
-    dout(5) << "failed to parse FormPost's expires: " << err << dendl;
+    ldpp_dout(this, 5) << "failed to parse FormPost's expires: " << err << dendl;
     return false;
   }
 
   const utime_t now = ceph_clock_now();
   if (expires_timestamp <= static_cast<uint64_t>(now.sec())) {
-    dout(5) << "FormPost form expired: "
+    ldpp_dout(this, 5) << "FormPost form expired: "
             << expires_timestamp << " <= " << now.sec() << dendl;
     return false;
   }
@@ -1777,14 +2034,14 @@ bool RGWFormPost::is_integral()
   const std::string form_signature = get_part_str(ctrl_parts, "signature");
 
   try {
-    get_owner_info(s, *s->user);
+    get_owner_info(s, s->user->get_info());
     s->auth.identity = rgw::auth::transform_old_authinfo(s);
   } catch (...) {
-    ldout(s->cct, 5) << "cannot get user_info of account's owner" << dendl;
+    ldpp_dout(this, 5) << "cannot get user_info of account's owner" << dendl;
     return false;
   }
 
-  for (const auto& kv : s->user->temp_url_keys) {
+  for (const auto& kv : s->user->get_info().temp_url_keys) {
     const int temp_url_key_num = kv.first;
     const string& temp_url_key = kv.second;
 
@@ -1802,13 +2059,13 @@ bool RGWFormPost::is_integral()
 
     const auto local_sig = sig_helper.get_signature();
 
-    ldout(s->cct, 20) << "FormPost signature [" << temp_url_key_num << "]"
+    ldpp_dout(this, 20) << "FormPost signature [" << temp_url_key_num << "]"
                       << " (calculated): " << local_sig << dendl;
 
     if (sig_helper.is_equal_to(form_signature)) {
       return true;
     } else {
-      ldout(s->cct, 5) << "FormPost's signature mismatch: "
+      ldpp_dout(this, 5) << "FormPost's signature mismatch: "
                        << local_sig << " != " << form_signature << dendl;
     }
   }
@@ -1823,6 +2080,8 @@ void RGWFormPost::get_owner_info(const req_state* const s,
    * now. It will be initialized in RGWHandler_REST_SWIFT::postauth_init(). */
   const string& bucket_name = s->init_state.url_bucket;
 
+  auto user_ctl = store->ctl()->user;
+
   /* TempURL in Formpost only requires that bucket name is specified. */
   if (bucket_name.empty()) {
     throw -EPERM;
@@ -1837,14 +2096,14 @@ void RGWFormPost::get_owner_info(const req_state* const s,
     if (uid.tenant.empty()) {
       const rgw_user tenanted_uid(uid.id, uid.id);
 
-      if (rgw_get_user_info_by_uid(store, tenanted_uid, uinfo) >= 0) {
+      if (user_ctl->get_info_by_uid(tenanted_uid, &uinfo, s->yield) >= 0) {
         /* Succeeded. */
         bucket_tenant = uinfo.user_id.tenant;
         found = true;
       }
     }
 
-    if (!found && rgw_get_user_info_by_uid(store, uid, uinfo) < 0) {
+    if (!found && user_ctl->get_info_by_uid(uid, &uinfo, s->yield) < 0) {
       throw -EPERM;
     } else {
       bucket_tenant = uinfo.user_id.tenant;
@@ -1853,17 +2112,17 @@ void RGWFormPost::get_owner_info(const req_state* const s,
 
   /* Need to get user info of bucket owner. */
   RGWBucketInfo bucket_info;
-  int ret = store->get_bucket_info(*static_cast<RGWObjectCtx *>(s->obj_ctx),
+  int ret = store->getRados()->get_bucket_info(store->svc(),
                                    bucket_tenant, bucket_name,
-                                   bucket_info, nullptr);
+                                   bucket_info, nullptr, s->yield);
   if (ret < 0) {
     throw ret;
   }
 
-  ldout(s->cct, 20) << "temp url user (bucket owner): " << bucket_info.owner
+  ldpp_dout(this, 20) << "temp url user (bucket owner): " << bucket_info.owner
                  << dendl;
 
-  if (rgw_get_user_info_by_uid(store, bucket_info.owner, owner_info) < 0) {
+  if (user_ctl->get_info_by_uid(bucket_info.owner, &owner_info, s->yield) < 0) {
     throw -EPERM;
   }
 }
@@ -1876,7 +2135,7 @@ int RGWFormPost::get_params()
     return ret;
   }
 
-  policy.create_default(s->user->user_id, s->user->display_name);
+  policy.create_default(s->user->get_id(), s->user->get_display_name());
 
   /* Let's start parsing the HTTP body by parsing each form part step-
    * by-step till encountering the first part with file data. */
@@ -1887,17 +2146,17 @@ int RGWFormPost::get_params()
       return ret;
     }
 
-    if (s->cct->_conf->subsys.should_gather(ceph_subsys_rgw, 20)) {
-      ldout(s->cct, 20) << "read part header -- part.name="
+    if (s->cct->_conf->subsys.should_gather<ceph_subsys_rgw, 20>()) {
+      ldpp_dout(this, 20) << "read part header -- part.name="
                         << part.name << dendl;
 
       for (const auto& pair : part.fields) {
-        ldout(s->cct, 20) << "field.name=" << pair.first << dendl;
-        ldout(s->cct, 20) << "field.val=" << pair.second.val << dendl;
-        ldout(s->cct, 20) << "field.params:" << dendl;
+        ldpp_dout(this, 20) << "field.name=" << pair.first << dendl;
+        ldpp_dout(this, 20) << "field.val=" << pair.second.val << dendl;
+        ldpp_dout(this, 20) << "field.params:" << dendl;
 
         for (const auto& param_pair : pair.second.params) {
-          ldout(s->cct, 20) << " " << param_pair.first
+          ldpp_dout(this, 20) << " " << param_pair.first
                             << " -> " << param_pair.second << dendl;
         }
       }
@@ -2096,7 +2355,7 @@ int RGWSwiftWebsiteHandler::serve_errordoc(const int http_ret,
 
   class RGWGetErrorPage : public RGWGetObj_ObjStore_SWIFT {
   public:
-    RGWGetErrorPage(RGWRados* const store,
+    RGWGetErrorPage(rgw::sal::RGWRadosStore* const store,
                     RGWHandler_REST* const handler,
                     req_state* const s,
                     const int http_ret) {
@@ -2172,7 +2431,7 @@ RGWOp* RGWSwiftWebsiteHandler::get_ws_redirect_op()
   class RGWMovedPermanently: public RGWOp {
     const std::string location;
   public:
-    RGWMovedPermanently(const std::string& location)
+    explicit RGWMovedPermanently(const std::string& location)
       : location(location) {
     }
 
@@ -2193,7 +2452,7 @@ RGWOp* RGWSwiftWebsiteHandler::get_ws_redirect_op()
       end_header(s, this);
     }
 
-    const string name() override {
+    const char* name() const override {
       return "RGWMovedPermanently";
     }
   };
@@ -2273,7 +2532,7 @@ RGWOp* RGWSwiftWebsiteHandler::get_ws_listing_op()
   public:
     /* Taking prefix_override by value to leverage std::string r-value ref
      * ctor and thus avoid extra memory copying/increasing ref counter. */
-    RGWWebsiteListing(std::string prefix_override)
+    explicit RGWWebsiteListing(std::string prefix_override)
       : prefix_override(std::move(prefix_override)) {
     }
   };
@@ -2293,17 +2552,20 @@ bool RGWSwiftWebsiteHandler::is_web_dir() const
     return false;
   } else if (subdir_name.back() == '/') {
     subdir_name.pop_back();
+    if (subdir_name.empty()) {
+      return false;
+    }
   }
 
   rgw_obj obj(s->bucket, std::move(subdir_name));
 
   /* First, get attrset of the object we'll try to retrieve. */
   RGWObjectCtx& obj_ctx = *static_cast<RGWObjectCtx *>(s->obj_ctx);
-  obj_ctx.obj.set_atomic(obj);
-  obj_ctx.obj.set_prefetch_data(obj);
+  obj_ctx.set_atomic(obj);
+  obj_ctx.set_prefetch_data(obj);
 
   RGWObjState* state = nullptr;
-  if (store->get_obj_state(&obj_ctx, s->bucket_info, obj, &state, false) < 0) {
+  if (store->getRados()->get_obj_state(&obj_ctx, s->bucket_info, obj, &state, false, s->yield) < 0) {
     return false;
   }
 
@@ -2324,16 +2586,16 @@ bool RGWSwiftWebsiteHandler::is_web_dir() const
   return subdir_marker == content_type && state->size <= 1;
 }
 
-bool RGWSwiftWebsiteHandler::is_index_present(const std::string& index)
+bool RGWSwiftWebsiteHandler::is_index_present(const std::string& index) const
 {
   rgw_obj obj(s->bucket, index);
 
   RGWObjectCtx& obj_ctx = *static_cast<RGWObjectCtx *>(s->obj_ctx);
-  obj_ctx.obj.set_atomic(obj);
-  obj_ctx.obj.set_prefetch_data(obj);
+  obj_ctx.set_atomic(obj);
+  obj_ctx.set_prefetch_data(obj);
 
   RGWObjState* state = nullptr;
-  if (store->get_obj_state(&obj_ctx, s->bucket_info, obj, &state, false) < 0) {
+  if (store->getRados()->get_obj_state(&obj_ctx, s->bucket_info, obj, &state, false, s->yield) < 0) {
     return false;
   }
 
@@ -2344,7 +2606,7 @@ bool RGWSwiftWebsiteHandler::is_index_present(const std::string& index)
 
 int RGWSwiftWebsiteHandler::retarget_bucket(RGWOp* op, RGWOp** new_op)
 {
-  ldout(s->cct, 10) << "Starting retarget" << dendl;
+  ldpp_dout(s, 10) << "Starting retarget" << dendl;
   RGWOp* op_override = nullptr;
 
   /* In Swift static web content is served if the request is anonymous or
@@ -2378,7 +2640,7 @@ int RGWSwiftWebsiteHandler::retarget_bucket(RGWOp* op, RGWOp** new_op)
 
 int RGWSwiftWebsiteHandler::retarget_object(RGWOp* op, RGWOp** new_op)
 {
-  ldout(s->cct, 10) << "Starting object retarget" << dendl;
+  ldpp_dout(s, 10) << "Starting object retarget" << dendl;
   RGWOp* op_override = nullptr;
 
   /* In Swift static web content is served if the request is anonymous or
@@ -2528,9 +2790,9 @@ RGWOp *RGWHandler_REST_Obj_SWIFT::op_options()
 }
 
 
-int RGWHandler_REST_SWIFT::authorize()
+int RGWHandler_REST_SWIFT::authorize(const DoutPrefixProvider *dpp)
 {
-  return rgw::auth::Strategy::apply(auth_strategy, s);
+  return rgw::auth::Strategy::apply(dpp, auth_strategy, s);
 }
 
 int RGWHandler_REST_SWIFT::postauth_init()
@@ -2538,7 +2800,7 @@ int RGWHandler_REST_SWIFT::postauth_init()
   struct req_init_state* t = &s->init_state;
 
   /* XXX Stub this until Swift Auth sets account into URL. */
-  s->bucket_tenant = s->user->user_id.tenant;
+  s->bucket_tenant = s->user->get_tenant();
   s->bucket_name = t->url_bucket;
 
   dout(10) << "s->object=" <<
@@ -2548,7 +2810,7 @@ int RGWHandler_REST_SWIFT::postauth_init()
           << dendl;
 
   int ret;
-  ret = validate_tenant_name(s->bucket_tenant);
+  ret = rgw_validate_tenant_name(s->bucket_tenant);
   if (ret)
     return ret;
   ret = validate_bucket_name(s->bucket_name);
@@ -2563,7 +2825,7 @@ int RGWHandler_REST_SWIFT::postauth_init()
      * We don't allow cross-tenant copy at present. It requires account
      * names in the URL for Swift.
      */
-    s->src_tenant_name = s->user->user_id.tenant;
+    s->src_tenant_name = s->user->get_tenant();
     s->src_bucket_name = t->src_bucket;
 
     ret = validate_bucket_name(s->src_bucket_name);
@@ -2581,11 +2843,22 @@ int RGWHandler_REST_SWIFT::postauth_init()
 
 int RGWHandler_REST_SWIFT::validate_bucket_name(const string& bucket)
 {
-  int ret = RGWHandler_REST::validate_bucket_name(bucket);
-  if (ret < 0)
-    return ret;
+  const size_t len = bucket.size();
+
+  if (len > MAX_BUCKET_NAME_LEN) {
+    /* Bucket Name too long. Generate custom error message and bind it
+     * to an R-value reference. */
+    const auto msg = boost::str(
+      boost::format("Container name length of %lld longer than %lld")
+        % len % int(MAX_BUCKET_NAME_LEN));
+    set_req_state_err(s, ERR_INVALID_BUCKET_NAME, msg);
+    return -ERR_INVALID_BUCKET_NAME;
+  }
 
-  int len = bucket.size();
+  const auto ret = RGWHandler_REST::validate_bucket_name(bucket);
+  if (ret < 0) {
+    return ret;
+  }
 
   if (len == 0)
     return 0;
@@ -2598,9 +2871,11 @@ int RGWHandler_REST_SWIFT::validate_bucket_name(const string& bucket)
 
   const char *s = bucket.c_str();
 
-  for (int i = 0; i < len; ++i, ++s) {
+  for (size_t i = 0; i < len; ++i, ++s) {
     if (*(unsigned char *)s == 0xff)
       return -ERR_INVALID_BUCKET_NAME;
+    if (*(unsigned char *)s == '/')
+      return -ERR_INVALID_BUCKET_NAME;
   }
 
   return 0;
@@ -2653,23 +2928,23 @@ int RGWHandler_REST_SWIFT::init_from_header(struct req_state* const s,
   }
 
   if ('\0' == req_name[0]) {
-    return g_conf->rgw_swift_url_prefix == "/" ? -ERR_BAD_URL : 0;
+    return g_conf()->rgw_swift_url_prefix == "/" ? -ERR_BAD_URL : 0;
   }
 
   req = req_name;
 
   size_t pos = req.find('/');
-  if (std::string::npos != pos && g_conf->rgw_swift_url_prefix != "/") {
-    bool cut_url = g_conf->rgw_swift_url_prefix.length();
+  if (std::string::npos != pos && g_conf()->rgw_swift_url_prefix != "/") {
+    bool cut_url = g_conf()->rgw_swift_url_prefix.length();
     first = req.substr(0, pos);
 
-    if (first.compare(g_conf->rgw_swift_url_prefix) == 0) {
+    if (first.compare(g_conf()->rgw_swift_url_prefix) == 0) {
       if (cut_url) {
         /* Rewind to the "v1/..." part. */
         next_tok(req, first, '/');
       }
     }
-  } else if (req.compare(g_conf->rgw_swift_url_prefix) == 0) {
+  } else if (req.compare(g_conf()->rgw_swift_url_prefix) == 0) {
     s->formatter = new RGWFormatter_Plain;
     return -ERR_BAD_URL;
   } else {
@@ -2677,19 +2952,19 @@ int RGWHandler_REST_SWIFT::init_from_header(struct req_state* const s,
   }
 
   std::string tenant_path;
-  if (! g_conf->rgw_swift_tenant_name.empty()) {
+  if (! g_conf()->rgw_swift_tenant_name.empty()) {
     tenant_path = "/AUTH_";
-    tenant_path.append(g_conf->rgw_swift_tenant_name);
+    tenant_path.append(g_conf()->rgw_swift_tenant_name);
   }
 
   /* verify that the request_uri conforms with what's expected */
-  char buf[g_conf->rgw_swift_url_prefix.length() + 16 + tenant_path.length()];
+  char buf[g_conf()->rgw_swift_url_prefix.length() + 16 + tenant_path.length()];
   int blen;
-  if (g_conf->rgw_swift_url_prefix == "/") {
+  if (g_conf()->rgw_swift_url_prefix == "/") {
     blen = sprintf(buf, "/v1%s", tenant_path.c_str());
   } else {
     blen = sprintf(buf, "/%s/v1%s",
-                   g_conf->rgw_swift_url_prefix.c_str(), tenant_path.c_str());
+                   g_conf()->rgw_swift_url_prefix.c_str(), tenant_path.c_str());
   }
 
   if (strncmp(reqbuf, buf, blen) != 0) {
@@ -2704,7 +2979,7 @@ int RGWHandler_REST_SWIFT::init_from_header(struct req_state* const s,
 
   next_tok(req, ver, '/');
 
-  if (!tenant_path.empty() || g_conf->rgw_swift_account_in_url) {
+  if (!tenant_path.empty() || g_conf()->rgw_swift_account_in_url) {
     string account_name;
     next_tok(req, account_name, '/');
 
@@ -2747,15 +3022,15 @@ int RGWHandler_REST_SWIFT::init_from_header(struct req_state* const s,
   return 0;
 }
 
-int RGWHandler_REST_SWIFT::init(RGWRados* store, struct req_state* s,
+int RGWHandler_REST_SWIFT::init(rgw::sal::RGWRadosStore* store, struct req_state* s,
                                rgw::io::BasicClient *cio)
 {
   struct req_init_state *t = &s->init_state;
 
   s->dialect = "swift";
 
-  const char *copy_source = s->info.env->get("HTTP_X_COPY_FROM");
-  if (copy_source) {
+  std::string copy_source = s->info.env->get("HTTP_X_COPY_FROM", "");
+  if (! copy_source.empty()) {
     bool result = RGWCopyObj::parse_copy_location(copy_source, t->src_bucket,
                                                  s->src_object);
     if (!result)
@@ -2763,11 +3038,11 @@ int RGWHandler_REST_SWIFT::init(RGWRados* store, struct req_state* s,
   }
 
   if (s->op == OP_COPY) {
-    const char *req_dest = s->info.env->get("HTTP_DESTINATION");
-    if (!req_dest)
+    std::string req_dest = s->info.env->get("HTTP_DESTINATION", "");
+    if (req_dest.empty())
       return -ERR_BAD_URL;
 
-    string dest_bucket_name;
+    std::string dest_bucket_name;
     rgw_obj_key dest_obj_key;
     bool result =
       RGWCopyObj::parse_copy_location(req_dest, dest_bucket_name,
@@ -2775,7 +3050,7 @@ int RGWHandler_REST_SWIFT::init(RGWRados* store, struct req_state* s,
     if (!result)
        return -ERR_BAD_URL;
 
-    string dest_object = dest_obj_key.name;
+    std::string dest_object = dest_obj_key.name;
 
     /* convert COPY operation into PUT */
     t->src_bucket = t->url_bucket;
@@ -2785,6 +3060,8 @@ int RGWHandler_REST_SWIFT::init(RGWRados* store, struct req_state* s,
     s->op = OP_PUT;
   }
 
+  s->info.storage_class = s->info.env->get("HTTP_X_OBJECT_STORAGE_CLASS", "");
+
   return RGWHandler_REST::init(store, s, cio);
 }
 
@@ -2795,7 +3072,7 @@ RGWRESTMgr_SWIFT::get_handler(struct req_state* const s,
 {
   int ret = RGWHandler_REST_SWIFT::init_from_header(s, frontend_prefix);
   if (ret < 0) {
-    ldout(s->cct, 10) << "init_from_header returned err=" << ret <<  dendl;
+    ldpp_dout(s, 10) << "init_from_header returned err=" << ret <<  dendl;
     return nullptr;
   }