From 9688fcc941445ae9e4e06d3b21785fa23ad8054f Mon Sep 17 00:00:00 2001 From: Matt Benjamin Date: Fri, 12 Jan 2018 10:12:16 -0500 Subject: [PATCH] rgw: URL-decode S3 and Swift object-copy URLs Fixes: http://tracker.ceph.com/issues/22121 Signed-off-by: Matt Benjamin --- src/rgw/rgw_op.cc | 39 ++++++++++++++++++++------------------- src/rgw/rgw_op.h | 5 ++--- src/rgw/rgw_rest_s3.cc | 32 ++++++++++++++++++-------------- src/rgw/rgw_rest_swift.cc | 14 ++++++++------ 4 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 1195528210122..12d006cf3630d 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -2932,7 +2932,7 @@ void RGWDeleteBucket::execute() int RGWPutObj::verify_permission() { - if (copy_source) { + if (! copy_source.empty()) { RGWAccessControlPolicy cs_acl(s->cct); boost::optional policy; @@ -2945,8 +2945,8 @@ int RGWPutObj::verify_permission() store->set_prefetch_data(s->obj_ctx, obj); /* check source object permissions */ - if (read_obj_policy(store, s, copy_source_bucket_info, cs_attrs, &cs_acl, policy, - cs_bucket, cs_object) < 0) { + if (read_obj_policy(store, s, copy_source_bucket_info, cs_attrs, &cs_acl, + policy, cs_bucket, cs_object) < 0) { return -EACCES; } @@ -3405,7 +3405,7 @@ void RGWPutObj::execute() bufferlist data; if (fst > lst) break; - if (!copy_source) { + if (copy_source.empty()) { len = get_data(data); } else { uint64_t cur_lst = min(fst + s->cct->_conf->rgw_max_chunk_size - 1, lst); @@ -4280,11 +4280,12 @@ void RGWDeleteObj::execute() } } - -bool RGWCopyObj::parse_copy_location(const string& url_src, string& bucket_name, rgw_obj_key& key) +bool RGWCopyObj::parse_copy_location(const boost::string_view& url_src, + string& bucket_name, + rgw_obj_key& key) { - string name_str; - string params_str; + boost::string_view name_str; + boost::string_view params_str; size_t pos = url_src.find('?'); if (pos == string::npos) { @@ -4294,27 +4295,27 @@ bool RGWCopyObj::parse_copy_location(const string& url_src, string& bucket_name, params_str = url_src.substr(pos + 1); } - std::string dec_src = url_decode(name_str); - const char *src = dec_src.c_str(); - - if (*src == '/') ++src; + boost::string_view dec_src{name_str}; + if (dec_src[0] == '/') + dec_src.remove_prefix(1); - string str(src); - - pos = str.find('/'); + pos = dec_src.find('/'); if (pos ==string::npos) return false; - bucket_name = str.substr(0, pos); - key.name = str.substr(pos + 1); + boost::string_view bn_view{dec_src.substr(0, pos)}; + bucket_name = std::string{bn_view.data(), bn_view.size()}; + + boost::string_view kn_view{dec_src.substr(pos + 1)}; + key.name = std::string{kn_view.data(), kn_view.size()}; if (key.name.empty()) { return false; } - if (!params_str.empty()) { + if (! params_str.empty()) { RGWHTTPArgs args; - args.set(params_str); + args.set(params_str.to_string()); args.parse(); key.instance = args.get("versionId", NULL); diff --git a/src/rgw/rgw_op.h b/src/rgw/rgw_op.h index 50fbb6865f489..45958505cc37c 100644 --- a/src/rgw/rgw_op.h +++ b/src/rgw/rgw_op.h @@ -978,7 +978,7 @@ protected: const char *supplied_etag; const char *if_match; const char *if_nomatch; - const char *copy_source; + std::string copy_source; const char *copy_source_range; RGWBucketInfo copy_source_bucket_info; string copy_source_tenant_name; @@ -1009,7 +1009,6 @@ public: supplied_etag(NULL), if_match(NULL), if_nomatch(NULL), - copy_source(NULL), copy_source_range(NULL), copy_source_range_fst(0), copy_source_range_lst(0), @@ -1320,7 +1319,7 @@ public: copy_if_newer = false; } - static bool parse_copy_location(const string& src, + static bool parse_copy_location(const boost::string_view& src, string& bucket_name, rgw_obj_key& object); diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index b9b5d1b6ffea3..ec774deb3b9ad 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -1252,29 +1252,33 @@ int RGWPutObj_ObjStore_S3::get_params() if_match = s->info.env->get("HTTP_IF_MATCH"); if_nomatch = s->info.env->get("HTTP_IF_NONE_MATCH"); - copy_source = s->info.env->get("HTTP_X_AMZ_COPY_SOURCE"); + copy_source = url_decode(s->info.env->get("HTTP_X_AMZ_COPY_SOURCE", "")); copy_source_range = s->info.env->get("HTTP_X_AMZ_COPY_SOURCE_RANGE"); /* handle x-amz-copy-source */ - - if (copy_source) { - if (*copy_source == '/') ++copy_source; - copy_source_bucket_name = copy_source; + boost::string_view cs_view(copy_source); + if (! cs_view.empty()) { + if (cs_view[0] == '/') + cs_view.remove_prefix(1); + copy_source_bucket_name = cs_view.to_string(); pos = copy_source_bucket_name.find("/"); if (pos == std::string::npos) { ret = -EINVAL; ldout(s->cct, 5) << "x-amz-copy-source bad format" << dendl; return ret; } - copy_source_object_name = copy_source_bucket_name.substr(pos + 1, copy_source_bucket_name.size()); + copy_source_object_name = + copy_source_bucket_name.substr(pos + 1, copy_source_bucket_name.size()); copy_source_bucket_name = copy_source_bucket_name.substr(0, pos); #define VERSION_ID_STR "?versionId=" pos = copy_source_object_name.find(VERSION_ID_STR); if (pos == std::string::npos) { copy_source_object_name = url_decode(copy_source_object_name); } else { - copy_source_version_id = copy_source_object_name.substr(pos + sizeof(VERSION_ID_STR) - 1); - copy_source_object_name = url_decode(copy_source_object_name.substr(0, pos)); + copy_source_version_id = + copy_source_object_name.substr(pos + sizeof(VERSION_ID_STR) - 1); + copy_source_object_name = + url_decode(copy_source_object_name.substr(0, pos)); } pos = copy_source_bucket_name.find(":"); if (pos == std::string::npos) { @@ -1376,7 +1380,7 @@ void RGWPutObj_ObjStore_S3::send_response() s->cct->_conf->rgw_s3_success_create_obj_status); set_req_state_err(s, op_ret); } - if (!copy_source) { + if (copy_source.empty()) { dump_errno(s); dump_etag(s, etag); dump_content_length(s, 0); @@ -3274,11 +3278,11 @@ int RGWHandler_REST_S3::init(RGWRados *store, struct req_state *s, s->has_acl_header = s->info.env->exists_prefix("HTTP_X_AMZ_GRANT"); const char *copy_source = s->info.env->get("HTTP_X_AMZ_COPY_SOURCE"); - - if (copy_source && !s->info.env->get("HTTP_X_AMZ_COPY_SOURCE_RANGE")) { - ret = RGWCopyObj::parse_copy_location(copy_source, - s->init_state.src_bucket, - s->src_object); + if (copy_source && + (! s->info.env->get("HTTP_X_AMZ_COPY_SOURCE_RANGE"))) { + ret = RGWCopyObj::parse_copy_location(url_decode(copy_source), + s->init_state.src_bucket, + s->src_object); if (!ret) { ldout(s->cct, 0) << "failed to parse copy location" << dendl; return -EINVAL; // XXX why not -ERR_INVALID_BUCKET_NAME or -ERR_BAD_URL? diff --git a/src/rgw/rgw_rest_swift.cc b/src/rgw/rgw_rest_swift.cc index a21f31bfea8ea..199c6a084d032 100644 --- a/src/rgw/rgw_rest_swift.cc +++ b/src/rgw/rgw_rest_swift.cc @@ -2909,8 +2909,9 @@ int RGWHandler_REST_SWIFT::init(RGWRados* store, struct req_state* s, s->dialect = "swift"; - const char *copy_source = s->info.env->get("HTTP_X_COPY_FROM"); - if (copy_source) { + std::string copy_source = + url_decode(s->info.env->get("HTTP_X_COPY_FROM", "")); + if (! copy_source.empty()) { bool result = RGWCopyObj::parse_copy_location(copy_source, t->src_bucket, s->src_object); if (!result) @@ -2918,11 +2919,12 @@ int RGWHandler_REST_SWIFT::init(RGWRados* store, struct req_state* s, } if (s->op == OP_COPY) { - const char *req_dest = s->info.env->get("HTTP_DESTINATION"); - if (!req_dest) + std::string req_dest = + url_decode(s->info.env->get("HTTP_DESTINATION", "")); + if (req_dest.empty()) return -ERR_BAD_URL; - string dest_bucket_name; + std::string dest_bucket_name; rgw_obj_key dest_obj_key; bool result = RGWCopyObj::parse_copy_location(req_dest, dest_bucket_name, @@ -2930,7 +2932,7 @@ int RGWHandler_REST_SWIFT::init(RGWRados* store, struct req_state* s, if (!result) return -ERR_BAD_URL; - string dest_object = dest_obj_key.name; + std::string dest_object = dest_obj_key.name; /* convert COPY operation into PUT */ t->src_bucket = t->url_bucket; -- 2.39.5