mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-30 00:47:13 +00:00
chore(deps): refresh s3s and dependencies (#6665)
* chore(deps): refresh s3s and related dependencies Update the RustFS s3s git dependency to the requested f4dedc905 revision and keep the resolved dependency refresh from Cargo. Co-Authored-By: heihutu <heihutu@gmail.com> * fix(api): adapt s3s upload stream error mapping Detect the s3s upload stream SHA256 mismatch through the error chain without relying on the removed crate-root re-export. Co-Authored-By: heihutu <heihutu@gmail.com> * fix(auth): preserve SigV2 S3 compatibility Keep RustFS S3 service configuration explicit after the s3s default disables SigV2. Co-Authored-By: heihutu <heihutu@gmail.com> --------- Co-authored-by: heihutu <heihutu@gmail.com>
This commit is contained in:
@@ -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::<s3s::UploadStreamError>()),
|
||||
Some(s3s::UploadStreamError::Sha256Mismatch)
|
||||
.and_then(|source| source.downcast_ref::<MockUploadStreamSha256Mismatch>()),
|
||||
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::<Bytes, std::io::Error>(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::<Bytes, s3s::UploadStreamError>(s3s::UploadStreamError::Sha256Mismatch)]);
|
||||
let body = futures::stream::iter(vec![Err::<Bytes, MockUploadStreamSha256Mismatch>(MockUploadStreamSha256Mismatch)]);
|
||||
|
||||
let error = match read_zero_copy_put_body_exact(body, 1).await {
|
||||
Ok(_) => panic!("SHA256 mismatch should reject the zero-copy PUT body"),
|
||||
|
||||
+38
-10
@@ -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::<s3s::UploadStreamError>(), 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::<s3s::UploadStreamError>(), 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 {
|
||||
|
||||
@@ -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<metrics::Counter> =
|
||||
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() {
|
||||
|
||||
Reference in New Issue
Block a user