fix(s3): allow UTF-8 in PostObject form field values (fix #1489) (#1492)

PostObject (presigned POST) returns `400 InvalidHeaderValue` when the upload involves a non-ASCII filename. The same key uploads fine vie PUT, as the issue #1489 noted.

The problem was that `handle_post_object` stores the form field values in an `http::HeaderMap`. values go in through `HeaderValue::from_str` but are read back with the strict `HeaderValue::to_str()` (ASCII-only) which fails on any UTF-8 value.

This is the same problem fixed in eab2b81b for `x-amz-meta-*` headers, and the fix is the same:
`std::str::from_utf8(value.as_bytes())` instead of `to_str()`. The `key` field in `post_object.rs` and the standard headers (`content-disposition` etc.) in `extract_metadata_headers`.

Added integration tests for PostObject (there were none): UTF-8 key, `${filename}` substitution, and UTF-8 `Content-Disposition` metadata. The substitution test passes even without the fix, proving that the filename path was never broken, only the form-params round-trip.

Co-authored-by: Mathew Storm <mathew@stormdevelopments.ca>
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/1492
Reviewed-by: trinity-1686a <trinity-1686a@noreply.localhost>
This commit is contained in:
smattymatty
2026-07-20 18:12:39 +00:00
committed by Alex
parent 0f89923d2d
commit 663fc5ae48
4 changed files with 177 additions and 5 deletions
+6 -4
View File
@@ -83,10 +83,12 @@ pub async fn handle_post_object(
};
// Current part is file. Do some checks before handling to PutObject code
let key = params
.get("key")
.ok_or_bad_request("No key was provided")?
.to_str()?;
let key = std::str::from_utf8(
params
.get("key")
.ok_or_bad_request("No key was provided")?
.as_bytes(),
)?;
let policy = params
.get("policy")
.ok_or_bad_request("No policy was provided")?
+4 -1
View File
@@ -679,7 +679,10 @@ pub(crate) fn extract_metadata_headers(
];
for name in standard_header.iter() {
if let Some(value) = headers.get(name) {
ret.push((name.to_string(), value.to_str()?.to_string()));
ret.push((
name.to_string(),
std::str::from_utf8(value.as_bytes())?.to_string(),
));
}
}