Limit each client's requests to the image routes (closes #236) #237

Open
clawbot wants to merge 1 commits from issue-236-image-rate-limit into next
Collaborator

Closes #236.

Adds image_requests_per_minute (PIXA_IMAGE_REQUESTS_PER_MINUTE), default 600: how many GET and HEAD requests one client may send to /v1/image/ and /v1/e/ together per minute, cache hits included. The next one is answered 429 with Retry-After. 0 turns the limit off; a negative or non-integer value stops startup. Before this, one client could keep every processing slot busy, and other clients' cache misses waited behind it until their downstream_timeout ended.

The limit is the login limit's RateLimit middleware, so clients are told apart the same way (trusted_proxies, an IPv6 client by its /64). It sits in the image routes' group inside /v1, after the CORS middleware, which answers a preflight itself, so a preflight is never counted. With 0 the middleware is not added at all.

What a reader may trip over:

  • Behind a CDN or proxy whose addresses are not in trusted_proxies, every request counts as one client, so such a deployment starts getting 429s past 600 requests a minute after upgrading. README.md and config.example.yml say to raise the limit or set 0 there.
  • newTestServer leaves the field at 0, so the existing server tests run with the limit off; the new tests set it and call SetupRoutes again.

Disclosures:

  • TestEnvironmentSetsEveryKey gains the new variable and its value, under the standing approval in #64.
  • validate() would have reached cyclop complexity 16 and newFromSmartConfig funlen 82 lines: the sentry_dsn check moves unchanged into validateSentryDSN, and the cache_max_bytes explicit flag is assigned in one line.

Model: opus-5-5

Closes https://git.eeqj.de/sneak/pixa/issues/236. Adds `image_requests_per_minute` (`PIXA_IMAGE_REQUESTS_PER_MINUTE`), default 600: how many `GET` and `HEAD` requests one client may send to `/v1/image/` and `/v1/e/` together per minute, cache hits included. The next one is answered 429 with `Retry-After`. `0` turns the limit off; a negative or non-integer value stops startup. Before this, one client could keep every processing slot busy, and other clients' cache misses waited behind it until their `downstream_timeout` ended. The limit is the login limit's `RateLimit` middleware, so clients are told apart the same way (`trusted_proxies`, an IPv6 client by its /64). It sits in the image routes' group inside `/v1`, after the CORS middleware, which answers a preflight itself, so a preflight is never counted. With `0` the middleware is not added at all. What a reader may trip over: - Behind a CDN or proxy whose addresses are not in `trusted_proxies`, every request counts as one client, so such a deployment starts getting 429s past 600 requests a minute after upgrading. `README.md` and `config.example.yml` say to raise the limit or set `0` there. - `newTestServer` leaves the field at 0, so the existing server tests run with the limit off; the new tests set it and call `SetupRoutes` again. Disclosures: - `TestEnvironmentSetsEveryKey` gains the new variable and its value, under the standing approval in https://git.eeqj.de/sneak/pixa/issues/64. - `validate()` would have reached cyclop complexity 16 and `newFromSmartConfig` funlen 82 lines: the `sentry_dsn` check moves unchanged into `validateSentryDSN`, and the `cache_max_bytes` explicit flag is assigned in one line. Model: opus-5-5
clawbot added the needs-review label 2026-10-12 11:24:16 +02:00
clawbot self-assigned this 2026-10-12 11:24:16 +02:00
clawbot added 1 commit 2026-10-12 11:24:16 +02:00
The new setting image_requests_per_minute (PIXA_IMAGE_REQUESTS_PER_MINUTE),
default 600, caps the GET and HEAD requests one client sends to /v1/image/
and /v1/e/ per minute; the next is answered 429 with Retry-After. It uses
the login limit's RateLimit middleware, so clients are told apart the same
way, and sits in the image routes' group behind the CORS middleware, so a
preflight is not counted. 0 turns it off; a negative or non-integer value
stops startup.

TestEnvironmentSetsEveryKey gains the new variable, under the owner's
standing approval in #64. To stay
within the linters' limits, the sentry_dsn check moves unchanged into
validateSentryDSN, and the cache_max_bytes explicit flag is set in one
line.

Model: opus-5-5
Some checks are pending
check / check (push) Waiting to run
You are not authorized to merge this pull request.
This pull request can be merged automatically.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin issue-236-image-rate-limit:issue-236-image-rate-limit
git checkout issue-236-image-rate-limit
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/pixa#237