Fetch the source path and query URL-encoded, not joined as text (closes #288)

The source path, decoded, is fetched percent-encoded again by net/url,
so 100%25.png fetches /100%25.png, and my%20cat.png and my%2520cat.png
fetch different paths. The source query stays as the source URL writes
it; the characters a browser percent-encodes in a query, such as a
space, are percent-encoded when the image URL is read, so the query is
signed and cached as it is sent. The generator page answers 400 for a
source URL its image URL would fetch written another way, such as with
%2F in the path, and shows the URL pixa would fetch. README.md says how
the source path and query are fetched.

Model: opus-5-5
This commit is contained in:
2026-10-16 00:47:13 +00:00
parent af5ce499b9
commit 545507e9d4
5 changed files with 94 additions and 16 deletions
+16
View File
@@ -141,6 +141,22 @@ func (s *Handlers) HandleGenerateURL() http.HandlerFunc {
return
}
// The image URL must fetch the source URL as it was written. The
// token keeps the path decoded and pixa fetches it percent-encoded
// again, so a path written another way, such as with %2F, would fetch
// another URL. The scheme is not kept: only path and query are compared
sourceRequest := payload.ToImageRequest()
sourceRequest.AllowHTTP = s.config.AllowHTTP
fetchURL, err := url.Parse(sourceRequest.SourceURL())
if err != nil || fetchURL.RequestURI() != parsed.RequestURI() {
s.renderGeneratorWithForm(w, r, "Source URL cannot be fetched as "+
"written: pixa would fetch "+sourceRequest.SourceURL(),
r.Form, http.StatusBadRequest)
return
}
// Generate encrypted token
token, err := s.encGen.Generate(payload)
if err != nil {