Serve resized images without redirects #3

Merged
waylon merged 1 commit from codex/direct-public-image-response into main 2026-10-11 12:20:57 -05:00
Owner

Summary

Serve resize-only requests for original images directly from the existing derivative FileResponse. The response keeps the same public immutable cache headers, ETag, content type, and HEAD behavior. Existing derivative filenames and video resize redirects remain unchanged.

Root cause

The deployed 0.0.72 image redirects /file/{filename}?w=... to the cached derivative filename with HTTP 307 and Cache-Control: no-store. The redirect is generated by Dropper in _get_file_response; Cloudflare reports BYPASS for that response. The derivative path returns HTTP 200 with the existing one-year public cache policy and was observed as a Cloudflare HIT. The homelab manifest pins three replicas of registry.wayl.one/dropper:0.0.72, shared /data, per-pod /cache, MinIO storage, and a 120-request image transform limit.

Why direct response

A stable derivative URL requires consumers to learn or construct derivative names. An edge rewrite would require Cloudflare configuration and would still need a cacheable origin response for the query URL. Direct response preserves current consumer URLs and allows Cloudflare to cache the requested URL after its first miss. It uses the existing derivative and response path; it does not add image work per cache hit.

Validation

  • uv run pytest -q: passed.
  • uv run ruff check dropper: passed.
  • uv run ruff format --check dropper/api/routes.py tests/test_hardening.py tests/test_upload_response_formats.py: passed.
  • Local baseline vs patch, same app and local image: baseline warm requests used 2 HTTP requests (307 + derivative), median 10.20 ms, p95 18.58 ms (40 samples); patched requests used 1 HTTP request, median 5.84 ms, p95 11.91 ms (40 samples).
  • With 100 ms artificial delay per HTTP request (8 samples), median was 213.82 ms baseline vs 109.27 ms patched. This is a local request-delay simulation, not a Cloudflare or real Slow 3G benchmark.
  • Production read-only probe confirmed the current response chain and a warm derivative HIT. No cold production derivative was requested.

Rollout and rollback

After review, build and test a candidate image in Dropper dev and verify a public GET and HEAD resize request return one 200 with a cacheable response. Confirm warm query URLs report Cloudflare HIT and that private/auth support files remain inaccessible. Promote the image by the normal homelab GitOps review only after approval. Roll back by restoring the prior image pin; no storage migration or derivative cleanup is required.

Production GitOps pins and workloads are unchanged by this PR.

  • Local concurrent smoke, 10 requests: same derivative completed all requests with 20 HTTP transactions on baseline vs 10 patched; 10 distinct dimensions likewise used 20 vs 10 transactions. All returned HTTP 200. This used one local worker and does not measure cross-pod transform races.
  • ETag is present on the direct response. Starlette currently returns 200 with the body for a matching If-None-Match; that pre-existing validator behavior was not changed. Long-lived edge caching is expected to avoid routine conditional origin requests.
## Summary Serve resize-only requests for original images directly from the existing derivative `FileResponse`. The response keeps the same public immutable cache headers, ETag, content type, and HEAD behavior. Existing derivative filenames and video resize redirects remain unchanged. ## Root cause The deployed `0.0.72` image redirects `/file/{filename}?w=...` to the cached derivative filename with HTTP 307 and `Cache-Control: no-store`. The redirect is generated by Dropper in `_get_file_response`; Cloudflare reports `BYPASS` for that response. The derivative path returns HTTP 200 with the existing one-year public cache policy and was observed as a Cloudflare HIT. The homelab manifest pins three replicas of `registry.wayl.one/dropper:0.0.72`, shared `/data`, per-pod `/cache`, MinIO storage, and a 120-request image transform limit. ## Why direct response A stable derivative URL requires consumers to learn or construct derivative names. An edge rewrite would require Cloudflare configuration and would still need a cacheable origin response for the query URL. Direct response preserves current consumer URLs and allows Cloudflare to cache the requested URL after its first miss. It uses the existing derivative and response path; it does not add image work per cache hit. ## Validation - `uv run pytest -q`: passed. - `uv run ruff check dropper`: passed. - `uv run ruff format --check dropper/api/routes.py tests/test_hardening.py tests/test_upload_response_formats.py`: passed. - Local baseline vs patch, same app and local image: baseline warm requests used 2 HTTP requests (307 + derivative), median 10.20 ms, p95 18.58 ms (40 samples); patched requests used 1 HTTP request, median 5.84 ms, p95 11.91 ms (40 samples). - With 100 ms artificial delay per HTTP request (8 samples), median was 213.82 ms baseline vs 109.27 ms patched. This is a local request-delay simulation, not a Cloudflare or real Slow 3G benchmark. - Production read-only probe confirmed the current response chain and a warm derivative HIT. No cold production derivative was requested. ## Rollout and rollback After review, build and test a candidate image in Dropper dev and verify a public `GET` and `HEAD` resize request return one `200` with a cacheable response. Confirm warm query URLs report Cloudflare HIT and that private/auth support files remain inaccessible. Promote the image by the normal homelab GitOps review only after approval. Roll back by restoring the prior image pin; no storage migration or derivative cleanup is required. Production GitOps pins and workloads are unchanged by this PR. - Local concurrent smoke, 10 requests: same derivative completed all requests with 20 HTTP transactions on baseline vs 10 patched; 10 distinct dimensions likewise used 20 vs 10 transactions. All returned HTTP 200. This used one local worker and does not measure cross-pod transform races. - `ETag` is present on the direct response. Starlette currently returns 200 with the body for a matching `If-None-Match`; that pre-existing validator behavior was not changed. Long-lived edge caching is expected to avoid routine conditional origin requests.
waylon merged commit 2175f8ab6d into main 2026-10-11 12:20:57 -05:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
waylon/dropper!3
No description provided.