Fetch the source path and query URL-encoded, not joined as text (closes #288)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
The source URL was built by joining the decoded path and query as text, so a space in the query reached the upstream raw and failed with 502, 100%25.png made a URL Go could not parse and answered 401, and %20 and %2520 fetched the same path under different cache keys. The source URL is now built with net/url, so each decoded path and query is one upstream request matching its signature and cache key; the query encodes the characters a browser encodes, ' included. The generator page compares what pixa would fetch with the URL as entered, and answers 400 with the URL to use when they differ, or for a user name and password or a .. segment. Model: opus-5-5
This commit was merged in pull request #289.
This commit is contained in:
@@ -51,6 +51,13 @@ var sizeFormatRegex = regexp.MustCompile(
|
||||
// percentEscapeRegex matches one percent-escape, such as "%2e"
|
||||
var percentEscapeRegex = regexp.MustCompile(`%[0-9A-Fa-f]{2}`)
|
||||
|
||||
// queryEscapeRegex matches a percent-escape, or one character that a browser
|
||||
// percent-encodes in the query of an http or https URL: one outside the
|
||||
// printable ASCII characters "!" to "~", such as a space, a control character
|
||||
// or a character outside ASCII, or one of `"#'<>`. A "%" that does not begin a
|
||||
// percent-escape matches too.
|
||||
var queryEscapeRegex = regexp.MustCompile(`%[0-9A-Fa-f]{2}|[^!-~]|["#'<>%]`)
|
||||
|
||||
// hostRegex matches the forms the host of an image URL may take: a host name
|
||||
// or an IPv4 address (letters, digits, "-", "_" and "."), or an IPv6 address
|
||||
// in brackets (hex digits, ":" and "."), either one optionally followed by ":"
|
||||
@@ -179,9 +186,12 @@ func parseImageComponents(remainder string) (*ParsedURL, error) {
|
||||
`%w: the source path or query holds a "#"`, ErrInvalidPath)
|
||||
}
|
||||
|
||||
// Extract query string if present in path
|
||||
// Extract query string if present in path. It is the source URL's query
|
||||
// as that URL writes it. A character a URL's query cannot hold as it is,
|
||||
// such as a space written %20 in the image URL, is percent-encoded here,
|
||||
// so the query is signed and cached as it is sent upstream
|
||||
if qIndex := strings.Index(path, "?"); qIndex != -1 {
|
||||
query = path[qIndex+1:]
|
||||
query = escapeQuery(path[qIndex+1:])
|
||||
path = path[:qIndex]
|
||||
}
|
||||
|
||||
@@ -270,6 +280,20 @@ func decodePercentEscapes(s string) string {
|
||||
})
|
||||
}
|
||||
|
||||
// escapeQuery returns a source query as a URL's query holds it: each
|
||||
// character that queryEscapeRegex names, such as a space, percent-encoded,
|
||||
// and the rest, the query's percent-escapes included, kept as they are. The
|
||||
// result is unchanged by a second escapeQuery.
|
||||
func escapeQuery(query string) string {
|
||||
return queryEscapeRegex.ReplaceAllStringFunc(query, func(match string) string {
|
||||
if percentEscapeRegex.MatchString(match) {
|
||||
return match
|
||||
}
|
||||
|
||||
return url.PathEscape(match)
|
||||
})
|
||||
}
|
||||
|
||||
// parseSizeFormat parses strings like "800x600.webp", "orig.png" or "800x600"
|
||||
func parseSizeFormat(s string) (Size, ImageFormat, error) {
|
||||
matches := sizeFormatRegex.FindStringSubmatch(s)
|
||||
|
||||
Reference in New Issue
Block a user