mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-17 10:17:55 +00:00
a9691b6797
backlog#1823 step 10, batch 1 of the repo-wide item-allow sweep. 227 bare #[allow(dead_code)] remain across 83 files; this takes the 19 in utils, notify, checksums, policy, keystone and trusted-proxies, which are small enough to verify end to end. Removing all 19 first, before writing any reason, matters: 8 of them suppress nothing. Every allow in utils, one in policy and three in notify sit on items that are publicly reachable, so dead_code never applied to them — the same shape as the swift module and kms's dek.rs. Writing a reason onto a no-op allow would dress noise up as considered judgement, so those are simply deleted. Three items are genuinely dead and go with their allows: notify's new_target_id_set, the AWS metadata fetcher's get_metadata_token, and policy's empty `pub struct Value;`, none of which is referenced anywhere in the tree. The remaining eight keep an allow, now saying why the item survives rather than who calls it. Two are exercised only by their own crate's tests (checksums' MD5_HEADER_NAME, policy's is_match_as_pattern_prefix). Four are fields written but never read back: keystone's verify_ssl, parsed from config after the reqwest client is already built; keystone's client handle, which keeps the Keystone client alive for the mapper's lifetime; the AWS IMDS endpoint, kept beside the client while requests build their own URLs; and notify's rules_map, whose own comment retains it for snapshot-time judgements no code performs. checksums' Md5 needed the most care. Crc32, Sha256 and seven others each have an arm in ChecksumAlgorithm::into_impl, and Md5 has none, which reads like a missing algorithm. It is not: ChecksumAlgorithm has no Md5 variant at all. S3 carries Content-MD5 as its own header, separate from the x-amz-checksum-* family, and this impl exists so both paths share the Checksum trait. The reason records that, so the next reader does not re-derive it. One measurement note for anyone continuing this sweep: cargo does not re-emit warnings for cached compilations, so a per-crate loop of `cargo check -p <crate>` under-reports. checksums showed zero that way while actually carrying three. Touch the sources and check the crates in one invocation, then attribute by path. Verification: the six crates are warning-free under cargo check --tests; clippy --lib --tests -D warnings clean; cargo nextest run 1096 passed; make pre-commit exit 0. Ref rustfs/backlog#1823 (step 10).
239 lines
8.3 KiB
Rust
239 lines
8.3 KiB
Rust
// Copyright 2024 RustFS Team
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
use crate::base64;
|
|
use http::header::{HeaderMap, HeaderValue};
|
|
|
|
use crate::Crc64Nvme;
|
|
use crate::{
|
|
CRC_32_C_NAME, CRC_32_NAME, CRC_64_NVME_NAME, Checksum, Crc32, Crc32c, Md5, SHA_1_NAME, SHA_256_NAME, Sha1, Sha256, Sha512,
|
|
Xxhash3, Xxhash64, Xxhash128,
|
|
};
|
|
|
|
// DELIBERATE DUPLICATION of the x-amz-checksum-* names that also exist as
|
|
// AMZ_CHECKSUM_* in rustfs-utils' headers module (crates/utils/src/http/
|
|
// headers.rs): this crate is a zero-internal-dependency leaf, so it cannot
|
|
// import them, and it additionally owns the RustFS extension names
|
|
// (sha512/xxhash*) that utils does not carry. Values are pinned by the S3
|
|
// wire protocol; do not merge without a maintainer decision on the leaf
|
|
// boundary (backlog#1833).
|
|
pub const CRC_32_HEADER_NAME: &str = "x-amz-checksum-crc32";
|
|
pub const CRC_32_C_HEADER_NAME: &str = "x-amz-checksum-crc32c";
|
|
pub const SHA_1_HEADER_NAME: &str = "x-amz-checksum-sha1";
|
|
pub const SHA_256_HEADER_NAME: &str = "x-amz-checksum-sha256";
|
|
pub const CRC_64_NVME_HEADER_NAME: &str = "x-amz-checksum-crc64nvme";
|
|
pub const SHA_512_HEADER_NAME: &str = "x-amz-checksum-sha512";
|
|
pub const XXHASH_3_HEADER_NAME: &str = "x-amz-checksum-xxhash3";
|
|
pub const XXHASH_64_HEADER_NAME: &str = "x-amz-checksum-xxhash64";
|
|
pub const XXHASH_128_HEADER_NAME: &str = "x-amz-checksum-xxhash128";
|
|
|
|
#[allow(
|
|
dead_code,
|
|
reason = "Content-MD5 wire name, resolved by header_name() below and asserted by this crate's tests (backlog#1823)"
|
|
)]
|
|
pub(crate) static MD5_HEADER_NAME: &str = "content-md5";
|
|
|
|
pub const CHECKSUM_ALGORITHMS_IN_PRIORITY_ORDER: [&str; 5] =
|
|
[CRC_64_NVME_NAME, CRC_32_C_NAME, CRC_32_NAME, SHA_1_NAME, SHA_256_NAME];
|
|
|
|
pub trait HttpChecksum: Checksum + Send + Sync {
|
|
fn headers(self: Box<Self>) -> HeaderMap<HeaderValue> {
|
|
let mut header_map = HeaderMap::new();
|
|
header_map.insert(self.header_name(), self.header_value());
|
|
|
|
header_map
|
|
}
|
|
|
|
fn header_name(&self) -> &'static str;
|
|
|
|
fn header_value(self: Box<Self>) -> HeaderValue {
|
|
let hash = self.finalize();
|
|
HeaderValue::from_str(&base64::encode(&hash[..])).expect("base64 encoded bytes are always valid header values")
|
|
}
|
|
|
|
fn size(&self) -> u64 {
|
|
let trailer_name_size_in_bytes = self.header_name().len();
|
|
let base64_encoded_checksum_size_in_bytes = base64::encoded_length(Checksum::size(self) as usize);
|
|
|
|
let size = trailer_name_size_in_bytes + ":".len() + base64_encoded_checksum_size_in_bytes;
|
|
|
|
size as u64
|
|
}
|
|
}
|
|
|
|
impl HttpChecksum for Crc32 {
|
|
fn header_name(&self) -> &'static str {
|
|
CRC_32_HEADER_NAME
|
|
}
|
|
}
|
|
|
|
impl HttpChecksum for Crc32c {
|
|
fn header_name(&self) -> &'static str {
|
|
CRC_32_C_HEADER_NAME
|
|
}
|
|
}
|
|
|
|
impl HttpChecksum for Crc64Nvme {
|
|
fn header_name(&self) -> &'static str {
|
|
CRC_64_NVME_HEADER_NAME
|
|
}
|
|
}
|
|
|
|
impl HttpChecksum for Sha1 {
|
|
fn header_name(&self) -> &'static str {
|
|
SHA_1_HEADER_NAME
|
|
}
|
|
}
|
|
|
|
impl HttpChecksum for Sha256 {
|
|
fn header_name(&self) -> &'static str {
|
|
SHA_256_HEADER_NAME
|
|
}
|
|
}
|
|
|
|
impl HttpChecksum for Sha512 {
|
|
fn header_name(&self) -> &'static str {
|
|
SHA_512_HEADER_NAME
|
|
}
|
|
}
|
|
|
|
impl HttpChecksum for Xxhash3 {
|
|
fn header_name(&self) -> &'static str {
|
|
XXHASH_3_HEADER_NAME
|
|
}
|
|
}
|
|
|
|
impl HttpChecksum for Xxhash64 {
|
|
fn header_name(&self) -> &'static str {
|
|
XXHASH_64_HEADER_NAME
|
|
}
|
|
}
|
|
|
|
impl HttpChecksum for Xxhash128 {
|
|
fn header_name(&self) -> &'static str {
|
|
XXHASH_128_HEADER_NAME
|
|
}
|
|
}
|
|
|
|
impl HttpChecksum for Md5 {
|
|
fn header_name(&self) -> &'static str {
|
|
MD5_HEADER_NAME
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::base64;
|
|
use bytes::Bytes;
|
|
|
|
use crate::{CRC_32_C_NAME, CRC_32_NAME, CRC_64_NVME_NAME, ChecksumAlgorithm, SHA_1_NAME, SHA_256_NAME};
|
|
|
|
use super::HttpChecksum;
|
|
|
|
#[test]
|
|
fn test_trailer_length_of_crc32_checksum_body() {
|
|
let checksum = CRC_32_NAME.parse::<ChecksumAlgorithm>().unwrap().into_impl();
|
|
let expected_size = 29;
|
|
let actual_size = HttpChecksum::size(&*checksum);
|
|
assert_eq!(expected_size, actual_size)
|
|
}
|
|
|
|
#[test]
|
|
fn test_trailer_value_of_crc32_checksum_body() {
|
|
let checksum = CRC_32_NAME.parse::<ChecksumAlgorithm>().unwrap().into_impl();
|
|
// The CRC32 of an empty string is all zeroes
|
|
let expected_value = Bytes::from_static(b"\0\0\0\0");
|
|
let expected_value = base64::encode(&expected_value);
|
|
let actual_value = checksum.header_value();
|
|
assert_eq!(expected_value, actual_value)
|
|
}
|
|
|
|
#[test]
|
|
fn test_trailer_length_of_crc32c_checksum_body() {
|
|
let checksum = CRC_32_C_NAME.parse::<ChecksumAlgorithm>().unwrap().into_impl();
|
|
let expected_size = 30;
|
|
let actual_size = HttpChecksum::size(&*checksum);
|
|
assert_eq!(expected_size, actual_size)
|
|
}
|
|
|
|
#[test]
|
|
fn test_trailer_value_of_crc32c_checksum_body() {
|
|
let checksum = CRC_32_C_NAME.parse::<ChecksumAlgorithm>().unwrap().into_impl();
|
|
// The CRC32C of an empty string is all zeroes
|
|
let expected_value = Bytes::from_static(b"\0\0\0\0");
|
|
let expected_value = base64::encode(&expected_value);
|
|
let actual_value = checksum.header_value();
|
|
assert_eq!(expected_value, actual_value)
|
|
}
|
|
|
|
#[test]
|
|
fn test_trailer_length_of_crc64nvme_checksum_body() {
|
|
let checksum = CRC_64_NVME_NAME.parse::<ChecksumAlgorithm>().unwrap().into_impl();
|
|
let expected_size = 37;
|
|
let actual_size = HttpChecksum::size(&*checksum);
|
|
assert_eq!(expected_size, actual_size)
|
|
}
|
|
|
|
#[test]
|
|
fn test_trailer_value_of_crc64nvme_checksum_body() {
|
|
let checksum = CRC_64_NVME_NAME.parse::<ChecksumAlgorithm>().unwrap().into_impl();
|
|
// The CRC64NVME of an empty string is all zeroes
|
|
let expected_value = Bytes::from_static(b"\0\0\0\0\0\0\0\0");
|
|
let expected_value = base64::encode(&expected_value);
|
|
let actual_value = checksum.header_value();
|
|
assert_eq!(expected_value, actual_value)
|
|
}
|
|
|
|
#[test]
|
|
fn test_trailer_length_of_sha1_checksum_body() {
|
|
let checksum = SHA_1_NAME.parse::<ChecksumAlgorithm>().unwrap().into_impl();
|
|
let expected_size = 48;
|
|
let actual_size = HttpChecksum::size(&*checksum);
|
|
assert_eq!(expected_size, actual_size)
|
|
}
|
|
|
|
#[test]
|
|
fn test_trailer_value_of_sha1_checksum_body() {
|
|
let checksum = SHA_1_NAME.parse::<ChecksumAlgorithm>().unwrap().into_impl();
|
|
// The SHA1 of an empty string is da39a3ee5e6b4b0d3255bfef95601890afd80709
|
|
let expected_value = Bytes::from_static(&[
|
|
0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07,
|
|
0x09,
|
|
]);
|
|
let expected_value = base64::encode(&expected_value);
|
|
let actual_value = checksum.header_value();
|
|
assert_eq!(expected_value, actual_value)
|
|
}
|
|
|
|
#[test]
|
|
fn test_trailer_length_of_sha256_checksum_body() {
|
|
let checksum = SHA_256_NAME.parse::<ChecksumAlgorithm>().unwrap().into_impl();
|
|
let expected_size = 66;
|
|
let actual_size = HttpChecksum::size(&*checksum);
|
|
assert_eq!(expected_size, actual_size)
|
|
}
|
|
|
|
#[test]
|
|
fn test_trailer_value_of_sha256_checksum_body() {
|
|
let checksum = SHA_256_NAME.parse::<ChecksumAlgorithm>().unwrap().into_impl();
|
|
let expected_value = Bytes::from_static(&[
|
|
0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41,
|
|
0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
|
|
]);
|
|
let expected_value = base64::encode(&expected_value);
|
|
let actual_value = checksum.header_value();
|
|
assert_eq!(expected_value, actual_value)
|
|
}
|
|
}
|