From 87941128b60608d66dc5327038f099a1fb2a99c3 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Thu, 10 Nov 2011 14:56:10 -0800 Subject: [PATCH] rgw: implement swift copy, fix copy auth --- src/rgw/rgw_common.h | 1 + src/rgw/rgw_op.cc | 61 ++++++++++++++++++++++++--------------- src/rgw/rgw_op.h | 8 +++++ src/rgw/rgw_rest.cc | 22 +++++--------- src/rgw/rgw_rest.h | 3 +- src/rgw/rgw_rest_s3.cc | 33 +++++++++++++++++++++ src/rgw/rgw_rest_s3.h | 3 ++ src/rgw/rgw_rest_swift.cc | 57 ++++++++++++++++++++++++++++++++++++ src/rgw/rgw_rest_swift.h | 5 +++- 9 files changed, 151 insertions(+), 42 deletions(-) diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index 68cd00dc5933c..7aff456bf04db 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -265,6 +265,7 @@ enum http_op { OP_DELETE, OP_HEAD, OP_POST, + OP_COPY, OP_UNKNOWN, }; diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 9ec86551295c1..802734ec80a5c 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -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); diff --git a/src/rgw/rgw_op.h b/src/rgw/rgw_op.h index e05520c77df31..d9c19dd178681 100644 --- a/src/rgw/rgw_op.h +++ b/src/rgw/rgw_op.h @@ -313,11 +313,19 @@ protected: time_t *unmod_ptr; int ret; map 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() {} diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc index 4abfc6c64422c..e3e303050a0ad 100644 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@ -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; } diff --git a/src/rgw/rgw_rest.h b/src/rgw/rgw_rest.h index d26bc03ae9971..b711cf87d8075 100644 --- a/src/rgw/rgw_rest.h +++ b/src/rgw/rgw_rest.h @@ -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(); diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 1b9def43122d3..0f6e738432f99 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -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? */ diff --git a/src/rgw/rgw_rest_s3.h b/src/rgw/rgw_rest_s3.h index 85b9e9cdebe9e..e2bdb93f62e05 100644 --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@ -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(); }; diff --git a/src/rgw/rgw_rest_swift.cc b/src/rgw/rgw_rest_swift.cc index 7b77692b76d9e..673498c58ee4e 100644 --- a/src/rgw/rgw_rest_swift.cc +++ b/src/rgw/rgw_rest_swift.cc @@ -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); +} diff --git a/src/rgw/rgw_rest_swift.h b/src/rgw/rgw_rest_swift.h index 07f718311418a..dc22671f2834b 100644 --- a/src/rgw/rgw_rest_swift.h +++ b/src/rgw/rgw_rest_swift.h @@ -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(); }; -- 2.39.5