mirror of
https://github.com/deuxfleurs-org/garage.git
synced 2026-07-26 07:58:14 +00:00
api: switch to crc_fast for checksumming and implement full-object mpu checksums
This commit is contained in:
Generated
+61
-22
@@ -556,7 +556,7 @@ checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"instant",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -838,6 +838,20 @@ version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||
|
||||
[[package]]
|
||||
name = "crc-fast"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf0ab672ed7761a44410115d2e0e5ccd86b987ba186a78a4148fb02bb302a774"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"crc",
|
||||
"digest",
|
||||
"libc",
|
||||
"rand 0.9.1",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32c"
|
||||
version = "0.6.8"
|
||||
@@ -896,7 +910,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
@@ -1211,7 +1225,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"bytesize",
|
||||
"chrono",
|
||||
"crc32fast",
|
||||
"crc-fast",
|
||||
"format_table",
|
||||
"futures",
|
||||
"garage_api_admin",
|
||||
@@ -1292,9 +1306,7 @@ dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"crc32c",
|
||||
"crc32fast",
|
||||
"crc64fast-nvme",
|
||||
"crc-fast",
|
||||
"crypto-common",
|
||||
"err-derive",
|
||||
"futures",
|
||||
@@ -1353,9 +1365,7 @@ dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"crc32c",
|
||||
"crc32fast",
|
||||
"crc64fast-nvme",
|
||||
"crc-fast",
|
||||
"err-derive",
|
||||
"form_urlencoded",
|
||||
"futures",
|
||||
@@ -1407,7 +1417,7 @@ dependencies = [
|
||||
"garage_util",
|
||||
"hex",
|
||||
"opentelemetry",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"tokio",
|
||||
"tokio-util 0.7.14",
|
||||
@@ -1448,7 +1458,7 @@ dependencies = [
|
||||
"hex",
|
||||
"http 1.3.1",
|
||||
"parse_duration",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"tokio",
|
||||
@@ -1473,7 +1483,7 @@ dependencies = [
|
||||
"opentelemetry-contrib",
|
||||
"pin-project",
|
||||
"pretty_env_logger",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rmp-serde",
|
||||
"serde",
|
||||
"tokio",
|
||||
@@ -1503,7 +1513,7 @@ dependencies = [
|
||||
"nix",
|
||||
"opentelemetry",
|
||||
"pnet_datalink",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"reqwest",
|
||||
"schemars",
|
||||
"serde",
|
||||
@@ -1527,7 +1537,7 @@ dependencies = [
|
||||
"hex",
|
||||
"hexdump",
|
||||
"opentelemetry",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"tokio",
|
||||
@@ -1554,7 +1564,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"mktemp",
|
||||
"opentelemetry",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rmp-serde",
|
||||
"rustc_version",
|
||||
"serde",
|
||||
@@ -2868,7 +2878,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
@@ -3010,7 +3020,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
@@ -3359,8 +3369,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3370,7 +3390,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3382,6 +3412,15 @@ dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom 0.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
@@ -4465,7 +4504,7 @@ dependencies = [
|
||||
"indexmap 1.9.3",
|
||||
"pin-project",
|
||||
"pin-project-lite",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util 0.7.14",
|
||||
@@ -4717,7 +4756,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
+1
-3
@@ -49,9 +49,7 @@ bytes = "1.0"
|
||||
bytesize = "1.1"
|
||||
cfg-if = "1.0"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
crc32fast = "1.4"
|
||||
crc32c = "0.6"
|
||||
crc64fast-nvme = "1.2"
|
||||
crc-fast = "1.1"
|
||||
crypto-common = "0.1"
|
||||
err-derive = "0.3"
|
||||
gethostname = "0.4"
|
||||
|
||||
@@ -21,9 +21,7 @@ garage_util.workspace = true
|
||||
base64.workspace = true
|
||||
bytes.workspace = true
|
||||
chrono.workspace = true
|
||||
crc32fast.workspace = true
|
||||
crc32c.workspace = true
|
||||
crc64fast-nvme.workspace = true
|
||||
crc-fast.workspace = true
|
||||
crypto-common.workspace = true
|
||||
err-derive.workspace = true
|
||||
hex.workspace = true
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::hash::Hasher;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use base64::prelude::*;
|
||||
use crc32c::Crc32cHasher as Crc32c;
|
||||
use crc32fast::Hasher as Crc32;
|
||||
use crc64fast_nvme::Digest as Crc64Nvme;
|
||||
use crc_fast::{CrcAlgorithm, Digest as CrcDigest};
|
||||
use md5::{Digest, Md5};
|
||||
use sha1::Sha1;
|
||||
use sha2::Sha256;
|
||||
@@ -41,6 +38,21 @@ pub type Md5Checksum = [u8; 16];
|
||||
pub type Sha1Checksum = [u8; 20];
|
||||
pub type Sha256Checksum = [u8; 32];
|
||||
|
||||
// -- MAP OF CRC ALGORITHMS :
|
||||
// CRC32 -> CrcAlgorithm::Crc32IsoHdlc
|
||||
// CRC32C -> CrcAlgorithm::Crc32Iscsi
|
||||
// CRC64NVME -> CrcAlgorithm::Crc64Nvme
|
||||
|
||||
pub fn new_crc32() -> CrcDigest {
|
||||
CrcDigest::new(CrcAlgorithm::Crc32IsoHdlc)
|
||||
}
|
||||
pub fn new_crc32c() -> CrcDigest {
|
||||
CrcDigest::new(CrcAlgorithm::Crc32Iscsi)
|
||||
}
|
||||
pub fn new_crc64nvme() -> CrcDigest {
|
||||
CrcDigest::new(CrcAlgorithm::Crc64Nvme)
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct ExpectedChecksums {
|
||||
// base64-encoded md5 (content-md5 header)
|
||||
@@ -52,9 +64,9 @@ pub struct ExpectedChecksums {
|
||||
}
|
||||
|
||||
pub struct Checksummer {
|
||||
pub crc32: Option<Crc32>,
|
||||
pub crc32c: Option<Crc32c>,
|
||||
pub crc64nvme: Option<Crc64Nvme>,
|
||||
pub crc32: Option<CrcDigest>,
|
||||
pub crc32c: Option<CrcDigest>,
|
||||
pub crc64nvme: Option<CrcDigest>,
|
||||
pub md5: Option<Md5>,
|
||||
pub sha1: Option<Sha1>,
|
||||
pub sha256: Option<Sha256>,
|
||||
@@ -103,13 +115,13 @@ impl Checksummer {
|
||||
self.sha256 = Some(Sha256::new());
|
||||
}
|
||||
if matches!(&expected.extra, Some(ChecksumValue::Crc32(_))) {
|
||||
self.crc32 = Some(Crc32::new());
|
||||
self.crc32 = Some(new_crc32());
|
||||
}
|
||||
if matches!(&expected.extra, Some(ChecksumValue::Crc32c(_))) {
|
||||
self.crc32c = Some(Crc32c::default());
|
||||
self.crc32c = Some(new_crc32c());
|
||||
}
|
||||
if matches!(&expected.extra, Some(ChecksumValue::Crc64Nvme(_))) {
|
||||
self.crc64nvme = Some(Crc64Nvme::default());
|
||||
self.crc64nvme = Some(new_crc64nvme());
|
||||
}
|
||||
if matches!(&expected.extra, Some(ChecksumValue::Sha1(_))) {
|
||||
self.sha1 = Some(Sha1::new());
|
||||
@@ -119,13 +131,13 @@ impl Checksummer {
|
||||
pub fn add(mut self, algo: Option<ChecksumAlgorithm>) -> Self {
|
||||
match algo {
|
||||
Some(ChecksumAlgorithm::Crc32) => {
|
||||
self.crc32 = Some(Crc32::new());
|
||||
self.crc32 = Some(new_crc32());
|
||||
}
|
||||
Some(ChecksumAlgorithm::Crc32c) => {
|
||||
self.crc32c = Some(Crc32c::default());
|
||||
self.crc32c = Some(new_crc32c());
|
||||
}
|
||||
Some(ChecksumAlgorithm::Crc64Nvme) => {
|
||||
self.crc64nvme = Some(Crc64Nvme::default());
|
||||
self.crc64nvme = Some(new_crc64nvme());
|
||||
}
|
||||
Some(ChecksumAlgorithm::Sha1) => {
|
||||
self.sha1 = Some(Sha1::new());
|
||||
@@ -143,10 +155,10 @@ impl Checksummer {
|
||||
crc32.update(bytes);
|
||||
}
|
||||
if let Some(crc32c) = &mut self.crc32c {
|
||||
crc32c.write(bytes);
|
||||
crc32c.update(bytes);
|
||||
}
|
||||
if let Some(crc64nvme) = &mut self.crc64nvme {
|
||||
crc64nvme.write(bytes);
|
||||
crc64nvme.update(bytes);
|
||||
}
|
||||
if let Some(md5) = &mut self.md5 {
|
||||
md5.update(bytes);
|
||||
@@ -161,11 +173,9 @@ impl Checksummer {
|
||||
|
||||
pub fn finalize(self) -> Checksums {
|
||||
Checksums {
|
||||
crc32: self.crc32.map(|x| u32::to_be_bytes(x.finalize())),
|
||||
crc32c: self
|
||||
.crc32c
|
||||
.map(|x| u32::to_be_bytes(u32::try_from(x.finish()).unwrap())),
|
||||
crc64nvme: self.crc64nvme.map(|x| u64::to_be_bytes(x.sum64())),
|
||||
crc32: self.crc32.map(|x| u32::to_be_bytes(x.finalize() as u32)),
|
||||
crc32c: self.crc32c.map(|x| u32::to_be_bytes(x.finalize() as u32)),
|
||||
crc64nvme: self.crc64nvme.map(|x| u64::to_be_bytes(x.finalize())),
|
||||
md5: self.md5.map(|x| x.finalize()[..].try_into().unwrap()),
|
||||
sha1: self.sha1.map(|x| x.finalize()[..].try_into().unwrap()),
|
||||
sha256: self.sha256.map(|x| x.finalize()[..].try_into().unwrap()),
|
||||
@@ -197,10 +207,11 @@ impl Checksums {
|
||||
}
|
||||
if let Some(extra) = expected.extra {
|
||||
let algo = extra.algorithm();
|
||||
if self.extract(Some(algo)) != Some(extra) {
|
||||
let calculated = self.extract(Some(algo));
|
||||
if calculated != Some(extra) {
|
||||
return Err(Error::InvalidDigest(format!(
|
||||
"Failed to validate checksum for algorithm {:?}",
|
||||
algo
|
||||
"Failed to validate checksum for algorithm {:?}: calculated {:?}, expected {:?}",
|
||||
algo, calculated, extra
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,7 @@ async-compression.workspace = true
|
||||
base64.workspace = true
|
||||
bytes.workspace = true
|
||||
chrono.workspace = true
|
||||
crc32fast.workspace = true
|
||||
crc32c.workspace = true
|
||||
crc64fast-nvme.workspace = true
|
||||
crc-fast.workspace = true
|
||||
err-derive.workspace = true
|
||||
hex.workspace = true
|
||||
hmac.workspace = true
|
||||
|
||||
@@ -1002,9 +1002,11 @@ mod tests {
|
||||
inner: ObjectVersionMetaInner {
|
||||
headers: vec![],
|
||||
checksum: None,
|
||||
checksum_type: None,
|
||||
},
|
||||
},
|
||||
checksum_algorithm: None,
|
||||
checksum_type: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
+126
-85
@@ -1,12 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::hash::Hasher;
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
|
||||
use base64::prelude::*;
|
||||
use crc32c::Crc32cHasher as Crc32c;
|
||||
use crc32fast::Hasher as Crc32;
|
||||
use crc64fast_nvme::Digest as Crc64Nvme;
|
||||
use crc_fast::{CrcAlgorithm, Digest as CrcDigest};
|
||||
use futures::prelude::*;
|
||||
use hyper::{header::HeaderValue, HeaderMap, Request, Response};
|
||||
use md5::{Digest, Md5};
|
||||
@@ -410,7 +407,11 @@ pub async fn handle_complete_multipart_upload(
|
||||
// https://teppen.io/2018/06/23/aws_s3_etags/
|
||||
let mut checksummer = MultipartChecksummer::init(checksum_algorithm, checksum_type);
|
||||
for part in parts.iter() {
|
||||
checksummer.update(part.etag.as_ref().unwrap(), part.checksum)?;
|
||||
checksummer.update(
|
||||
part.etag.as_ref().unwrap(),
|
||||
part.checksum,
|
||||
part.size.unwrap(),
|
||||
)?;
|
||||
}
|
||||
let (checksum_md5, checksum_extra) = checksummer.finalize();
|
||||
|
||||
@@ -693,36 +694,14 @@ pub(crate) struct MultipartChecksummer {
|
||||
pub extra: Option<MultipartExtraChecksummer>,
|
||||
}
|
||||
|
||||
pub(crate) enum MultipartExtraChecksummer {
|
||||
Crc32(Crc32),
|
||||
Crc32c(Crc32c),
|
||||
Crc64Nvme(Crc64Nvme),
|
||||
Sha1(Sha1),
|
||||
Sha256(Sha256),
|
||||
}
|
||||
|
||||
impl MultipartChecksummer {
|
||||
pub(crate) fn init(algo: Option<ChecksumAlgorithm>, cktype: Option<ChecksumType>) -> Self {
|
||||
if cktype == Some(ChecksumType::FullObject) {
|
||||
todo!()
|
||||
}
|
||||
Self {
|
||||
md5: Md5::new(),
|
||||
extra: match algo {
|
||||
None => None,
|
||||
Some(ChecksumAlgorithm::Crc32) => {
|
||||
Some(MultipartExtraChecksummer::Crc32(Crc32::new()))
|
||||
}
|
||||
Some(ChecksumAlgorithm::Crc32c) => {
|
||||
Some(MultipartExtraChecksummer::Crc32c(Crc32c::default()))
|
||||
}
|
||||
Some(ChecksumAlgorithm::Crc64Nvme) => {
|
||||
Some(MultipartExtraChecksummer::Crc64Nvme(Crc64Nvme::default()))
|
||||
}
|
||||
Some(ChecksumAlgorithm::Sha1) => Some(MultipartExtraChecksummer::Sha1(Sha1::new())),
|
||||
Some(ChecksumAlgorithm::Sha256) => {
|
||||
Some(MultipartExtraChecksummer::Sha256(Sha256::new()))
|
||||
}
|
||||
extra: match (algo, cktype) {
|
||||
(None, None) => None,
|
||||
(Some(algo), Some(cktype)) => Some(MultipartExtraChecksummer::init(algo, cktype)),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -731,68 +710,130 @@ impl MultipartChecksummer {
|
||||
&mut self,
|
||||
etag: &str,
|
||||
checksum: Option<ChecksumValue>,
|
||||
part_len: u64,
|
||||
) -> Result<(), Error> {
|
||||
self.md5
|
||||
.update(&hex::decode(&etag).ok_or_message("invalid etag hex")?);
|
||||
match (&mut self.extra, checksum) {
|
||||
(None, _) => (),
|
||||
(
|
||||
Some(MultipartExtraChecksummer::Crc32(ref mut crc32)),
|
||||
Some(ChecksumValue::Crc32(x)),
|
||||
) => {
|
||||
crc32.update(&x);
|
||||
}
|
||||
(
|
||||
Some(MultipartExtraChecksummer::Crc32c(ref mut crc32c)),
|
||||
Some(ChecksumValue::Crc32c(x)),
|
||||
) => {
|
||||
crc32c.write(&x);
|
||||
}
|
||||
(
|
||||
Some(MultipartExtraChecksummer::Crc64Nvme(ref mut crc64nvme)),
|
||||
Some(ChecksumValue::Crc64Nvme(x)),
|
||||
) => {
|
||||
crc64nvme.write(&x);
|
||||
}
|
||||
(Some(MultipartExtraChecksummer::Sha1(ref mut sha1)), Some(ChecksumValue::Sha1(x))) => {
|
||||
sha1.update(&x);
|
||||
}
|
||||
(
|
||||
Some(MultipartExtraChecksummer::Sha256(ref mut sha256)),
|
||||
Some(ChecksumValue::Sha256(x)),
|
||||
) => {
|
||||
sha256.update(&x);
|
||||
}
|
||||
(Some(_), b) => {
|
||||
return Err(Error::internal_error(format!(
|
||||
"part checksum was not computed correctly, got: {:?}",
|
||||
b
|
||||
)))
|
||||
}
|
||||
if let Some(extra) = &mut self.extra {
|
||||
extra.update(checksum, part_len)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn finalize(self) -> (Md5Checksum, Option<ChecksumValue>) {
|
||||
let md5 = self.md5.finalize()[..].try_into().unwrap();
|
||||
let extra = match self.extra {
|
||||
None => None,
|
||||
Some(MultipartExtraChecksummer::Crc32(crc32)) => {
|
||||
Some(ChecksumValue::Crc32(u32::to_be_bytes(crc32.finalize())))
|
||||
}
|
||||
Some(MultipartExtraChecksummer::Crc32c(crc32c)) => Some(ChecksumValue::Crc32c(
|
||||
u32::to_be_bytes(u32::try_from(crc32c.finish()).unwrap()),
|
||||
)),
|
||||
Some(MultipartExtraChecksummer::Crc64Nvme(crc64nvme)) => Some(
|
||||
ChecksumValue::Crc64Nvme(u64::to_be_bytes(crc64nvme.sum64())),
|
||||
),
|
||||
Some(MultipartExtraChecksummer::Sha1(sha1)) => {
|
||||
Some(ChecksumValue::Sha1(sha1.finalize()[..].try_into().unwrap()))
|
||||
}
|
||||
Some(MultipartExtraChecksummer::Sha256(sha256)) => Some(ChecksumValue::Sha256(
|
||||
sha256.finalize()[..].try_into().unwrap(),
|
||||
)),
|
||||
};
|
||||
let extra = self.extra.map(|c| c.finalize());
|
||||
(md5, extra)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum MultipartExtraChecksummer {
|
||||
FullObjectCrc(CrcAlgorithm, Option<u64>),
|
||||
CompositeCrc(ChecksumAlgorithm, CrcDigest),
|
||||
CompositeSha1(Sha1),
|
||||
CompositeSha256(Sha256),
|
||||
}
|
||||
|
||||
impl MultipartExtraChecksummer {
|
||||
fn init(algo: ChecksumAlgorithm, cktype: ChecksumType) -> Self {
|
||||
match (algo, cktype) {
|
||||
(algo, ChecksumType::FullObject) => {
|
||||
let crc_type = match algo {
|
||||
ChecksumAlgorithm::Crc32 => CrcAlgorithm::Crc32IsoHdlc,
|
||||
ChecksumAlgorithm::Crc32c => CrcAlgorithm::Crc32Iscsi,
|
||||
ChecksumAlgorithm::Crc64Nvme => CrcAlgorithm::Crc64Nvme,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
Self::FullObjectCrc(crc_type, None)
|
||||
}
|
||||
(ChecksumAlgorithm::Crc32, ChecksumType::Composite) => {
|
||||
Self::CompositeCrc(ChecksumAlgorithm::Crc32, new_crc32())
|
||||
}
|
||||
(ChecksumAlgorithm::Crc32c, ChecksumType::Composite) => {
|
||||
Self::CompositeCrc(ChecksumAlgorithm::Crc32c, new_crc32c())
|
||||
}
|
||||
(ChecksumAlgorithm::Sha1, ChecksumType::Composite) => Self::CompositeSha1(Sha1::new()),
|
||||
(ChecksumAlgorithm::Sha256, ChecksumType::Composite) => {
|
||||
Self::CompositeSha256(Sha256::new())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, checksum: Option<ChecksumValue>, part_len: u64) -> Result<(), Error> {
|
||||
match (self, checksum) {
|
||||
(Self::FullObjectCrc(crc_algo, crc_value), Some(ck)) => {
|
||||
let ck_u64 = match ck {
|
||||
ChecksumValue::Crc32(x) => u32::from_be_bytes(x) as u64,
|
||||
ChecksumValue::Crc32c(x) => u32::from_be_bytes(x) as u64,
|
||||
ChecksumValue::Crc64Nvme(x) => u64::from_be_bytes(x),
|
||||
_ => {
|
||||
return Err(Error::internal_error(format!(
|
||||
"part checksum was not computed correctly, got: {:?}",
|
||||
ck
|
||||
)))
|
||||
}
|
||||
};
|
||||
*crc_value = match *crc_value {
|
||||
None => Some(ck_u64),
|
||||
Some(prev) => Some(crc_fast::checksum_combine(
|
||||
*crc_algo, prev, ck_u64, part_len,
|
||||
)),
|
||||
};
|
||||
}
|
||||
(Self::CompositeCrc(_, digest), Some(ck)) => match ck {
|
||||
ChecksumValue::Crc32(x) => digest.update(&x),
|
||||
ChecksumValue::Crc32c(x) => digest.update(&x),
|
||||
ChecksumValue::Crc64Nvme(x) => digest.update(&x),
|
||||
_ => {
|
||||
return Err(Error::internal_error(format!(
|
||||
"part checksum was not computed correctly, got: {:?}",
|
||||
ck
|
||||
)))
|
||||
}
|
||||
},
|
||||
(Self::CompositeSha1(sha1), Some(ChecksumValue::Sha1(x))) => {
|
||||
sha1.update(&x);
|
||||
}
|
||||
(Self::CompositeSha256(sha256), Some(ChecksumValue::Sha256(x))) => {
|
||||
sha256.update(&x);
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::internal_error(format!(
|
||||
"part checksum was not computed correctly, got: {:?}",
|
||||
checksum
|
||||
)))
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn finalize(self) -> ChecksumValue {
|
||||
match self {
|
||||
Self::FullObjectCrc(algo, value) => match (algo, value) {
|
||||
(CrcAlgorithm::Crc32IsoHdlc, Some(v)) => {
|
||||
ChecksumValue::Crc32(u32::to_be_bytes(v as u32))
|
||||
}
|
||||
(CrcAlgorithm::Crc32Iscsi, Some(v)) => {
|
||||
ChecksumValue::Crc32c(u32::to_be_bytes(v as u32))
|
||||
}
|
||||
(CrcAlgorithm::Crc64Nvme, Some(v)) => ChecksumValue::Crc64Nvme(u64::to_be_bytes(v)),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Self::CompositeCrc(algo, crc) => match algo {
|
||||
ChecksumAlgorithm::Crc32 => {
|
||||
ChecksumValue::Crc32(u32::to_be_bytes(crc.finalize() as u32))
|
||||
}
|
||||
ChecksumAlgorithm::Crc32c => {
|
||||
ChecksumValue::Crc32c(u32::to_be_bytes(crc.finalize() as u32))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Self::CompositeSha1(sha1) => {
|
||||
ChecksumValue::Sha1(sha1.finalize()[..].try_into().unwrap())
|
||||
}
|
||||
Self::CompositeSha256(sha256) => {
|
||||
ChecksumValue::Sha256(sha256.finalize()[..].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ static_init.workspace = true
|
||||
assert-json-diff.workspace = true
|
||||
serde_json.workspace = true
|
||||
base64.workspace = true
|
||||
crc32fast.workspace = true
|
||||
crc-fast.workspace = true
|
||||
|
||||
k2v-client.workspace = true
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use base64::prelude::*;
|
||||
use crc32fast::Hasher as Crc32;
|
||||
use crc_fast::{checksum as crc_checksum, CrcAlgorithm};
|
||||
|
||||
use crate::common;
|
||||
use crate::common::ext::CommandExt;
|
||||
@@ -69,9 +69,8 @@ async fn test_putobject_streaming() {
|
||||
{
|
||||
let etag = "\"46cf18a9b447991b450cad3facf5937e\"";
|
||||
|
||||
let mut crc32 = Crc32::new();
|
||||
crc32.update(&BODY[..]);
|
||||
let crc32 = BASE64_STANDARD.encode(&u32::to_be_bytes(crc32.finalize())[..]);
|
||||
let crc32 = crc_checksum(CrcAlgorithm::Crc32IsoHdlc, &BODY[..]) as u32;
|
||||
let crc32 = BASE64_STANDARD.encode(&u32::to_be_bytes(crc32)[..]);
|
||||
|
||||
let mut headers = HashMap::new();
|
||||
headers.insert("x-amz-checksum-crc32".to_owned(), crc32.clone());
|
||||
@@ -129,7 +128,8 @@ async fn test_putobject_streaming_unsigned_trailer() {
|
||||
let mut headers = HashMap::new();
|
||||
headers.insert("content-type".to_owned(), content_type.to_owned());
|
||||
|
||||
let empty_crc32 = BASE64_STANDARD.encode(&u32::to_be_bytes(Crc32::new().finalize())[..]);
|
||||
let empty_crc32 = crc_checksum(CrcAlgorithm::Crc32IsoHdlc, &[]) as u32;
|
||||
let empty_crc32 = BASE64_STANDARD.encode(&u32::to_be_bytes(empty_crc32)[..]);
|
||||
|
||||
let res = ctx
|
||||
.custom_request
|
||||
@@ -180,9 +180,8 @@ async fn test_putobject_streaming_unsigned_trailer() {
|
||||
{
|
||||
let etag = "\"46cf18a9b447991b450cad3facf5937e\"";
|
||||
|
||||
let mut crc32 = Crc32::new();
|
||||
crc32.update(&BODY[..]);
|
||||
let crc32 = BASE64_STANDARD.encode(&u32::to_be_bytes(crc32.finalize())[..]);
|
||||
let crc32 = crc_checksum(CrcAlgorithm::Crc32IsoHdlc, &BODY[..]) as u32;
|
||||
let crc32 = BASE64_STANDARD.encode(&u32::to_be_bytes(crc32)[..]);
|
||||
|
||||
// try sending with wrong crc32, check that it fails
|
||||
let err_res = ctx
|
||||
|
||||
Reference in New Issue
Block a user