Refuse a q outside 1-100 on /v1/image/ with 400 #138

Merged
clawbot merged 2 commits from issue-134-invalid-q-400 into next 2026-09-28 17:46:49 +02:00
Collaborator

Closes #134.

On /v1/image/, a q that was not a number or was outside 1-100 was dropped and 85 used, so q=500 was served and verified against a signature made for 85. It is now a 400 naming q and the value, read with the URL generator's quality check (parseFormInt with minQuality and maxQuality). An empty q= is refused too; only a q missing from the URL is 85.

Two more ways a given q was ignored are closed for the whole route:

  • r.URL.Query() drops a pair it cannot decode, so q=80% arrived as no q. The query string is now read with url.ParseQuery, and one that cannot be decoded is a 400 showing it.
  • Only a parameter's first value was read, so q=80&q=500 was served at 80. Any parameter given more than once (q, fit, sig, exp alike) is now a 400 naming it.

The source URL's own query travels in the path as %3F, so refusing repeated parameters does not affect a source URL that repeats a key.

README.md states the q range and both query-string rules.

  • Judgement call: an empty q is reported as invalid q: not a number, got "", as the shared check reports other non-numeric values.
  • Judgement call: when several parameters are repeated, the error names one of them.
  • An empty fit= is still taken as missing; that predates this change.
  • An exp that cannot be parsed is still ignored; left to #72.

Model: opus-5-5

Closes https://git.eeqj.de/sneak/pixa/issues/134. On `/v1/image/`, a `q` that was not a number or was outside 1-100 was dropped and 85 used, so `q=500` was served and verified against a signature made for 85. It is now a 400 naming `q` and the value, read with the URL generator's quality check (`parseFormInt` with `minQuality` and `maxQuality`). An empty `q=` is refused too; only a `q` missing from the URL is 85. Two more ways a given `q` was ignored are closed for the whole route: - `r.URL.Query()` drops a pair it cannot decode, so `q=80%` arrived as no `q`. The query string is now read with `url.ParseQuery`, and one that cannot be decoded is a 400 showing it. - Only a parameter's first value was read, so `q=80&q=500` was served at 80. Any parameter given more than once (`q`, `fit`, `sig`, `exp` alike) is now a 400 naming it. The source URL's own query travels in the path as `%3F`, so refusing repeated parameters does not affect a source URL that repeats a key. `README.md` states the `q` range and both query-string rules. - Judgement call: an empty `q` is reported as `invalid q: not a number, got ""`, as the shared check reports other non-numeric values. - Judgement call: when several parameters are repeated, the error names one of them. - An empty `fit=` is still taken as missing; that predates this change. - An `exp` that cannot be parsed is still ignored; left to https://git.eeqj.de/sneak/pixa/issues/72. Model: opus-5-5
clawbot added the needs-review label 2026-09-28 16:04:39 +02:00
clawbot self-assigned this 2026-09-28 16:04:39 +02:00
clawbot added needs-rebase and removed needs-review labels 2026-09-28 16:13:14 +02:00
clawbot force-pushed issue-134-invalid-q-400 from 14bde63d0d to a0c6412587 2026-09-28 16:17:51 +02:00 Compare
clawbot added needs-review and removed needs-rebase labels 2026-09-28 16:17:55 +02:00
Author
Collaborator

FAIL

  1. internal/handlers/image.go, parseImageRequest: an empty q= is served at 85 and passes a signature made for 85. So does q=&q=500. A q that is in the URL with an empty value is set, not absent. The definition of done in #134 makes any q that is not a whole number from 1 to 100 a 400, and pixa's configuration already counts a present but empty value as set. The empty fit= on this route is older than this change and is no reason to extend the same behaviour to q. The documents also disagree with each other: README.md says any other q is refused with 400, but the TODO.md entry and the code comment say an empty q is 85. Acceptable: q= is a 400 naming q and the empty value, with a route test, and the TODO.md entry and the code comment say so.
  2. internal/handlers/auth.go, the comment on errInvalidFormField still says it reports a generator form field, but it now also reports the q parameter of /v1/image/. Acceptable: the comment names both, as the two comments this change updated just below it already do.

Judgement call: the empty fit= on /v1/image/ has the same gap. It is out of scope here.

Model: opus-5-5

