+ op_ret = retry_raced_bucket_write(this, s->bucket.get(), [this, y] {
+ rgw::sal::Attrs attrs = s->bucket->get_attrs();
+ attrs.erase(RGW_ATTR_TAGS);
+ op_ret = s->bucket->merge_and_store_attrs(this, attrs, y);
+ if (op_ret < 0) {
+ ldpp_dout(this, 0) << "RGWDeleteBucketTags() failed to remove RGW_ATTR_TAGS on bucket="
+ << s->bucket->get_name()
+ << " returned err= " << op_ret << dendl;
+ }
+ return op_ret;
+ });
+}
+
+int RGWGetBucketReplication::verify_permission(optional_yield y)
+{
+ auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false);
+ if (has_s3_resource_tag)
+ rgw_iam_add_buckettags(this, s);
+
+ if (!verify_bucket_permission(this, s, rgw::IAM::s3GetReplicationConfiguration)) {
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+void RGWGetBucketReplication::pre_exec()
+{
+ rgw_bucket_object_pre_exec(s);
+}
+
+void RGWGetBucketReplication::execute(optional_yield y)
+{
+ send_response_data();
+}
+
+int RGWPutBucketReplication::verify_permission(optional_yield y) {
+ auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false);
+ if (has_s3_resource_tag)
+ rgw_iam_add_buckettags(this, s);
+ return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutReplicationConfiguration);
+}
+
+void RGWPutBucketReplication::execute(optional_yield y) {
+
+ op_ret = get_params(y);
+ if (op_ret < 0)
+ return;
+
+ op_ret = store->forward_request_to_master(this, s->user.get(), nullptr, in_data, nullptr, s->info, y);
+ if (op_ret < 0) {
+ ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl;
+ return;
+ }
+
+ op_ret = retry_raced_bucket_write(this, s->bucket.get(), [this] {
+ auto sync_policy = (s->bucket->get_info().sync_policy ? *s->bucket->get_info().sync_policy : rgw_sync_policy_info());
+
+ for (auto& group : sync_policy_groups) {
+ sync_policy.groups[group.id] = group;
+ }
+
+ s->bucket->get_info().set_sync_policy(std::move(sync_policy));
+
+ int ret = s->bucket->put_info(this, false, real_time());
+ if (ret < 0) {
+ ldpp_dout(this, 0) << "ERROR: put_bucket_instance_info (bucket=" << s->bucket << ") returned ret=" << ret << dendl;
+ return ret;
+ }
+
+ return 0;
+ });
+}
+
+void RGWDeleteBucketReplication::pre_exec()
+{
+ rgw_bucket_object_pre_exec(s);
+}
+
+int RGWDeleteBucketReplication::verify_permission(optional_yield y)
+{
+ auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false);
+ if (has_s3_resource_tag)
+ rgw_iam_add_buckettags(this, s);
+
+ return verify_bucket_owner_or_policy(s, rgw::IAM::s3DeleteReplicationConfiguration);
+}
+
+void RGWDeleteBucketReplication::execute(optional_yield y)
+{
+ bufferlist in_data;
+ op_ret = store->forward_request_to_master(this, s->user.get(), nullptr, in_data, nullptr, s->info, y);
+ if (op_ret < 0) {
+ ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl;
+ return;
+ }
+
+ op_ret = retry_raced_bucket_write(this, s->bucket.get(), [this] {
+ if (!s->bucket->get_info().sync_policy) {
+ return 0;
+ }
+
+ rgw_sync_policy_info sync_policy = *s->bucket->get_info().sync_policy;
+
+ update_sync_policy(&sync_policy);
+
+ s->bucket->get_info().set_sync_policy(std::move(sync_policy));
+
+ int ret = s->bucket->put_info(this, false, real_time());
+ if (ret < 0) {
+ ldpp_dout(this, 0) << "ERROR: put_bucket_instance_info (bucket=" << s->bucket << ") returned ret=" << ret << dendl;
+ return ret;
+ }
+
+ return 0;
+ });
+}
+
+int RGWOp::do_aws4_auth_completion()
+{
+ ldpp_dout(this, 5) << "NOTICE: call to do_aws4_auth_completion" << dendl;
+ if (s->auth.completer) {
+ if (!s->auth.completer->complete()) {
+ return -ERR_AMZ_CONTENT_SHA256_MISMATCH;
+ } else {
+ ldpp_dout(this, 10) << "v4 auth ok -- do_aws4_auth_completion" << dendl;
+ }
+
+ /* TODO(rzarzynski): yes, we're really called twice on PUTs. Only first
+ * call passes, so we disable second one. This is old behaviour, sorry!
+ * Plan for tomorrow: seek and destroy. */
+ s->auth.completer = nullptr;
+ }
+
+ return 0;
+}
+
+int RGWOp::init_quota()
+{
+ /* no quota enforcement for system requests */
+ if (s->system_request)
+ return 0;
+
+ /* init quota related stuff */
+ if (!(s->user->get_info().op_mask & RGW_OP_TYPE_MODIFY)) {
+ return 0;
+ }
+
+ /* only interested in object related ops */
+ if (rgw::sal::Bucket::empty(s->bucket.get())
+ || rgw::sal::Object::empty(s->object.get())) {
+ return 0;
+ }
+
+ std::unique_ptr<rgw::sal::User> owner_user =
+ store->get_user(s->bucket->get_info().owner);
+ rgw::sal::User* user;
+
+ if (s->user->get_id() == s->bucket_owner.get_id()) {
+ user = s->user.get();
+ } else {
+ int r = owner_user->load_user(this, s->yield);
+ if (r < 0)
+ return r;
+ user = owner_user.get();
+ }
+
+ store->get_quota(bucket_quota, user_quota);
+
+ if (s->bucket->get_info().quota.enabled) {
+ bucket_quota = s->bucket->get_info().quota;
+ } else if (user->get_info().bucket_quota.enabled) {
+ bucket_quota = user->get_info().bucket_quota;
+ }
+
+ if (user->get_info().user_quota.enabled) {
+ user_quota = user->get_info().user_quota;
+ }
+
+ return 0;
+}
+
+static bool validate_cors_rule_method(const DoutPrefixProvider *dpp, RGWCORSRule *rule, const char *req_meth) {
+ uint8_t flags = 0;
+
+ if (!req_meth) {
+ ldpp_dout(dpp, 5) << "req_meth is null" << dendl;
+ return false;
+ }
+
+ if (strcmp(req_meth, "GET") == 0) flags = RGW_CORS_GET;
+ else if (strcmp(req_meth, "POST") == 0) flags = RGW_CORS_POST;
+ else if (strcmp(req_meth, "PUT") == 0) flags = RGW_CORS_PUT;
+ else if (strcmp(req_meth, "DELETE") == 0) flags = RGW_CORS_DELETE;
+ else if (strcmp(req_meth, "HEAD") == 0) flags = RGW_CORS_HEAD;
+
+ if (rule->get_allowed_methods() & flags) {
+ ldpp_dout(dpp, 10) << "Method " << req_meth << " is supported" << dendl;
+ } else {
+ ldpp_dout(dpp, 5) << "Method " << req_meth << " is not supported" << dendl;
+ return false;
+ }
+
+ return true;