]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: implement swift copy, fix copy auth
authorYehuda Sadeh <yehuda@hq.newdream.net>
Thu, 10 Nov 2011 22:56:10 +0000 (14:56 -0800)
committerYehuda Sadeh <yehuda@hq.newdream.net>
Thu, 10 Nov 2011 22:58:19 +0000 (14:58 -0800)
src/rgw/rgw_common.h
src/rgw/rgw_op.cc
src/rgw/rgw_op.h
src/rgw/rgw_rest.cc
src/rgw/rgw_rest.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h
src/rgw/rgw_rest_swift.cc
src/rgw/rgw_rest_swift.h

index 68cd00dc5933c5a0b9a44474539a003bab91b3e6..7aff456bf04db27a6355cef6c6ba7215dd9fc09c 100644 (file)
@@ -265,6 +265,7 @@ enum http_op {
   OP_DELETE,
   OP_HEAD,
   OP_POST,
+  OP_COPY,
   OP_UNKNOWN,
 };
 
index 9ec86551295c1779099775ef507c7b1640d885ad..802734ec80a5cd19645ba6d917d60fdaf24e73b7 100644 (file)
@@ -916,7 +916,7 @@ void RGWDeleteObj::execute()
   send_response();
 }
 
-static bool parse_copy_source(const char *src, string& bucket_name, string& object)
+bool RGWCopyObj::parse_copy_location(const char *src, string& bucket_name, string& object)
 {
   string url_src(src);
   string dec_src;
@@ -924,7 +924,7 @@ static bool parse_copy_source(const char *src, string& bucket_name, string& obje
   url_decode(url_src, dec_src);
   src = dec_src.c_str();
 
-  dout(15) << "decoded src=" << src << dendl;
+  dout(15) << "decoded obj=" << src << dendl;
 
   if (*src == '/') ++src;
 
@@ -947,37 +947,55 @@ int RGWCopyObj::verify_permission()
 {
   string empty_str;
   RGWAccessControlPolicy src_policy;
-  RGWAccessControlPolicy dest_policy;
+  ret = get_params();
+  if (ret < 0)
+    return ret;
 
-  if (!::verify_permission(s, RGW_PERM_WRITE))
-    return -EACCES;
+  RGWBucketInfo src_bucket_info, dest_bucket_info;
 
-  ret = dest_policy.create_canned(s->user.user_id, s->user.display_name, s->canned_acl);
-  if (!ret)
-     return -EINVAL;
+  /* get buckets info (source and dest) */
 
-  string src_bucket_name;
+  ret = rgwstore->get_bucket_info(s->obj_ctx, src_bucket_name, src_bucket_info);
+  if (ret < 0)
+    return ret;
 
-  ret = parse_copy_source(s->copy_source, src_bucket_name, src_object);
-  if (!ret)
-     return -EINVAL;
+  src_bucket = src_bucket_info.bucket;
 
-  RGWBucketInfo bucket_info;
+  if (src_bucket_name.compare(dest_bucket_name) == 0) {
+    dest_bucket_info = src_bucket_info;
+  } else {
+    ret = rgwstore->get_bucket_info(s->obj_ctx, dest_bucket_name, dest_bucket_info);
+    if (ret < 0)
+      return ret;
+  }
+
+  dest_bucket = dest_bucket_info.bucket;
 
-  ret = rgwstore->get_bucket_info(s->obj_ctx, src_bucket_name, bucket_info);
+  /* check source object permissions */
+  ret = read_acls(s, src_bucket_info, &src_policy, src_bucket, src_object);
   if (ret < 0)
     return ret;
 
-  src_bucket = bucket_info.bucket;
+  if (!::verify_permission(&src_policy, s->user.user_id, s->perm_mask, RGW_PERM_READ))
+    return -EACCES;
+
+  RGWAccessControlPolicy dest_bucket_policy;
 
-  /* just checking the bucket's permission */
-  ret = read_acls(s, bucket_info, &src_policy, src_bucket, empty_str);
+  /* check dest bucket permissions */
+  ret = read_acls(s, dest_bucket_info, &dest_bucket_policy, dest_bucket, empty_str);
   if (ret < 0)
     return ret;
 
-  if (!::verify_permission(&src_policy, s->user.user_id, s->perm_mask, RGW_PERM_READ))
+  if (!::verify_permission(&dest_bucket_policy, s->user.user_id, s->perm_mask, RGW_PERM_WRITE))
     return -EACCES;
 
+  /* build a polict for the target object */
+  RGWAccessControlPolicy dest_policy;
+
+  ret = dest_policy.create_canned(s->user.user_id, s->user.display_name, s->canned_acl);
+  if (!ret)
+     return -EINVAL;
+
   dest_policy.encode(aclbl);
 
   return 0;
@@ -990,7 +1008,6 @@ int RGWCopyObj::init_common()
   time_t unmod_time;
   time_t *mod_ptr = NULL;
   time_t *unmod_ptr = NULL;
-
   if (if_mod) {
     if (parse_time(if_mod, &mod_time) < 0) {
       ret = -EINVAL;
@@ -1017,15 +1034,11 @@ void RGWCopyObj::execute()
 {
   rgw_obj src_obj, dst_obj;
 
-  ret = get_params();
-  if (ret < 0)
-    goto done;
-
   if (init_common() < 0)
     goto done;
 
   src_obj.init(src_bucket, src_object);
-  dst_obj.init(s->bucket, s->object_str);
+  dst_obj.init(dest_bucket, dest_object);
   rgwstore->set_atomic(s->obj_ctx, src_obj);
   rgwstore->set_atomic(s->obj_ctx, dst_obj);
 
index e05520c77df3147410894956bcceefa1c880d8bc..d9c19dd1786818a371db542c4fc2932e2de30b82 100644 (file)
@@ -313,11 +313,19 @@ protected:
   time_t *unmod_ptr;
   int ret;
   map<string, bufferlist> attrs;
+  string src_bucket_name;
   rgw_bucket src_bucket;
   string src_object;
+  string dest_bucket_name;
+  rgw_bucket dest_bucket;
+  string dest_object;
   time_t mtime;
 
   int init_common();
+
+protected:
+  bool parse_copy_location(const char *src, string& bucket_name, string& object);
+
 public:
   RGWCopyObj() {}
 
index 4abfc6c64422c0b831caf1bf817e915179f9d174..e3e303050a0adcff8e0245e277abcbe5552435c7 100644 (file)
@@ -283,16 +283,6 @@ int RGWPutObj_REST::get_data()
   return len;
 }
 
-int RGWCopyObj_REST::get_params()
-{
-  if_mod = s->env->get("HTTP_X_AMZ_COPY_IF_MODIFIED_SINCE");
-  if_unmod = s->env->get("HTTP_X_AMZ_COPY_IF_UNMODIFIED_SINCE");
-  if_match = s->env->get("HTTP_X_AMZ_COPY_IF_MATCH");
-  if_nomatch = s->env->get("HTTP_X_AMZ_COPY_IF_NONE_MATCH");
-
-  return 0;
-}
-
 int RGWPutACLs_REST::get_params()
 {
   size_t cl = 0;
@@ -784,6 +774,8 @@ int RGWHandler_REST::preprocess(struct req_state *s, FCGX_Request *fcgx)
     s->op = OP_HEAD;
   else if (strcmp(s->method, "POST") == 0)
     s->op = OP_POST;
+  else if (strcmp(s->method, "COPY") == 0)
+    s->op = OP_COPY;
   else
     s->op = OP_UNKNOWN;
 
@@ -819,11 +811,6 @@ int RGWHandler_REST::preprocess(struct req_state *s, FCGX_Request *fcgx)
 
   init_auth_info(s);
 
-  const char *cacl = s->env->get("HTTP_X_AMZ_ACL");
-  if (cacl)
-    s->canned_acl = cacl;
-
-  s->copy_source = s->env->get("HTTP_X_AMZ_COPY_SOURCE");
   s->http_auth = s->env->get("HTTP_AUTHORIZATION");
 
   if (g_conf->rgw_print_continue) {
@@ -854,6 +841,8 @@ int RGWHandler_REST::read_permissions()
   case OP_DELETE:
     only_bucket = true;
     break;
+  case OP_COPY: // op itself will read and verify the permissions
+    return 0;
   default:
     return -EINVAL;
   }
@@ -880,6 +869,9 @@ RGWOp *RGWHandler_REST::get_op()
    case OP_POST:
      op = get_post_op();
      break;
+   case OP_COPY:
+     op = get_copy_op();
+     break;
    default:
      return NULL;
   }
index d26bc03ae9971455c6da7bedd3f8a565b8b84f97..b711cf87d8075e8c1587f6041e68b8b7e404a6df 100644 (file)
@@ -83,8 +83,6 @@ class RGWCopyObj_REST : public RGWCopyObj {
 public:
   RGWCopyObj_REST() {}
   ~RGWCopyObj_REST() {}
-
-  int get_params();
 };
 
 class RGWGetACLs_REST : public RGWGetACLs {
@@ -150,6 +148,7 @@ protected:
   virtual RGWOp *get_create_op() = 0;
   virtual RGWOp *get_delete_op() = 0;
   virtual RGWOp *get_post_op() = 0;
+  virtual RGWOp *get_copy_op() = 0;
 
 public:
   int read_permissions();
index 1b9def43122d38499809b04f1c4fbf071f648efa..0f6e738432f99de73bd660bb11e01f2df99e96a4 100644 (file)
@@ -230,6 +230,28 @@ void RGWDeleteObj_REST_S3::send_response()
   end_header(s);
 }
 
+int RGWCopyObj_REST_S3::get_params()
+{
+  if_mod = s->env->get("HTTP_X_AMZ_COPY_IF_MODIFIED_SINCE");
+  if_unmod = s->env->get("HTTP_X_AMZ_COPY_IF_UNMODIFIED_SINCE");
+  if_match = s->env->get("HTTP_X_AMZ_COPY_IF_MATCH");
+  if_nomatch = s->env->get("HTTP_X_AMZ_COPY_IF_NONE_MATCH");
+
+  const char *req_src = s->copy_source;
+  const char *req_dest = s->object;
+  if (!req_src || !req_src)
+    return -EINVAL;
+
+  ret = parse_copy_location(req_src, src_bucket_name, src_object);
+  if (!ret)
+     return -EINVAL;
+
+  dest_bucket_name = s->bucket.name;
+  dest_object = s->object_str;
+
+  return 0;
+}
+
 void RGWCopyObj_REST_S3::send_response()
 {
   if (ret)
@@ -507,6 +529,17 @@ RGWOp *RGWHandler_REST_S3::get_post_op()
   return NULL;
 }
 
+int RGWHandler_REST_S3::init(struct req_state *state, FCGX_Request *fcgx)
+{
+  const char *cacl = state->env->get("HTTP_X_AMZ_ACL");
+  if (cacl)
+    state->canned_acl = cacl;
+
+  state->copy_source = state->env->get("HTTP_X_AMZ_COPY_SOURCE");
+
+  return RGWHandler_REST::init(state, fcgx);
+}
+
 /*
  * ?get the canonical amazon-style header for something?
  */
index 85b9e9cdebe9e664d92e7153161855d9a820f45d..e2bdb93f62e05eb2cbac9a350328e66be196a983 100644 (file)
@@ -73,6 +73,7 @@ public:
   RGWCopyObj_REST_S3() {}
   ~RGWCopyObj_REST_S3() {}
 
+  int get_params();
   void send_response();
 };
 
@@ -142,11 +143,13 @@ protected:
   RGWOp *get_create_op();
   RGWOp *get_delete_op();
   RGWOp *get_post_op();
+  RGWOp *get_copy_op() { return NULL; }
 
 public:
   RGWHandler_REST_S3() : RGWHandler_REST() {}
   virtual ~RGWHandler_REST_S3() {}
 
+  virtual int init(struct req_state *state, FCGX_Request *fcgx);
   int authorize();
 };
 
index 7b77692b76d9e515a75108226ae5f177c6eca2ff..673498c58ee4e6c17ba52b3f49b125ffee02b3e3 100644 (file)
@@ -328,6 +328,48 @@ void RGWDeleteObj_REST_SWIFT::send_response()
   flush_formatter_to_req_state(s, s->formatter);
 }
 
+int RGWCopyObj_REST_SWIFT::get_params()
+{
+  if_mod = s->env->get("HTTP_IF_MODIFIED_SINCE");
+  if_unmod = s->env->get("HTTP_IF_UNMODIFIED_SINCE");
+  if_match = s->env->get("HTTP_COPY_IF_MATCH");
+  if_nomatch = s->env->get("HTTP_COPY_IF_NONE_MATCH");
+
+  if (s->op == OP_COPY) {
+    const char *req_dest = s->env->get("HTTP_DESTINATION");
+    if (!req_dest)
+      return -EINVAL;
+
+    ret = parse_copy_location(req_dest, dest_bucket_name, dest_object);
+    if (!ret)
+       return -EINVAL;
+    src_bucket_name = s->bucket_name;
+    src_object = s->object_str;
+  } else {
+    const char *req_src = s->copy_source;
+    if (!req_src)
+      return -EINVAL;
+
+    ret = parse_copy_location(req_src, src_bucket_name, src_object);
+    if (!ret)
+       return -EINVAL;
+
+    dest_bucket_name = s->bucket_name;
+    dest_object = s->object_str;
+  }
+
+  return 0;
+}
+
+void RGWCopyObj_REST_SWIFT::send_response()
+{
+  if (!ret)
+    ret = STATUS_CREATED;
+  set_req_state_err(s, ret);
+  dump_errno(s);
+  end_header(s);
+}
+
 int RGWGetObj_REST_SWIFT::send_response(void *handle)
 {
   const char *content_type = NULL;
@@ -453,6 +495,14 @@ RGWOp *RGWHandler_REST_SWIFT::get_post_op()
   return NULL;
 }
 
+RGWOp *RGWHandler_REST_SWIFT::get_copy_op()
+{
+  if (s->object)
+    return new RGWCopyObj_REST_SWIFT;
+
+  return NULL;
+}
+
 int RGWHandler_REST_SWIFT::authorize()
 {
   bool authorized = rgw_verify_os_token(s);
@@ -463,3 +513,10 @@ int RGWHandler_REST_SWIFT::authorize()
 
   return 0;
 }
+
+int RGWHandler_REST_SWIFT::init(struct req_state *state, FCGX_Request *fcgx)
+{
+  state->copy_source = state->env->get("HTTP_X_COPY_FROM");
+
+  return RGWHandler_REST::init(state, fcgx);
+}
index 07f718311418adb2f1196c1db841492b2302f015..dc22671f2834bb9098e0ee10ebce9b297094377e 100644 (file)
@@ -104,7 +104,8 @@ public:
   RGWCopyObj_REST_SWIFT() {}
   ~RGWCopyObj_REST_SWIFT() {}
 
-  void send_response() {}
+  int get_params();
+  void send_response();
 };
 
 class RGWGetACLs_REST_SWIFT : public RGWGetACLs_REST {
@@ -132,11 +133,13 @@ protected:
   RGWOp *get_create_op();
   RGWOp *get_delete_op();
   RGWOp *get_post_op();
+  RGWOp *get_copy_op();
 
 public:
   RGWHandler_REST_SWIFT() : RGWHandler_REST() {}
   virtual ~RGWHandler_REST_SWIFT() {}
 
+  int init(struct req_state *state, FCGX_Request *fcgx);
   int authorize();
 };