From: Yehuda Sadeh Date: Tue, 12 Jun 2012 21:42:03 +0000 (-0700) Subject: rgw: obj copy respects -metadata-directive X-Git-Tag: v0.48argonaut~55 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=b415fd219ecd843b64790c9ec38b09e14a7ca65d;p=ceph.git rgw: obj copy respects -metadata-directive Fixes #2542. The old behavior just merged src object attrs and provided attributes. The new (and correct) behavior looks at the x-[amz|rgw|...]-metadata-directive and either copies the source attrs, or replaces them with the provided attrs. Signed-off-by: Yehuda Sadeh --- diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index 7c3f567f1abf..31b1113a3395 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -120,6 +120,7 @@ using ceph::crypto::MD5; #define ERR_UNPROCESSABLE_ENTITY 2018 #define ERR_TOO_LARGE 2019 #define ERR_TOO_MANY_BUCKETS 2020 +#define ERR_INVALID_REQUEST 2021 #define ERR_USER_SUSPENDED 2100 #define ERR_INTERNAL_ERROR 2200 diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 50354c5128b6..dfd6caf55d34 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -1214,6 +1214,12 @@ int RGWCopyObj::init_common() attrs[RGW_ATTR_ACL] = aclbl; rgw_get_request_metadata(s, attrs); + if (s->content_type) { + bufferlist bl; + bl.append(s->content_type, strlen(s->content_type) + 1); + attrs[RGW_ATTR_CONTENT_TYPE] = bl; + } + return 0; } @@ -1237,6 +1243,7 @@ void RGWCopyObj::execute() unmod_ptr, if_match, if_nomatch, + replace_attrs, attrs, RGW_OBJ_CATEGORY_MAIN, &s->err); done: @@ -1374,7 +1381,6 @@ int RGWInitMultipart::verify_permission() void RGWInitMultipart::execute() { - bufferlist bl; bufferlist aclbl; map attrs; rgw_obj obj; @@ -1390,6 +1396,7 @@ void RGWInitMultipart::execute() attrs[RGW_ATTR_ACL] = aclbl; if (s->content_type) { + bufferlist bl; bl.append(s->content_type, strlen(s->content_type) + 1); attrs[RGW_ATTR_CONTENT_TYPE] = bl; } diff --git a/src/rgw/rgw_op.h b/src/rgw/rgw_op.h index 77092846a37d..be4087fa9410 100644 --- a/src/rgw/rgw_op.h +++ b/src/rgw/rgw_op.h @@ -373,6 +373,7 @@ protected: rgw_bucket dest_bucket; string dest_object; time_t mtime; + bool replace_attrs; int init_common(); @@ -398,6 +399,7 @@ public: src_bucket.clear(); src_object.clear(); mtime = 0; + replace_attrs = false; dest_policy.set_ctx(s->cct); } int verify_permission(); diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index 05bfd39d22b1..e7032a0dd972 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -1043,13 +1043,9 @@ bool RGWRados::aio_completed(void *handle) } /** * Copy an object. - * dest_bucket: the bucket to copy into * dest_obj: the object to copy into - * src_bucket: the bucket to copy from * src_obj: the object to copy from - * mod_ptr, unmod_ptr, if_match, if_nomatch: as used in get_obj - * attrs: these are placed on the new object IN ADDITION to - * (or overwriting) any attrs copied from the original object + * attrs: if replace_attrs is set then these are placed on the new object * err: stores any errors resulting from the get of the original object * Returns: 0 on success, -ERR# otherwise. */ @@ -1061,7 +1057,8 @@ int RGWRados::copy_obj(void *ctx, const time_t *unmod_ptr, const char *if_match, const char *if_nomatch, - map& attrs, /* in/out */ + bool replace_attrs, + map& attrs, RGWObjCategory category, struct rgw_err *err) { @@ -1133,12 +1130,11 @@ int RGWRados::copy_obj(void *ctx, } manifest.obj_size = ofs; - for (iter = attrs.begin(); iter != attrs.end(); ++iter) { - attrset[iter->first] = iter->second; + if (replace_attrs) { + attrset = attrs; } - attrs = attrset; - ret = rgwstore->put_obj_meta(ctx, dest_obj, end + 1, NULL, attrs, category, false, NULL, &first_chunk, &manifest); + ret = rgwstore->put_obj_meta(ctx, dest_obj, end + 1, NULL, attrset, category, false, NULL, &first_chunk, &manifest); if (mtime) obj_stat(ctx, dest_obj, NULL, mtime, NULL, NULL); diff --git a/src/rgw/rgw_rados.h b/src/rgw/rgw_rados.h index a475b9995407..4acd8e8da800 100644 --- a/src/rgw/rgw_rados.h +++ b/src/rgw/rgw_rados.h @@ -411,13 +411,9 @@ public: /** * Copy an object. - * dest_bucket: the bucket to copy into * dest_obj: the object to copy into - * src_bucket: the bucket to copy from * src_obj: the object to copy from - * mod_ptr, unmod_ptr, if_match, if_nomatch: as used in get_obj - * attrs: these are placed on the new object IN ADDITION to - * (or overwriting) any attrs copied from the original object + * attrs: if replace_attrs is set then these are placed on the new object * err: stores any errors resulting from the get of the original object * Returns: 0 on success, -ERR# otherwise. */ @@ -428,6 +424,7 @@ public: const time_t *unmod_ptr, const char *if_match, const char *if_nomatch, + bool replace_attrs, map& attrs, RGWObjCategory category, struct rgw_err *err); diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc index 9d7e13f52465..ecba55d5c626 100644 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@ -40,6 +40,7 @@ const static struct rgw_html_errors RGW_HTML_ERRORS[] = { { STATUS_PARTIAL_CONTENT, 206, "" }, { ERR_NOT_MODIFIED, 304, "NotModified" }, { EINVAL, 400, "InvalidArgument" }, + { ERR_INVALID_REQUEST, 400, "InvalidRequest" }, { ERR_INVALID_DIGEST, 400, "InvalidDigest" }, { ERR_BAD_DIGEST, 400, "BadDigest" }, { ERR_INVALID_BUCKET_NAME, 400, "InvalidBucketName" }, diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index b3d7e7e4ec35..b6f0fa11c550 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -309,6 +309,23 @@ int RGWCopyObj_REST_S3::get_params() dest_bucket_name = s->bucket.name; dest_object = s->object_str; + const char *md_directive = s->env->get("HTTP_X_AMZ_METADATA_DIRECTIVE"); + if (md_directive) { + if (strcasecmp(md_directive, "COPY") == 0) { + replace_attrs = false; + } else if (strcasecmp(md_directive, "REPLACE") == 0) { + replace_attrs = true; + } else { + return -EINVAL; + } + } + + if ((dest_bucket_name.compare(src_bucket_name) == 0) && + (dest_object.compare(src_object) == 0) && + !replace_attrs) { + /* can only copy object into itself if replacing attrs */ + return -ERR_INVALID_REQUEST; + } return 0; }