Skip to content

Commit ae4a871

Browse files
committed
rgw_cksum: implement POST upload checksums
* properly transform pseudo headers in PostObj * enable cksum verify in PostObj * match checksum headers in match_policy_vars * fixup add POST headers to environment Signed-off-by: Matt Benjamin <[email protected]>
1 parent 6ef9a28 commit ae4a871

File tree

6 files changed

+108
-25
lines changed

6 files changed

+108
-25
lines changed

src/rgw/rgw_cksum.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,25 @@ namespace rgw { namespace cksum {
206206
return ck.type;
207207
}
208208
return Type::none;
209-
}
209+
} /* parse_cksum_type */
210+
211+
static inline Type parse_cksum_type_hdr(const std::string_view hdr_name) {
212+
auto pos = hdr_name.find("x-amz-checksum-", 0);
213+
if (pos == std::string::npos) {
214+
return Type::none;
215+
}
216+
constexpr int8_t psz = sizeof("x-amz-checksum-") - 1;
217+
if ((hdr_name.size() - psz) > 0 ) {
218+
std::string ck_name{hdr_name.substr(psz)};
219+
return parse_cksum_type(ck_name.c_str());
220+
}
221+
return Type::none;
222+
} /* parse_cksum_type_hdr */
223+
224+
static inline bool is_checksum_hdr(const std::string_view hdr_name) {
225+
return hdr_name == "x-amz-checksum-algorithm" ||
226+
parse_cksum_type_hdr(hdr_name) != Type::none;
227+
} /* is_cksum_hdr */
210228

211229
class Digest {
212230
public:

src/rgw/rgw_op.cc

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4649,7 +4649,8 @@ void RGWPostObj::execute(optional_yield y)
46494649

46504650
// make reservation for notification if needed
46514651
std::unique_ptr<rgw::sal::Notification> res
4652-
= driver->get_notification(s->object.get(), s->src_object.get(), s, rgw::notify::ObjectCreatedPost, y);
4652+
= driver->get_notification(s->object.get(), s->src_object.get(), s,
4653+
rgw::notify::ObjectCreatedPost, y);
46534654
op_ret = res->publish_reserve(this);
46544655
if (op_ret < 0) {
46554656
return;
@@ -4700,10 +4701,13 @@ void RGWPostObj::execute(optional_yield y)
47004701
return;
47014702
}
47024703

4704+
std::unique_ptr<rgw::putobj::RGWPutObj_Cksum> cksum_filter;
4705+
std::unique_ptr<rgw::sal::DataProcessor> encrypt;
4706+
47034707
/* No filters by default. */
47044708
rgw::sal::DataProcessor *filter = processor.get();
47054709

4706-
std::unique_ptr<rgw::sal::DataProcessor> encrypt;
4710+
/* last filter runs first */
47074711
op_ret = get_encrypt_filter(&encrypt, filter);
47084712
if (op_ret < 0) {
47094713
return;
@@ -4724,6 +4728,20 @@ void RGWPostObj::execute(optional_yield y)
47244728
}
47254729
}
47264730

4731+
/* XXX no lua filter? */
4732+
4733+
/* optional streaming checksum */
4734+
try {
4735+
cksum_filter =
4736+
rgw::putobj::RGWPutObj_Cksum::Factory(filter, *s->info.env);
4737+
} catch (const rgw::io::Exception& e) {
4738+
op_ret = e.code().value();
4739+
return;
4740+
}
4741+
if (cksum_filter) {
4742+
filter = &*cksum_filter;
4743+
}
4744+
47274745
bool again;
47284746
do {
47294747
ceph::bufferlist data;
@@ -4738,6 +4756,7 @@ void RGWPostObj::execute(optional_yield y)
47384756
break;
47394757
}
47404758

4759+
/* XXXX we should modernize to use component buffers? */
47414760
hash.Update((const unsigned char *)data.c_str(), data.length());
47424761
op_ret = filter->process(std::move(data), ofs);
47434762
if (op_ret < 0) {
@@ -4809,16 +4828,41 @@ void RGWPostObj::execute(optional_yield y)
48094828
emplace_attr(RGW_ATTR_COMPRESSION, std::move(tmp));
48104829
}
48114830

