Make one image URL per source on the generator page for host case and an empty path (closes #293)
check / check (push) Waiting to run

The generator page put the source host and path into the encrypted URL
as entered, so CDN.Example.com and cdn.example.com, or a source URL with
no path and with the path /, made two cache keys and two upstream
requests for one image. It now parses the source URL with the host
lower-cased and an empty path written as /, as /v1/image/ reads a
source URL, before the check that pixa fetches the URL as entered. That
is a small function of its own because HandleGenerateURL is at the
linter's length limit. The README says what the token keeps.

Model: opus-5-5
This commit is contained in:
2026-10-16 01:46:26 +00:00
parent 2bedd1dd03
commit 96b32dab3e
3 changed files with 30 additions and 4 deletions
+20 -1
View File
@@ -127,7 +127,7 @@ func (s *Handlers) HandleGenerateURL() http.HandlerFunc {
sourceURL := r.FormValue("url")
// Validate source URL
parsed, err := url.Parse(sourceURL)
parsed, err := parseSourceURL(sourceURL)
if err != nil || parsed.Host == "" {
s.renderGeneratorWithForm(w, r, "Invalid source URL", r.Form,
http.StatusBadRequest)
@@ -198,6 +198,25 @@ func (s *Handlers) HandleGenerateURL() http.HandlerFunc {
}
}
// parseSourceURL parses the source URL entered on the generator page with its
// host lower-cased and an empty path written as "/", as /v1/image/ reads a
// source URL, so that each spelling of one source URL makes one cache key and
// one upstream request.
func parseSourceURL(sourceURL string) (*url.URL, error) {
parsed, err := url.Parse(sourceURL)
if err != nil {
return nil, err
}
parsed.Host = strings.ToLower(parsed.Host)
if parsed.Path == "" {
parsed.Path = "/"
}
return parsed, nil
}
// fetchedAsWritten reports whether fetchURL, the URL pixa fetches for an
// image URL made from the source URL source, is source as it was written,
// apart from the scheme, which the token does not keep. It is not when source