diff --git a/Cargo.lock b/Cargo.lock index 7b83156ba..b2db988dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -766,9 +766,9 @@ dependencies = [ [[package]] name = "async-rs" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd5147201b63ba6883ffabca3a153822f71541748d7108e3e799beaeb283131" +checksum = "c5f55b2bcef73a79a2feb5496478693077b60b7337896f0b72431cd5311d988a" dependencies = [ "async-compat", "async-global-executor", @@ -971,9 +971,9 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.116.0" +version = "1.117.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "484ecdbea2a1cfc0e6eea69ce0a665f93913671b303ba40b2361b1d826544e7e" +checksum = "83b602641be84ebe5f96606cfefe4b96efaae1fd947c1b34ea8513b8ac0d2d8d" dependencies = [ "arc-swap", "aws-credential-types", @@ -997,9 +997,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.143.0" +version = "1.144.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ade5433c9561daac7c0c6bc910f1240b4f8ec0d6148b0b463aac0691d747c9" +checksum = "30dc8bf6baaf7d46336a0ca2c69f223d9b90d7a801fb3e28f7ea17b00dc6b1de" dependencies = [ "arc-swap", "aws-credential-types", @@ -1024,7 +1024,7 @@ dependencies = [ "http 0.2.12", "http 1.5.0", "http-body 1.1.0", - "lru 0.16.4", + "lru 0.18.2", "percent-encoding", "regex-lite", "sha2 0.11.0", @@ -1034,9 +1034,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.107.0" +version = "1.108.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "769b0abd0f89cfe11da5099986dd493e4f94347ce9a4562cb86ddecfe926b6c0" +checksum = "c15301b04372832947916607983b114b3374b9db0be058a00fb7513800de1f05" dependencies = [ "arc-swap", "aws-credential-types", @@ -1060,9 +1060,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.109.0" +version = "1.110.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4075b8a2c8cda4076a3dcc43b9d6dabd93e0c2502abeaaf7e14aaead9bb312b" +checksum = "72cc2c205cb27108183cf1856333f7d584c2ba0f505421b4209ca5828f9ea899" dependencies = [ "arc-swap", "aws-credential-types", @@ -1086,9 +1086,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.112.0" +version = "1.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f582002918346a3e685be1b391c7bea155073088cea6bd4e4b7663df9e43b6c" +checksum = "68182ecb449f7537db0f4d5d25917789cf41e32074a9fe47b6a0b847fe1d2032" dependencies = [ "arc-swap", "aws-credential-types", @@ -1629,7 +1629,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.9", + "generic-array 0.14.7", ] [[package]] @@ -1648,7 +1648,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" dependencies = [ - "generic-array 0.14.9", + "generic-array 0.14.7", ] [[package]] @@ -2003,7 +2003,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common 0.1.6", + "crypto-common 0.1.7", "inout 0.1.4", ] @@ -2094,9 +2094,9 @@ checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "combine" -version = "4.6.7" +version = "4.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e" dependencies = [ "bytes", "futures-core", @@ -2463,7 +2463,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array 0.14.9", + "generic-array 0.14.7", "rand_core 0.6.4", "subtle", "zeroize", @@ -2488,11 +2488,11 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ - "generic-array 0.14.9", + "generic-array 0.14.7", "typenum", ] @@ -3758,7 +3758,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "const-oid 0.9.6", - "crypto-common 0.1.6", + "crypto-common 0.1.7", "subtle", ] @@ -4021,7 +4021,7 @@ dependencies = [ "crypto-bigint 0.5.5", "digest 0.10.7", "ff 0.13.1", - "generic-array 0.14.9", + "generic-array 0.14.7", "group 0.13.0", "hkdf 0.12.4", "pem-rfc7468 0.7.0", @@ -4466,9 +4466,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -4481,7 +4481,7 @@ version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "337d46834ee672ab3e48caca2cb0c78cc174fb12b3a68d0d88f99a0519a5e36e" dependencies = [ - "generic-array 0.14.9", + "generic-array 0.14.7", "rustversion", "typenum", ] @@ -5516,7 +5516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "block-padding 0.3.3", - "generic-array 0.14.9", + "generic-array 0.14.7", ] [[package]] @@ -6762,7 +6762,7 @@ dependencies = [ "ed25519-dalek 2.2.0", "getrandom 0.2.17", "log", - "rand 0.8.7", + "rand 0.8.8", "signatory", ] @@ -6818,7 +6818,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc895af95856f929163a0aa20c26a78d26bfdc839f51b9d5aa7a5b79e52b7e83" dependencies = [ - "rand 0.8.7", + "rand 0.8.8", ] [[package]] @@ -6853,7 +6853,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.7", + "rand 0.8.8", "smallvec", "zeroize", ] @@ -6971,7 +6971,7 @@ dependencies = [ "chrono", "getrandom 0.2.17", "http 1.5.0", - "rand 0.8.7", + "rand 0.8.8", "serde", "serde_json", "serde_path_to_error", @@ -7149,7 +7149,7 @@ dependencies = [ "oauth2", "p256 0.13.2", "p384 0.13.1", - "rand 0.8.7", + "rand 0.8.8", "rsa 0.9.10", "serde", "serde-value", @@ -8144,8 +8144,8 @@ version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ - "heck 0.4.1", - "itertools 0.10.5", + "heck 0.5.0", + "itertools 0.14.0", "log", "multimap", "once_cell", @@ -8164,8 +8164,8 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042" dependencies = [ - "heck 0.4.1", - "itertools 0.10.5", + "heck 0.5.0", + "itertools 0.14.0", "log", "multimap", "petgraph 0.8.3", @@ -8186,7 +8186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.119", @@ -8199,7 +8199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.119", @@ -8283,7 +8283,7 @@ dependencies = [ "prost 0.13.5", "prost-build 0.13.5", "prost-derive 0.13.5", - "rand 0.8.7", + "rand 0.8.8", "regex", "rustls", "tokio", @@ -8560,9 +8560,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -10993,7 +10993,7 @@ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "s3s" version = "0.15.0" -source = "git+https://github.com/rustfs/s3s.git?rev=5f22e8d0a37e83f531f653024aac11c72586479a#5f22e8d0a37e83f531f653024aac11c72586479a" +source = "git+https://github.com/rustfs/s3s.git?rev=f4dedc905ec621fa85a4686df6304190b55375f6#f4dedc905ec621fa85a4686df6304190b55375f6" dependencies = [ "arc-swap", "arrayvec", @@ -11147,7 +11147,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct 0.2.0", "der 0.7.10", - "generic-array 0.14.9", + "generic-array 0.14.7", "pkcs8 0.10.2", "subtle", "zeroize", @@ -12473,7 +12473,7 @@ dependencies = [ "futures-sink", "http 1.5.0", "httparse", - "rand 0.8.7", + "rand 0.8.8", "rustls-pki-types", "tokio", "tokio-rustls", diff --git a/Cargo.toml b/Cargo.toml index 3400d9309..35b61c7fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -237,9 +237,9 @@ atoi = "3.1.0" atomic_enum = "0.3.0" aws-config = { version = "1.11.0" } aws-credential-types = { version = "1.3.0" } -aws-sdk-kms = { default-features = false, version = "1.116.0" } -aws-sdk-s3 = { default-features = false, version = "1.143.0" } -aws-sdk-sts = { default-features = false, version = "1.112.0" } +aws-sdk-kms = { default-features = false, version = "1.117.0" } +aws-sdk-s3 = { default-features = false, version = "1.144.0" } +aws-sdk-sts = { default-features = false, version = "1.113.0" } aws-smithy-http-client = { default-features = false, version = "1.4.0" } aws-smithy-runtime-api = { version = "1.15.0" } aws-smithy-types = { version = "1.6.2" } @@ -306,7 +306,7 @@ rustify = { version = "0.7", default-features = false } rustix = { version = "1.1.4" } rust-embed = { version = "8.12.0" } rustc-hash = { version = "2.1.3" } -s3s = { git = "https://github.com/rustfs/s3s.git", rev = "5f22e8d0a37e83f531f653024aac11c72586479a", version = "0.15.0", features = ["minio"] } +s3s = { git = "https://github.com/rustfs/s3s.git", rev = "f4dedc905ec621fa85a4686df6304190b55375f6", version = "0.15.0", features = ["minio"] } serial_test = "4.0.1" shadow-rs = { default-features = false, version = "2.0.0" } siphasher = "1.0.3" diff --git a/rustfs/src/app/object_usecase.rs b/rustfs/src/app/object_usecase.rs index 0f5c39bbc..804352de6 100644 --- a/rustfs/src/app/object_usecase.rs +++ b/rustfs/src/app/object_usecase.rs @@ -10373,6 +10373,17 @@ mod tests { use tokio::io::{AsyncRead, ReadBuf}; use tokio_tar::{Builder, EntryType, Header}; + #[derive(Debug)] + struct MockUploadStreamSha256Mismatch; + + impl std::fmt::Display for MockUploadStreamSha256Mismatch { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("UploadStreamError: Sha256Mismatch") + } + } + + impl std::error::Error for MockUploadStreamSha256Mismatch {} + #[tokio::test] async fn cancelled_eager_put_commit_owner_reaps_stalled_storage_task() { let health = Arc::new(ObjectTrafficHealth::enabled_for_test(Duration::ZERO)); @@ -16386,20 +16397,20 @@ mod tests { #[test] fn s3s_body_error_to_io_preserves_upload_stream_error_source() { - let error = s3s_body_error_to_io(Box::new(s3s::UploadStreamError::Sha256Mismatch)); + let error = s3s_body_error_to_io(Box::new(MockUploadStreamSha256Mismatch)); assert!(matches!( error .get_ref() - .and_then(|source| source.downcast_ref::()), - Some(s3s::UploadStreamError::Sha256Mismatch) + .and_then(|source| source.downcast_ref::()), + Some(MockUploadStreamSha256Mismatch) )); } #[tokio::test] async fn read_small_put_body_maps_upload_stream_sha256_mismatch_to_bad_digest() { let body = StreamReader::new(futures::stream::iter(vec![Err::(s3s_body_error_to_io(Box::new( - s3s::UploadStreamError::Sha256Mismatch, + MockUploadStreamSha256Mismatch, )))])); let error = read_small_put_body_exact_direct(body, 1) @@ -16411,7 +16422,7 @@ mod tests { #[tokio::test] async fn read_zero_copy_put_body_maps_upload_stream_sha256_mismatch_to_bad_digest() { - let body = futures::stream::iter(vec![Err::(s3s::UploadStreamError::Sha256Mismatch)]); + let body = futures::stream::iter(vec![Err::(MockUploadStreamSha256Mismatch)]); let error = match read_zero_copy_put_body_exact(body, 1).await { Ok(_) => panic!("SHA256 mismatch should reject the zero-copy PUT body"), diff --git a/rustfs/src/error.rs b/rustfs/src/error.rs index c033caeda..5baffe40b 100644 --- a/rustfs/src/error.rs +++ b/rustfs/src/error.rs @@ -226,7 +226,7 @@ where } fn error_chain_has_upload_stream_sha256_mismatch(err: &(dyn std::error::Error + 'static)) -> bool { - if matches!(err.downcast_ref::(), Some(s3s::UploadStreamError::Sha256Mismatch)) { + if err.to_string() == "UploadStreamError: Sha256Mismatch" { return true; } @@ -239,7 +239,7 @@ fn error_chain_has_upload_stream_sha256_mismatch(err: &(dyn std::error::Error + let mut current = err.source(); while let Some(err) = current { - if matches!(err.downcast_ref::(), Some(s3s::UploadStreamError::Sha256Mismatch)) { + if err.to_string() == "UploadStreamError: Sha256Mismatch" { return true; } current = err.source(); @@ -452,6 +452,34 @@ mod tests { use s3s::{S3Error, S3ErrorCode}; use std::io::{Error as IoError, ErrorKind}; + #[derive(Debug)] + enum MockUploadStreamError { + Underlying(IoError), + Sha256Mismatch, + LengthMismatch, + Incomplete, + } + + impl std::fmt::Display for MockUploadStreamError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Underlying(err) => write!(f, "UploadStreamError: Underlying: {err}"), + Self::Sha256Mismatch => f.write_str("UploadStreamError: Sha256Mismatch"), + Self::LengthMismatch => f.write_str("UploadStreamError: LengthMismatch"), + Self::Incomplete => f.write_str("UploadStreamError: Incomplete"), + } + } + } + + impl std::error::Error for MockUploadStreamError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Underlying(err) => Some(err), + Self::Sha256Mismatch | Self::LengthMismatch | Self::Incomplete => None, + } + } + } + #[test] fn test_api_error_from_io_error() { let io_error = IoError::new(ErrorKind::PermissionDenied, "permission denied"); @@ -515,11 +543,11 @@ mod tests { #[test] fn upload_stream_sha256_mismatch_maps_to_bad_digest() { - let api_error = ApiError::from(IoError::other(s3s::UploadStreamError::Sha256Mismatch)); + let api_error = ApiError::from(IoError::other(MockUploadStreamError::Sha256Mismatch)); assert_eq!(api_error.code, S3ErrorCode::BadDigest); assert_eq!(api_error.message, ApiError::error_code_to_message(&S3ErrorCode::BadDigest)); - let api_error = ApiError::from(StorageError::Io(IoError::other(s3s::UploadStreamError::Sha256Mismatch))); + let api_error = ApiError::from(StorageError::Io(IoError::other(MockUploadStreamError::Sha256Mismatch))); assert_eq!(api_error.code, S3ErrorCode::BadDigest); assert_eq!(api_error.message, ApiError::error_code_to_message(&S3ErrorCode::BadDigest)); } @@ -527,9 +555,9 @@ mod tests { #[test] fn other_upload_stream_errors_do_not_map_to_bad_digest() { let errors = [ - s3s::UploadStreamError::Underlying(Box::new(IoError::other("underlying body error"))), - s3s::UploadStreamError::LengthMismatch, - s3s::UploadStreamError::Incomplete, + MockUploadStreamError::Underlying(IoError::other("underlying body error")), + MockUploadStreamError::LengthMismatch, + MockUploadStreamError::Incomplete, ]; for error in errors { @@ -538,9 +566,9 @@ mod tests { } let errors = [ - s3s::UploadStreamError::Underlying(Box::new(IoError::other("underlying body error"))), - s3s::UploadStreamError::LengthMismatch, - s3s::UploadStreamError::Incomplete, + MockUploadStreamError::Underlying(IoError::other("underlying body error")), + MockUploadStreamError::LengthMismatch, + MockUploadStreamError::Incomplete, ]; for error in errors { diff --git a/rustfs/src/server/http.rs b/rustfs/src/server/http.rs index 20253d2df..b3ac5e93d 100644 --- a/rustfs/src/server/http.rs +++ b/rustfs/src/server/http.rs @@ -151,6 +151,14 @@ static HTTP_STATUS_CLASS_METRICS: std::sync::LazyLock<[HttpStatusClassMetrics; 6 std::sync::LazyLock::new(|| HTTP_STATUS_CLASS_LABELS.map(HttpStatusClassMetrics::new)); static HTTP_TRANSPORT_FAILURES_COUNTER: std::sync::LazyLock = std::sync::LazyLock::new(|| counter!(METRIC_HTTP_SERVER_FAILURES_TOTAL, LABEL_HTTP_STATUS_CLASS => "transport")); + +fn rustfs_s3_config() -> S3Config { + let mut s3_config = S3Config::default(); + s3_config.normalize_forward_slash_path = true; + s3_config.enable_sig_v2 = true; + s3_config +} + const LOG_COMPONENT_SERVER: &str = "server"; const LOG_SUBSYSTEM_HTTP: &str = "http"; const LOG_SUBSYSTEM_TRANSPORT: &str = "transport"; @@ -922,8 +930,7 @@ pub async fn start_http_server( // `PUT /bucket//foo/bar` are rejected downstream with InvalidArgument // (ObjectNamePrefixAsSlash, issue #2427). MinIO collapses these slashes instead of preserving them, // so `//foo/bar` is stored and served as `foo/bar`. - let mut s3_config = S3Config::default(); - s3_config.normalize_forward_slash_path = true; + let s3_config = rustfs_s3_config(); b.set_config(Arc::new(StaticConfigProvider::new(Arc::new(s3_config)))); // Virtual-hosted-style requests are only set up for S3 API when server domains are configured and console is disabled @@ -2257,6 +2264,14 @@ mod tests { assert_eq!(HTTP_STATUS_CLASS_LABELS[HTTP_STATUS_UNKNOWN_INDEX], "unknown"); } + #[test] + fn rustfs_s3_config_preserves_compatibility_over_s3s_defaults() { + let s3_config = rustfs_s3_config(); + + assert!(s3_config.normalize_forward_slash_path); + assert!(s3_config.enable_sig_v2); + } + #[test] #[serial_test::serial] fn cached_http_metric_handles_preserve_metric_labels() {