4812-
/* TODO: implement POST checksums */
4831+
if (cksum_filter) {
4832+
auto cksum_verify =
4833+
cksum_filter->verify(*s->info.env); // valid or no supplied cksum
4834+
cksum = get<1>(cksum_verify);
4835+
if (std::get<0>(cksum_verify)) {
4836+
buffer::list cksum_bl;
4837+
cksum->encode(cksum_bl);
4838+
emplace_attr(RGW_ATTR_CKSUM, std::move(cksum_bl));
4839+
} else {
4840+
/* content checksum mismatch */
4841+
const auto &hdr = cksum_filter->header();
4842+
ldpp_dout(this, 4) << fmt::format("{} content checksum mismatch",
4843+
hdr.second)
4844+
<< fmt::format(
4845+
"\n\tcalculated={} != \n\texpected={}",
4846+
cksum->to_armor(),
4847+
cksum_filter->expected(*s->info.env))
4848+
<< dendl;
4849+
op_ret = -ERR_INVALID_REQUEST;
4850+
return;
4851+
}
4852+
}
4853+
48134854
const req_context rctx{this, s->yield, s->trace.get()};
48144855
op_ret = processor->complete(s->obj_size, etag, nullptr, real_time(),
4815-
attrs, rgw::cksum::no_cksum,
4856+
attrs, cksum,
48164857
(delete_at ? *delete_at : real_time()),
48174858
nullptr, nullptr, nullptr, nullptr, nullptr,
48184859
rctx, rgw::sal::FLAG_LOG_OP);
48194860
if (op_ret < 0) {
48204861
return;
48214862
}
4863+
4864+
/* XXX shouldn't we have an op-counter update here? */
4865+
48224866
} while (is_next_file_to_upload());
48234867

48244868
// send request to notification manager
@@ -4827,8 +4871,7 @@ void RGWPostObj::execute(optional_yield y)
48274871
ldpp_dout(this, 1) << "ERROR: publishing notification failed, with error: " << ret << dendl;
48284872
// too late to rollback operation, hence op_ret is not set here
48294873
}
4830-
}
4831-
4874+
} /* RGWPostObj::execute() */
48324875

