S3 read path (handlers/mod.rs):
- Add Last-Modified + x-amz-meta-* to Range 206 responses
- Add x-amz-server-side-encryption to HEAD/?partNumber= responses
- 304 Not Modified now carries ETag, Last-Modified, version-id, cache headers
- Treat If-Match/If-Unmodified-Since and If-None-Match/If-Modified-Since
as RFC-9110 pairs on both GET and CopyObject (date header ignored when
ETag header is present)
Website hosting (middleware/auth.rs):
- Add ETag, Last-Modified, x-amz-server-side-encryption, and x-amz-meta-*
to website HEAD/200/206 responses so CDN cachers can revalidate
Replication (services/replication.rs, services/s3_client.rs,
middleware/auth.rs, services/site_registry.rs):
- Detect replicated incoming writes via the authenticated principal's
access key against the site registry's peer_inbound_access_key set.
The auth middleware inserts a ReplicationPeerRequest extension marker
on matched requests; handlers skip trigger_replication when set.
Replaces a forgeable User-Agent substring check.
- Replication retry preflight now probes HeadBucket on the actual target
bucket (not ListBuckets) and treats any HTTP response as reachable, so
bucket-scoped credentials no longer block valid retries
- Populate ReplicationFailure.last_error_code from SdkError metadata
- Health probes use a max_attempts=1 client (fast-fail) rather than the
production retry budget
The sites.html edit modal reads peer_inbound_access_key from the row's
data attribute, but the peers JSON built by sites_dashboard omitted the
field, so every edit cleared an existing key. Add the field to the JSON
so the modal renders the stored value and preserves it on save.
- Implement missing /ui/buckets/{bucket}/objects/search route used by the
Objects tab filter; previously returned 404 and showed 'Search failed'.
- Filter __checksum_*__ and __size__ sentinels from the object metadata
panel so users no longer see internal keys in the UI.
- Include a body field in bucket-delete flash message so the toast shows
distinct title and body.
- Replace Tera boolean 'or' operator with if/else fallback in
replication_wizard.html, sites.html, iam.html.
- Shallow listing: read per-directory _index.json once for eTags instead
of N serial .meta.json reads. Validate prefix for path traversal and
verify normalized target stays within bucket root.
- Recursive listing: cache full per-directory index during the walk so
each _index.json is parsed at most once per call.
- Per-bucket listing cache with 5s TTL and per-bucket rebuild mutex.
Invalidated on put/delete/copy/metadata/tags/multipart-complete.
Pagination uses partition_point for O(log n) start lookup.
- UI stream endpoint now actually streams via mpsc + Body::from_stream
instead of buffering into a Vec<String>. Cancels producer on client
disconnect.
- UI JSON endpoint honors delimiter=/ and returns common_prefixes.
- run_blocking wrapper dispatches sync filesystem work via
block_in_place on multi-threaded runtimes, falls back to inline on
current-thread runtimes (unit tests).