]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: obj copy respects -metadata-directive
authorYehuda Sadeh <yehuda@inktank.com>
Tue, 12 Jun 2012 21:42:03 +0000 (14:42 -0700)
committerSage Weil <sage@inktank.com>
Fri, 15 Jun 2012 20:44:09 +0000 (13:44 -0700)
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 <yehuda@inktank.com>
src/rgw/rgw_common.h
src/rgw/rgw_op.cc
src/rgw/rgw_op.h
src/rgw/rgw_rados.cc
src/rgw/rgw_rados.h
src/rgw/rgw_rest.cc
src/rgw/rgw_rest_s3.cc

index 7c3f567f1abf0e12241cc63c2edbf90da6a4778a..31b1113a339597cb8ed5560ca7a26c2de0935537 100644 (file)
@@ -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
 
index 50354c5128b6c74bbbb09a193f4b8cfe552a50bd..dfd6caf55d3442f32b21217dc688ac7fdbd8e146 100644 (file)
@@ -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<string, bufferlist> 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;
   }
index 77092846a37d14a65bf21575d1797975716c9254..be4087fa9410ec66d60172dfb7abc98374456035 100644 (file)
@@ -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();
index 05bfd39d22b1d34a1611a98fef485f5c3c27ae53..e7032a0dd972cc1bef4c80bf453b2aaf8399e456 100644 (file)
@@ -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<string, bufferlist>& attrs,  /* in/out */
+               bool replace_attrs,
+               map<string, bufferlist>& 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);
 
index a475b99954070f01eeea853ab8b17b8b455afc7a..4acd8e8da800edb51053f6e8f7b9c3358793d32d 100644 (file)
@@ -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<std::string, bufferlist>& attrs,
                RGWObjCategory category,
                struct rgw_err *err);
index 9d7e13f5246596b70ed57b9f6a8cd76054a3f820..ecba55d5c626921d76ef6d59ee9dc4ba91c17f44 100644 (file)
@@ -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" },
index b3d7e7e4ec35fa5b36aea0c3d2727d7d80071e44..b6f0fa11c55094ecd8400ebaa243f96dd76d40b0 100644 (file)
@@ -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;
 }