48334876
void RGWPutMetadataAccount::filter_out_temp_url(map<string, bufferlist>& add_attrs,
48344877
const set<string>& rmattr_names,

src/rgw/rgw_op.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,7 @@ class RGWPostObj : public RGWOp {
13351335
RGWAccessControlPolicy policy;
13361336
std::map<std::string, bufferlist> attrs;
13371337
boost::optional<ceph::real_time> delete_at;
1338+
std::optional<rgw::cksum::Cksum> cksum;
13381339

13391340
/* Must be called after get_data() or the result is undefined. */
13401341
virtual std::string get_current_filename() const = 0;

src/rgw/rgw_policy_s3.cc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "rgw_policy_s3.h"
88
#include "rgw_common.h"
99
#include "rgw_crypt_sanitize.h"
10+
#include "rgw_cksum.h"
1011

1112
#define dout_context g_ceph_context
1213
#define dout_subsys ceph_subsys_rgw
@@ -101,15 +102,20 @@ bool RGWPolicyEnv::get_value(const string& s, string& val, map<string, bool, lts
101102
return get_var(var, val);
102103
}
103104

104-
105-
bool RGWPolicyEnv::match_policy_vars(map<string, bool, ltstr_nocase>& policy_vars, string& err_msg)
105+
bool RGWPolicyEnv::match_policy_vars(
106+
map<string, bool, ltstr_nocase>& policy_vars, string& err_msg)
106107
{
107108
map<string, string, ltstr_nocase>::iterator iter;
108109
string ignore_prefix = "x-ignore-";
109110
for (iter = vars.begin(); iter != vars.end(); ++iter) {
110111
const string& var = iter->first;
111-
if (strncasecmp(ignore_prefix.c_str(), var.c_str(), ignore_prefix.size()) == 0)
112+
if (strncasecmp(ignore_prefix.c_str(), var.c_str(),
113+
ignore_prefix.size()) == 0) {
114+
continue;
115+
}
116+
if (rgw::cksum::is_checksum_hdr(var)) {
112117
continue;
118+
}
113119
if (policy_vars.count(var) == 0) {
114120
err_msg = "Policy missing condition: ";
115121
err_msg.append(iter->first);
@@ -118,7 +124,7 @@ bool RGWPolicyEnv::match_policy_vars(map<string, bool, ltstr_nocase>& policy_var
118124
}
119125
}
120126
return true;
121-
}
127+
} /* match_policy_vars */
122128

123129
RGWPolicy::~RGWPolicy()
124130
{

src/rgw/rgw_rest_s3.cc

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2962,22 +2962,33 @@ int RGWPostObj_ObjStore_S3::get_params(optional_yield y)
29622962
} while (!done);
29632963

29642964
for (auto &p: parts) {
2965-
if (! boost::istarts_with(p.first, "x-amz-server-side-encryption")) {
2966-
continue;
2967-
}
2968-
bufferlist &d { p.second.data };
2969-
std::string v { rgw_trim_whitespace(std::string_view(d.c_str(), d.length())) };
2970-
rgw_set_amz_meta_header(s->info.crypt_attribute_map, p.first, v, OVERWRITE);
2971-
}
2965+
if (boost::istarts_with(p.first, "x-amz-server-side-encryption")) {
2966+
bufferlist &d { p.second.data };
2967+
std::string v { rgw_trim_whitespace(std::string_view(d.c_str(), d.length())) };
2968+
rgw_set_amz_meta_header(s->info.crypt_attribute_map, p.first, v, OVERWRITE);
2969+
}
2970+
/* checksum headers */
2971+
auto& k = p.first;
2972+
auto cksum_type = rgw::cksum::parse_cksum_type_hdr(k);
2973+
if (cksum_type != rgw::cksum::Type::none) {
2974+
put_prop("HTTP_X_AMZ_CHECKSUM_ALGORITHM",
2975+
safe_upcase_str(to_string(cksum_type)));
2976+
bufferlist& d = p.second.data;
2977+
std::string v {
2978+
rgw_trim_whitespace(std::string_view(d.c_str(), d.length()))};
2979+
put_prop(ys_header_mangle(fmt::format("HTTP-{}", k)), v);
2980+
}
2981+
} /* each part */
29722982

29732983
int r = get_encryption_defaults(s);
29742984
if (r < 0) {
2975-
ldpp_dout(this, 5) << __func__ << "(): get_encryption_defaults() returned ret=" << r << dendl;
2985+
ldpp_dout(this, 5)
2986+
<< __func__ << "(): get_encryption_defaults() returned ret=" << r << dendl;
29762987
return r;
29772988
}
29782989

29792990
ldpp_dout(this, 20) << "adding bucket to policy env: " << s->bucket->get_name()
2980-
<< dendl;
2991+
<< dendl;
29812992
env.add_var("bucket", s->bucket->get_name());
29822993

29832994
string object_str;
@@ -3010,7 +3021,8 @@ int RGWPostObj_ObjStore_S3::get_params(optional_yield y)
30103021
if (! storage_class.empty()) {
30113022
s->dest_placement.storage_class = storage_class;
30123023
if (!driver->valid_placement(s->dest_placement)) {
3013-
ldpp_dout(this, 0) << "NOTICE: invalid dest placement: " << s->dest_placement.to_str() << dendl;
3024+
ldpp_dout(this, 0) << "NOTICE: invalid dest placement: "
3025+
<< s->dest_placement.to_str() << dendl;
30143026
err_msg = "The storage class you specified is not valid";
30153027
return -EINVAL;
30163028
}
@@ -3060,14 +3072,11 @@ int RGWPostObj_ObjStore_S3::get_params(optional_yield y)
30603072
if (r < 0)
30613073
return r;
30623074

3063-
30643075
min_len = post_policy.min_length;
30653076
max_len = post_policy.max_length;
30663077

3067-
3068-
30693078
return 0;
3070-
}
3079+
} /* RGWPostObj_Objstore_S3::get_params() */
30713080

30723081
int RGWPostObj_ObjStore_S3::get_tags()
30733082
{

src/rgw/rgw_rest_s3.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,12 @@ class RGWPostObj_ObjStore_S3 : public RGWPostObj_ObjStore {
303303
std::string get_current_filename() const override;
304304
std::string get_current_content_type() const override;
305305

306+
inline void put_prop(const std::string_view k, const std::string_view v) {
307+
/* assume the caller will mangle the key name, if required */
308+
auto& map = const_cast<env_map_t&>(s->info.env->get_map());
309+
map.insert(env_map_t::value_type(k, v));
310+
}
311+
306312
public:
307313
RGWPostObj_ObjStore_S3() {}
308314
~RGWPostObj_ObjStore_S3() override {}

0 commit comments

Comments
 (0)