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>
Documenting the structure of a team can be helpful to integrate newcomers, avoid some conflicts and to accompany the evolution of that structure as a FOSS project grows.
This is an attempt to do that for garage, after discussions with multiple maintainers. The aim of this text is to document the status quo, offering a start for further incremental updates.
I propose to put it as `GOVERNANCE.md` file because this naming has emerged as a sort of standard in FOSS projects.
I would be happy to help facilitate such updates if there is interest (while being aware that project members have other things on their plates and that governance work can be taxing).
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/1493
The rebalance op links to the multi-hdd page, but the multi-hdd page
does not refer to the rebalance op description and only states that an
operator can launch a repair procedure without stating which procedure.
Add a link to the rebalance repair procedure in the multi-hdd page to
make it easier to find what procedure to run for rebalance.
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/1491
save_peer_list() ran unconditionally every 60s from the discovery
loop, writing the same data to disk even when the peer set hadn't
changed. Compare the newly encoded peer list against the bytes
already on disk and skip the write when they match.
Fixes#1457
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/1488
Reviewed-by: Alex <lx@deuxfleurs.fr>
This performs synchronous repair-on-read for K2V reads:
- uses the new get_*_monotonic operations in the table module
- implements repair-on-read for the K2V-specific poll operations
`parse_duration` is no longer maintained upstream; `fundu-system` seems like the best option to provide most of the functionality provided by parse_duration and minimize deps.
Fixes#1246
Dep diffstat: +3 -6
## Caveats
- I've done basically no testing of this PR beyond `cargo test`
- See my comment in #1246 for regression risk; this is a breaking change. Is there a document I should update to make note of this? Should I rebase this for `next-v3` instead?
- In theory CVE-2021-29932 is fixed by this PR as `fundu-systemd` doesn't support exponents, but I've done no verification that this is really the case beyond the info in #1246
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/1468
Reviewed-by: Alex <lx@deuxfleurs.fr>
If the files configured in `api_token_file` or `rpc_secret_file` are not found, garage exits with no details (at least not enough) of what went wrong:
2026-06-14T23:40:34.517429Z INFO garage::server: Loading configuration from tmp/config1.toml...
Error: IO error: No such file or directory (os error 2)
This add the kind of file and the file path being read, to the returned error message:
2026-06-14T23:41:41.136213Z INFO garage::server: Loading configuration from tmp/config1.toml...
Error: Failed to read secret file /run/secrets/rpc_secret: No such file or directory (os error 2)
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/1475
Reviewed-by: Alex <lx@deuxfleurs.fr>
The OPTIONS placeholder for buckets without a resolvable global alias returns` Access-Control-Allow-Origin: *` and `Access-Control-Allow-Methods: *` but omits `Access-Control-Allow-Headers`.
Bug verified against Garage v2.2.0 with a local-aliased bucket: OPTIONS placeholder doesn't have `Access-Control-Allow-Headers`, causes the browser to reject signed PUT preflights
The current placeholder fails open for unsigned simple requests but blocks every signed request, undermining the design intent flagged in the FIXME:
```rs
// We take the permissive approach of allowing everything,
// because we don't want to prevent web apps that use
// local bucket names from making API calls.
```
Adds `Access-Control-Allow-Headers: *` so the permissive default is actually permissive for the request shapes that exist in practice.
Refs #258. Does not address the broader FIXME (CORS rule resolution for local-aliased buckets); the placeholder approach is preserved.
All tests are fine locally:
```bash
▲ ~/opensource/garage cargo test -p garage_api_common cors::
running 5 tests
test cors::tests::preflight_with_single_allowed_origin_returns_request_origin ... ok
test cors::tests::preflight_with_multiple_allowed_origins_reflects_request_origin ... ok
test cors::tests::preflight_with_wildcard_allowed_origin_returns_wildcard ... ok
test xml::cors::tests::test_deserialize_norules ... ok
test xml::cors::tests::test_deserialize ... ok
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 16 filtered out; finished in 0.00s
```
Co-authored-by: smattymatty <smattymatt@gmail.com>
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/1450
Reviewed-by: Alex <lx@deuxfleurs.fr>