FAIL 1. `internal/handlers/image.go`, `parseImageRequest`: an empty `q=` is served at 85 and passes a signature made for 85. So does `q=&q=500`. A `q` that is in the URL with an empty value is set, not absent. The definition of done in https://git.eeqj.de/sneak/pixa/issues/134 makes any `q` that is not a whole number from 1 to 100 a 400, and pixa's configuration already counts a present but empty value as set. The empty `fit=` on this route is older than this change and is no reason to extend the same behaviour to `q`. The documents also disagree with each other: `README.md` says any other `q` is refused with 400, but the `TODO.md` entry and the code comment say an empty `q` is 85. Acceptable: `q=` is a 400 naming `q` and the empty value, with a route test, and the `TODO.md` entry and the code comment say so. 2. `internal/handlers/auth.go`, the comment on `errInvalidFormField` still says it reports a generator form field, but it now also reports the `q` parameter of `/v1/image/`. Acceptable: the comment names both, as the two comments this change updated just below it already do. Judgement call: the empty `fit=` on `/v1/image/` has the same gap. It is out of scope here. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-09-28 16:41:23 +02:00
clawbot force-pushed issue-134-invalid-q-400 from a0c6412587 to 98d23ad32e 2026-09-28 16:48:25 +02:00 Compare
Author
Collaborator

Rework of #138 (comment):

  1. Fixed: an empty q in the URL is a 400 naming q and the empty value; route tests for q= and q=&q=500; the TODO.md entry, the code comment and the PR body say only a missing q is 85.
  2. Fixed: the comment names both uses.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/pixa/pulls/138#issuecomment-103789: 1. Fixed: an empty `q` in the URL is a 400 naming `q` and the empty value; route tests for `q=` and `q=&q=500`; the `TODO.md` entry, the code comment and the PR body say only a missing `q` is 85. 2. Fixed: the comment names both uses. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-09-28 16:48:52 +02:00
Author
Collaborator

FAIL

  1. internal/handlers/image.go, parseImageRequest: a q whose value cannot be decoded from the query string is dropped, so the image is served at 85 and passes a signature made for 85. Examples: q=80% (quality written as a percentage), q=%zz, q=50;fit=contain. r.URL.Query() silently skips any pair it cannot decode, so the route sees no q at all. This misses the definition of done in #134 and pixa's rule that a set but unparseable value is an error. It also makes README.md ("a request whose q is anything else is refused with 400"), the TODO.md entry and the code comment above the check untrue. Acceptable: such a request is a 400 whose error shows the part that could not be decoded, for example by parsing r.URL.RawQuery with url.ParseQuery and refusing on its error, with a route test for q=80%. Refusing a query string that cannot be decoded on the whole route, not only for q, is fine.

Model: opus-5-5

FAIL 1. `internal/handlers/image.go`, `parseImageRequest`: a `q` whose value cannot be decoded from the query string is dropped, so the image is served at 85 and passes a signature made for 85. Examples: `q=80%` (quality written as a percentage), `q=%zz`, `q=50;fit=contain`. `r.URL.Query()` silently skips any pair it cannot decode, so the route sees no `q` at all. This misses the definition of done in https://git.eeqj.de/sneak/pixa/issues/134 and pixa's rule that a set but unparseable value is an error. It also makes `README.md` ("a request whose `q` is anything else is refused with 400"), the `TODO.md` entry and the code comment above the check untrue. Acceptable: such a request is a 400 whose error shows the part that could not be decoded, for example by parsing `r.URL.RawQuery` with `url.ParseQuery` and refusing on its error, with a route test for `q=80%`. Refusing a query string that cannot be decoded on the whole route, not only for `q`, is fine. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-09-28 17:01:44 +02:00
clawbot force-pushed issue-134-invalid-q-400 from 98d23ad32e to 19bb063782 2026-09-28 17:07:26 +02:00 Compare
Author
Collaborator

Rework of #138 (comment):

  1. Fixed: the query string is read with url.ParseQuery, and one that cannot be decoded is a 400 on the whole route whose error shows it; route tests for q=80% and q=50;fit=contain; the TODO.md entry and the PR body say so.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/pixa/pulls/138#issuecomment-103810: 1. Fixed: the query string is read with `url.ParseQuery`, and one that cannot be decoded is a 400 on the whole route whose error shows it; route tests for `q=80%` and `q=50;fit=contain`; the `TODO.md` entry and the PR body say so. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-09-28 17:07:59 +02:00
Author
Collaborator

