Where: internal/handlers/auth.go, HandleGenerateURL, on next after #289. Found by the review of #289.
What is wrong: the generator page passes the source host and path into the encrypted URL as entered. https://cdn.example.com and https://cdn.example.com/ make two cache keys for the same upstream request of /, and hosts that differ only in letter case (CDN.Example.com and cdn.example.com) make separate cache keys too, because the generator does not lower-case the host the way /v1/image/ does since #246.
How it fails: a logged-in user who makes image URLs for the same image spelled two ways gets the image fetched and stored twice. Only logged-in users reach the page.
Severity: low
Definition of done:
The generator page lower-cases the source host and writes an empty source path as /, so each of those spellings makes one image URL with one cache key and one upstream request.
Router tests first, against a test upstream that records each request; make check green.
Package: internal/handlers.
Model: opus-5-5
Where: `internal/handlers/auth.go`, `HandleGenerateURL`, on `next` after https://git.eeqj.de/sneak/pixa/pulls/289. Found by the review of https://git.eeqj.de/sneak/pixa/pulls/289.
What is wrong: the generator page passes the source host and path into the encrypted URL as entered. `https://cdn.example.com` and `https://cdn.example.com/` make two cache keys for the same upstream request of `/`, and hosts that differ only in letter case (`CDN.Example.com` and `cdn.example.com`) make separate cache keys too, because the generator does not lower-case the host the way `/v1/image/` does since https://git.eeqj.de/sneak/pixa/issues/246.
How it fails: a logged-in user who makes image URLs for the same image spelled two ways gets the image fetched and stored twice. Only logged-in users reach the page.
Severity: low
Definition of done:
1. The generator page lower-cases the source host and writes an empty source path as `/`, so each of those spellings makes one image URL with one cache key and one upstream request.
2. Router tests first, against a test upstream that records each request; `make check` green.
Package: `internal/handlers`.
Model: opus-5-5
clawbot
self-assigned this 2026-10-16 03:31:25 +02:00
Plan: in HandleGenerateURL, before the encrypted URL is built, the generator page lower-cases the source host, as /v1/image/ has done since #246, and writes an empty source path as /, as /v1/image/ does. The check from #289 then compares the fetched URL with the source URL after these two changes, so https://cdn.example.com?x=1 still makes an image URL.
Tests come first, in the existing router test file internal/server/source_url_internal_test.go, against its test upstream that records each request. Each pair of spellings is entered on the generator page, both image URLs are requested, and the upstream must receive one request:
https://192.0.2.10 and https://192.0.2.10/
for host case, an IPv6 address written in upper and in lower case, such as [2001:DB8::10] and [2001:db8::10]. A host name such as CDN.Example.com would need a DNS lookup, which the fetcher makes before it connects, so the test cannot use one.
No existing test changes.
Model: opus-5-5
Plan: in `HandleGenerateURL`, before the encrypted URL is built, the generator page lower-cases the source host, as `/v1/image/` has done since https://git.eeqj.de/sneak/pixa/issues/246, and writes an empty source path as `/`, as `/v1/image/` does. The check from https://git.eeqj.de/sneak/pixa/pulls/289 then compares the fetched URL with the source URL after these two changes, so `https://cdn.example.com?x=1` still makes an image URL.
Tests come first, in the existing router test file `internal/server/source_url_internal_test.go`, against its test upstream that records each request. Each pair of spellings is entered on the generator page, both image URLs are requested, and the upstream must receive one request:
- `https://192.0.2.10` and `https://192.0.2.10/`
- for host case, an IPv6 address written in upper and in lower case, such as `[2001:DB8::10]` and `[2001:db8::10]`. A host name such as `CDN.Example.com` would need a DNS lookup, which the fetcher makes before it connects, so the test cannot use one.
No existing test changes.
Model: opus-5-5
Built as planned in #294. Two differences from the plan: the two changes sit in a small function that parses the source URL, because HandleGenerateURL was already at the linter's length limit; and the IPv6 address in the test has a port, because the fetcher refuses an IPv6 address written without one. That refusal is outside this issue and is not fixed in the PR.
Model: opus-5-5
Built as planned in https://git.eeqj.de/sneak/pixa/pulls/294. Two differences from the plan: the two changes sit in a small function that parses the source URL, because `HandleGenerateURL` was already at the linter's length limit; and the IPv6 address in the test has a port, because the fetcher refuses an IPv6 address written without one. That refusal is outside this issue and is not fixed in the PR.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Where:
internal/handlers/auth.go,HandleGenerateURL, onnextafter #289. Found by the review of #289.What is wrong: the generator page passes the source host and path into the encrypted URL as entered.
https://cdn.example.comandhttps://cdn.example.com/make two cache keys for the same upstream request of/, and hosts that differ only in letter case (CDN.Example.comandcdn.example.com) make separate cache keys too, because the generator does not lower-case the host the way/v1/image/does since #246.How it fails: a logged-in user who makes image URLs for the same image spelled two ways gets the image fetched and stored twice. Only logged-in users reach the page.
Severity: low
Definition of done:
/, so each of those spellings makes one image URL with one cache key and one upstream request.make checkgreen.Package:
internal/handlers.Model: opus-5-5
Plan: in
HandleGenerateURL, before the encrypted URL is built, the generator page lower-cases the source host, as/v1/image/has done since #246, and writes an empty source path as/, as/v1/image/does. The check from #289 then compares the fetched URL with the source URL after these two changes, sohttps://cdn.example.com?x=1still makes an image URL.Tests come first, in the existing router test file
internal/server/source_url_internal_test.go, against its test upstream that records each request. Each pair of spellings is entered on the generator page, both image URLs are requested, and the upstream must receive one request:https://192.0.2.10andhttps://192.0.2.10/[2001:DB8::10]and[2001:db8::10]. A host name such asCDN.Example.comwould need a DNS lookup, which the fetcher makes before it connects, so the test cannot use one.No existing test changes.
Model: opus-5-5
Built as planned in #294. Two differences from the plan: the two changes sit in a small function that parses the source URL, because
HandleGenerateURLwas already at the linter's length limit; and the IPv6 address in the test has a port, because the fetcher refuses an IPv6 address written without one. That refusal is outside this issue and is not fixed in the PR.Model: opus-5-5