From 572289a2c7fb1cceebef7fefdec032ba95418cf4 Mon Sep 17 00:00:00 2001 From: Matt Benjamin Date: Sat, 17 May 2025 15:52:20 -0400 Subject: [PATCH] rgw: recognize checksum from x-amz-checksum-{type} alone Some SDKs may send x-amz-checksum-algorithm or x-amz-sdk-checksum-algorithm regardless as well, but those are only required if the checksum header is in the trailer section. Fixes: https://tracker.ceph.com/issues/71350 Signed-off-by: Matt Benjamin --- src/rgw/rgw_cksum.h | 37 +++++++++++++++++++++++-------------- src/rgw/rgw_cksum_pipe.h | 9 +++++++++ src/rgw/rgw_rest_s3.cc | 9 +++------ 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/rgw/rgw_cksum.h b/src/rgw/rgw_cksum.h index 70836e7c6bacd..c4e2cca682c7f 100644 --- a/src/rgw/rgw_cksum.h +++ b/src/rgw/rgw_cksum.h @@ -60,6 +60,7 @@ namespace rgw { namespace cksum { public: const Type type; const char* name; + const char* name_uc; const uint16_t digest_size; const uint16_t armored_size; const uint16_t flags; @@ -68,9 +69,9 @@ namespace rgw { namespace cksum { return sz / 3 * 4 + 4; } - constexpr Desc(Type _type, const char* _name, uint16_t _size, - uint16_t _flags) - : type(_type), name(_name), + constexpr Desc(Type _type, const char* _name, const char* _name_uc, + uint16_t _size, uint16_t _flags) + : type(_type), name(_name), name_uc(_name_uc), digest_size(_size), armored_size(to_armored_size(digest_size)), flags(_flags) @@ -87,15 +88,15 @@ namespace rgw { namespace cksum { public: static constexpr std::array checksums = { - Desc(Type::none, "none", 0, FLAG_NONE), - Desc(Type::crc32, "crc32", 4, FLAG_AWS_CKSUM|FLAG_CRC), - Desc(Type::crc32c, "crc32c", 4, FLAG_AWS_CKSUM|FLAG_CRC), - Desc(Type::xxh3, "xxh3", 8, FLAG_NONE), - Desc(Type::sha1, "sha1", 20, FLAG_AWS_CKSUM), - Desc(Type::sha256, "sha256", 32, FLAG_AWS_CKSUM), - Desc(Type::sha512, "sha512", 64, FLAG_NONE), - Desc(Type::blake3, "blake3", 32, FLAG_NONE), - Desc(Type::crc64nvme, "crc64nvme", 8, FLAG_AWS_CKSUM|FLAG_CRC), + Desc(Type::none, "none", "NONE", 0, FLAG_NONE), + Desc(Type::crc32, "crc32", "CRC32", 4, FLAG_AWS_CKSUM|FLAG_CRC), + Desc(Type::crc32c, "crc32c", "CRC32C", 4, FLAG_AWS_CKSUM|FLAG_CRC), + Desc(Type::xxh3, "xxh3", "XXH3", 8, FLAG_NONE), + Desc(Type::sha1, "sha1", "SHA1", 20, FLAG_AWS_CKSUM), + Desc(Type::sha256, "sha256", "SHA256", 32, FLAG_AWS_CKSUM), + Desc(Type::sha512, "sha512", "SHA512", 64, FLAG_NONE), + Desc(Type::blake3, "blake3", "BLAKE3", 32, FLAG_NONE), + Desc(Type::crc64nvme, "crc64nvme", "CRC64NVME", 8, FLAG_AWS_CKSUM|FLAG_CRC), }; static constexpr uint16_t max_digest_size = 64; @@ -148,6 +149,10 @@ namespace rgw { namespace cksum { return (Cksum::checksums[uint16_t(type)]).name; } + const char* uc_type_string() const { + return (Cksum::checksums[uint16_t(type)]).name_uc; + } + const bool aws() const { return (Cksum::checksums[uint16_t(type)]).aws(); } @@ -187,8 +192,7 @@ namespace rgw { namespace cksum { } std::string element_name() const { - std::string ts{type_string()}; - return fmt::format("Checksum{}", boost::to_upper_copy(ts)); + return fmt::format("Checksum{}", uc_type_string()); } std::string_view raw() const { @@ -290,6 +294,11 @@ namespace rgw { namespace cksum { return ckd.name; } + static inline std::string to_uc_string(const Type type) { + const auto& ckd = Cksum::checksums[uint16_t(type)]; + return ckd.name_uc; + } + static inline Type parse_cksum_type(const char* name) { for (const auto& ck : Cksum::checksums) { diff --git a/src/rgw/rgw_cksum_pipe.h b/src/rgw/rgw_cksum_pipe.h index da79d17cdac53..f442f67d78e4d 100644 --- a/src/rgw/rgw_cksum_pipe.h +++ b/src/rgw/rgw_cksum_pipe.h @@ -78,6 +78,15 @@ namespace rgw::putobj { return cksum_hdr_t(hk, hv); } } + /* for requests not sending a trailer, we could just have (golang sdk v2) + * a checksum header and payload */ + for (const auto& ck_desc : cksum::Cksum::checksums) { + auto aws_hdr_name = fmt::format("HTTP_X_AMZ_CHECKSUM_{}", ck_desc.name_uc); + auto hv = env.get(aws_hdr_name.c_str()); + if (hv) { + return cksum_hdr_t("HTTP_X_AMZ_CHECKSUM_ALGORITHM", ck_desc.name_uc); + } + } return cksum_hdr_t(nullptr, nullptr); } /* cksum_algorithm_hdr */ diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index c27f8fe91989d..92124499a7a4b 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -3137,8 +3137,7 @@ int RGWPostObj_ObjStore_S3::get_params(optional_yield y) auto& k = p.first; auto cksum_type = rgw::cksum::parse_cksum_type_hdr(k); if (cksum_type != rgw::cksum::Type::none) { - put_prop("HTTP_X_AMZ_CHECKSUM_ALGORITHM", - boost::to_upper_copy(to_string(cksum_type))); + put_prop("HTTP_X_AMZ_CHECKSUM_ALGORITHM", to_uc_string(cksum_type)); bufferlist& d = p.second.data; std::string v { rgw_trim_whitespace(std::string_view(d.c_str(), d.length()))}; @@ -4540,8 +4539,7 @@ void RGWInitMultipart_ObjStore_S3::send_response() dump_header_if_nonempty(s, "x-amz-abort-rule-id", rule_id); } if (cksum_algo != rgw::cksum::Type::none) { - dump_header(s, "x-amz-checksum-algorithm", - boost::to_upper_copy(to_string(cksum_algo))); + dump_header(s, "x-amz-checksum-algorithm", to_uc_string(cksum_algo)); } end_header(s, this, to_mime_type(s->format)); if (op_ret == 0) { @@ -4666,8 +4664,7 @@ void RGWListMultipart_ObjStore_S3::send_response() Container element that identifies who initiated the multipart upload. If the initiator is an AWS account, this element provides the same information as the Owner element. If the initiator is an IAM User, this element provides the user ARN and display name, see https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html */ if (cksum && cksum->aws()) { - s->formatter->dump_string("ChecksumAlgorithm", - boost::to_upper_copy(std::string(cksum->type_string()))); + s->formatter->dump_string("ChecksumAlgorithm", cksum->uc_type_string()); } for (; iter != upload->get_parts().end(); ++iter) { -- 2.39.5