diff --git a/crates/ecstore/src/client/signer_error.rs b/crates/ecstore/src/client/signer_error.rs index 566b49803..384e0432d 100644 --- a/crates/ecstore/src/client/signer_error.rs +++ b/crates/ecstore/src/client/signer_error.rs @@ -72,3 +72,34 @@ pub(crate) fn error_chain_contains_signer_header_marker(err: &(dyn StdError + 's false } + +#[cfg(test)] +mod tests { + use super::{error_chain_contains_signer_header_marker, invalid_utf8_header_error, signer_error_to_io_error}; + + #[test] + fn invalid_utf8_header_error_is_detected_through_error_chain() { + let err = invalid_utf8_header_error("failed to sign request", "x-amz-meta-invalid"); + + assert!(error_chain_contains_signer_header_marker(&err)); + } + + #[test] + fn mapped_signer_header_error_is_detected_through_error_chain() { + let err = signer_error_to_io_error( + "failed to sign request", + rustfs_signer::SignV4Error::InvalidHeaderValue { + name: "x-amz-meta-invalid".to_string(), + }, + ); + + assert!(error_chain_contains_signer_header_marker(&err)); + } + + #[test] + fn generic_io_errors_do_not_match_signer_header_marker() { + let err = std::io::Error::other("unrelated failure"); + + assert!(!error_chain_contains_signer_header_marker(&err)); + } +} diff --git a/crates/signer/src/utils.rs b/crates/signer/src/utils.rs index 900fd003e..7a8710d83 100644 --- a/crates/signer/src/utils.rs +++ b/crates/signer/src/utils.rs @@ -60,3 +60,56 @@ where { v.sort_by(|lhs, rhs| lhs.0.cmp(&rhs.0)); } + +#[cfg(test)] +mod tests { + use super::{HostAddrError, try_get_host_addr}; + use http::HeaderValue; + use http::request; + use s3s::Body; + + #[test] + fn try_get_host_addr_prefers_explicit_host_header_when_it_differs_from_uri() { + let mut req = request::Request::builder() + .method(http::Method::GET) + .uri("https://bucket.example.com/object") + .body(Body::empty()) + .expect("request should build"); + req.headers_mut() + .insert("host", HeaderValue::from_static("proxy.internal:9443")); + + let host = try_get_host_addr(&req).expect("host lookup should succeed"); + + assert_eq!(host, "proxy.internal:9443"); + } + + #[test] + fn try_get_host_addr_rejects_non_utf8_host_header_value() { + let mut req = request::Request::builder() + .method(http::Method::GET) + .uri("https://bucket.example.com/object") + .body(Body::empty()) + .expect("request should build"); + req.headers_mut().insert( + "host", + HeaderValue::from_bytes(&[0xFF]).expect("invalid utf8 bytes should be accepted by HeaderValue"), + ); + + let err = try_get_host_addr(&req).expect_err("invalid host header should fail"); + + assert!(matches!(err, HostAddrError::InvalidHostHeader)); + } + + #[test] + fn try_get_host_addr_rejects_relative_uri_without_host() { + let req = request::Request::builder() + .method(http::Method::GET) + .uri("/object") + .body(Body::empty()) + .expect("request should build"); + + let err = try_get_host_addr(&req).expect_err("relative uri should fail"); + + assert!(matches!(err, HostAddrError::MissingUriHost)); + } +}