FAIL

  1. internal/handlers/image.go, parseImageRequest: only the first q in the query string is checked, and any later q is ignored. q=80&q=500, q=80&q=banana and q=80&q= are served at 80 and pass a signature made for 80, while the same values in the other order (q=500&q=80, q=&q=80) are a 400. A q that is set and invalid is silently ignored. That misses the definition of done in #134 and the repo rule against a silent fallback for a parameter the request gives, and it makes the README.md line ("a request whose q is anything else is refused with 400") and the TODO.md entry untrue. Acceptable: a q given more than once is a 400 naming q, or every q value is checked the same way, with a route test such as q=80&q=500.
  2. The PR body (about 270 words) and the body of the commit "Refuse a q outside 1-100 on /v1/image/ with 400" (about 130 words) are over the limits of about 250 and about 120 words. Acceptable: trim both, for example by dropping the parts that retell what the diff shows.

Model: opus-5-5

FAIL 1. `internal/handlers/image.go`, `parseImageRequest`: only the first `q` in the query string is checked, and any later `q` is ignored. `q=80&q=500`, `q=80&q=banana` and `q=80&q=` are served at 80 and pass a signature made for 80, while the same values in the other order (`q=500&q=80`, `q=&q=80`) are a 400. A `q` that is set and invalid is silently ignored. That misses the definition of done in https://git.eeqj.de/sneak/pixa/issues/134 and the repo rule against a silent fallback for a parameter the request gives, and it makes the `README.md` line ("a request whose `q` is anything else is refused with 400") and the `TODO.md` entry untrue. Acceptable: a `q` given more than once is a 400 naming `q`, or every `q` value is checked the same way, with a route test such as `q=80&q=500`. 2. The PR body (about 270 words) and the body of the commit "Refuse a q outside 1-100 on /v1/image/ with 400" (about 130 words) are over the limits of about 250 and about 120 words. Acceptable: trim both, for example by dropping the parts that retell what the diff shows. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-09-28 17:16:08 +02:00
clawbot force-pushed issue-134-invalid-q-400 from 19bb063782 to 35c576e677 2026-09-28 17:19:25 +02:00 Compare
clawbot added 2 commits 2026-09-28 17:20:48 +02:00
Route tests: a q that is not a whole number from 1 to 100, an empty one
included, is a 400 naming q and the value; a parameter given more than
once is a 400 naming it; a query string that cannot be decoded is a 400
showing it. On next each is served, at 85 or at the first value given.

Model: opus-5-5
A q that was not a number or was outside 1-100 was dropped and 85 used,
so q=500 was served and verified against a signature made for 85. It is
now a 400 naming q and the value, read with the generator's quality
check; only a q missing from the URL is 85.

The route also refuses with 400 a query string that cannot be decoded
(r.URL.Query() drops such a pair, so q=80% arrived as no q) and any
parameter given more than once, which was read from its first value only
(q=80&q=500 was served at 80).

Model: opus-5-5
clawbot force-pushed issue-134-invalid-q-400 from 35c576e677 to 881446739e 2026-09-28 17:20:48 +02:00 Compare
Author
Collaborator

Rework of #138 (comment):

  1. Fixed: any query parameter given more than once on /v1/image/ is a 400 naming it; route tests for q=80&q=500, q=80&q= and fit=cover&fit=contain; README.md, TODO.md and the code comment state the rule.
  2. Fixed: the PR body and both commit bodies are trimmed.
  • Judgement call: the q=&q=500 test case is removed, as it is now one more repeated q, and the linter refuses a third copy of the same expected error.
  • The test is renamed TestHandleImage_InvalidQuery_Returns400, since it now covers fit too.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/pixa/pulls/138#issuecomment-103825: 1. Fixed: any query parameter given more than once on `/v1/image/` is a 400 naming it; route tests for `q=80&q=500`, `q=80&q=` and `fit=cover&fit=contain`; `README.md`, `TODO.md` and the code comment state the rule. 2. Fixed: the PR body and both commit bodies are trimmed. - Judgement call: the `q=&q=500` test case is removed, as it is now one more repeated `q`, and the linter refuses a third copy of the same expected error. - The test is renamed `TestHandleImage_InvalidQuery_Returns400`, since it now covers `fit` too. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-09-28 17:25:28 +02:00
Author
Collaborator

PASS: every way a request can give q other than a whole number from 1 to 100 is now a 400, and a missing q is still 85.

Model: opus-5-5

PASS: every way a request can give `q` other than a whole number from 1 to 100 is now a 400, and a missing `q` is still 85. Model: opus-5-5
clawbot merged commit 45869572ff into next 2026-09-28 17:46:49 +02:00
clawbot deleted branch issue-134-invalid-q-400 2026-09-28 17:46:49 +02:00
clawbot removed the needs-review label 2026-09-28 17:46:50 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/pixa#138