mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-27 15:37:02 +00:00
fix(tiering): support UTF-8 metadata signing (#4969)
Co-authored-by: Zhengchao An <anzhengchao@gmail.com>
This commit is contained in:
@@ -148,11 +148,15 @@ fn try_get_canonical_headers(req: &request::Request<Body>, ignored_headers: &Has
|
||||
.get_all(k)
|
||||
.iter()
|
||||
.map(|e| {
|
||||
e.to_str()
|
||||
.map(|v| v.to_string())
|
||||
.map_err(|_| SignV4Error::InvalidHeaderValue {
|
||||
let value = std::str::from_utf8(e.as_bytes()).map_err(|_| SignV4Error::InvalidHeaderValue {
|
||||
name: k.as_str().to_lowercase(),
|
||||
})?;
|
||||
if value.chars().any(|ch| !ch.is_ascii() && ch.is_whitespace()) {
|
||||
return Err(SignV4Error::InvalidHeaderValue {
|
||||
name: k.as_str().to_lowercase(),
|
||||
})
|
||||
});
|
||||
}
|
||||
Ok(value.to_string())
|
||||
})
|
||||
.collect::<SignResult<Vec<String>>>()?;
|
||||
vals.insert(k.as_str().to_lowercase(), vv);
|
||||
@@ -1129,6 +1133,51 @@ mod tests {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_sign_v4_accepts_utf8_header_value() {
|
||||
let mut req = request::Request::builder()
|
||||
.method(http::Method::PUT)
|
||||
.uri("http://examplebucket.s3.amazonaws.com/object")
|
||||
.body(Body::empty())
|
||||
.expect("request should build");
|
||||
let headers = req.headers_mut();
|
||||
headers.insert("host", HeaderValue::from_static("examplebucket.s3.amazonaws.com"));
|
||||
headers.insert("x-amz-content-sha256", HeaderValue::from_static(UNSIGNED_PAYLOAD));
|
||||
headers.insert(
|
||||
"x-amz-meta-name",
|
||||
HeaderValue::from_bytes("20260715/鲁A12345/object".as_bytes()).expect("valid utf8 metadata header"),
|
||||
);
|
||||
|
||||
let signed =
|
||||
try_sign_v4(req, 0, "rustfsadmin", "rustfsadmin", "", "us-east-1").expect("valid utf8 metadata should be signed");
|
||||
|
||||
assert!(signed.headers().contains_key(http::header::AUTHORIZATION));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_sign_v4_rejects_non_ascii_whitespace_header_value() {
|
||||
let mut req = request::Request::builder()
|
||||
.method(http::Method::PUT)
|
||||
.uri("http://examplebucket.s3.amazonaws.com/object")
|
||||
.body(Body::empty())
|
||||
.expect("request should build");
|
||||
let headers = req.headers_mut();
|
||||
headers.insert("host", HeaderValue::from_static("examplebucket.s3.amazonaws.com"));
|
||||
headers.insert("x-amz-content-sha256", HeaderValue::from_static(UNSIGNED_PAYLOAD));
|
||||
headers.insert(
|
||||
"x-amz-meta-name",
|
||||
HeaderValue::from_bytes("tier/a\u{00a0}b/object".as_bytes()).expect("valid utf8 metadata header"),
|
||||
);
|
||||
|
||||
let err = try_sign_v4(req, 0, "rustfsadmin", "rustfsadmin", "", "us-east-1")
|
||||
.expect_err("non-ascii whitespace must not be normalized differently from the wire value");
|
||||
|
||||
assert!(matches!(
|
||||
err,
|
||||
SignV4Error::InvalidHeaderValue { name } if name == "x-amz-meta-name"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_sign_v4_returns_invalid_uri_error_when_uri_has_no_host() {
|
||||
let mut req = request::Request::builder()
|
||||
|
||||
Reference in New Issue
Block a user