Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35c576e677 | ||
|
|
2dff1b5515 |
@@ -94,6 +94,9 @@ In-process caching of request-to-output mappings targets 1-5k r/s.
|
|||||||
|
|
||||||
Images are only fetched from origins using TLS with valid certificates.
|
Images are only fetched from origins using TLS with valid certificates.
|
||||||
|
|
||||||
|
A request whose query string cannot be decoded, or gives any parameter more
|
||||||
|
than once, is refused with 400.
|
||||||
|
|
||||||
- `<format>`: one of `orig`, `png`, `jpeg`, `webp`
|
- `<format>`: one of `orig`, `png`, `jpeg`, `webp`
|
||||||
- `<size>`: `orig` or `<width>x<height>` (e.g. `800x600`)
|
- `<size>`: `orig` or `<width>x<height>` (e.g. `800x600`)
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,10 @@ exhaustion
|
|||||||
85; the route reads `q` with the generator's quality check
|
85; the route reads `q` with the generator's quality check
|
||||||
(`parseFormInt` with `minQuality` and `maxQuality`); only a `q` missing
|
(`parseFormInt` with `minQuality` and `maxQuality`); only a `q` missing
|
||||||
from the URL is still 85; a query string that cannot be decoded, such
|
from the URL is still 85; a query string that cannot be decoded, such
|
||||||
as `q=80%`, is a 400 showing it; `README.md` states the range.
|
as `q=80%`, is a 400 showing it; any query parameter given more than
|
||||||
|
once (`q`, `fit`, `sig`, `exp` alike) is a 400 naming it, so none is
|
||||||
|
read from its first value only; `README.md` states the range and both
|
||||||
|
query-string rules.
|
||||||
- 2026-09-28 unknown `PIXA_` environment variables abort startup (closes
|
- 2026-09-28 unknown `PIXA_` environment variables abort startup (closes
|
||||||
#133): a variable whose name starts with `PIXA_` but is neither a
|
#133): a variable whose name starts with `PIXA_` but is neither a
|
||||||
setting's variable nor `PIXA_CONFIG_PATH` aborts startup naming it, as
|
setting's variable nor `PIXA_CONFIG_PATH` aborts startup naming it, as
|
||||||
|
|||||||
@@ -293,12 +293,13 @@ func TestHandleImage_InvalidFitMode_Returns400(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestHandleImage_InvalidQuality_Returns400 verifies that the plain image
|
// TestHandleImage_InvalidQuery_Returns400 verifies that the plain image route
|
||||||
// route answers a q that is not a whole number from 1 to 100, an empty one
|
// answers a q that is not a whole number from 1 to 100, an empty one
|
||||||
// included, with 400 naming q and the value, and a query string that cannot
|
// included, with 400 naming q and the value, a parameter given more than once
|
||||||
// be decoded with 400 showing it, instead of serving the image at the default
|
// with 400 naming it, and a query string that cannot be decoded with 400
|
||||||
// quality 85.
|
// showing it, instead of serving the image at the default quality 85 or at
|
||||||
func TestHandleImage_InvalidQuality_Returns400(t *testing.T) {
|
// the first value given.
|
||||||
|
func TestHandleImage_InvalidQuery_Returns400(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@@ -308,7 +309,10 @@ func TestHandleImage_InvalidQuality_Returns400(t *testing.T) {
|
|||||||
{"q=0", `invalid q: must be from 1 to 100, got "0"`},
|
{"q=0", `invalid q: must be from 1 to 100, got "0"`},
|
||||||
{"q=101", `invalid q: must be from 1 to 100, got "101"`},
|
{"q=101", `invalid q: must be from 1 to 100, got "101"`},
|
||||||
{"q=", `invalid q: not a number, got ""`},
|
{"q=", `invalid q: not a number, got ""`},
|
||||||
{"q=&q=500", `invalid q: not a number, got ""`},
|
{"q=&q=500", `invalid q: given more than once`},
|
||||||
|
{"q=80&q=500", `invalid q: given more than once`},
|
||||||
|
{"q=80&q=", `invalid q: given more than once`},
|
||||||
|
{"fit=cover&fit=contain", `invalid fit: given more than once`},
|
||||||
{"q=80%", `invalid query string "q=80%": invalid URL escape "%"`},
|
{"q=80%", `invalid query string "q=80%": invalid URL escape "%"`},
|
||||||
{
|
{
|
||||||
"q=50;fit=contain",
|
"q=50;fit=contain",
|
||||||
|
|||||||
@@ -94,7 +94,9 @@ func (s *Handlers) parseImageRequest(
|
|||||||
|
|
||||||
// Parse signature params from query string. r.URL.Query() would silently
|
// Parse signature params from query string. r.URL.Query() would silently
|
||||||
// drop a pair it cannot decode, such as q=80%, so that q would be served
|
// drop a pair it cannot decode, such as q=80%, so that q would be served
|
||||||
// at 85; a query string that cannot be decoded is refused instead.
|
// at 85; a query string that cannot be decoded is refused instead. A
|
||||||
|
// parameter given more than once is refused too, as only its first value
|
||||||
|
// would be read.
|
||||||
query, err := url.ParseQuery(r.URL.RawQuery)
|
query, err := url.ParseQuery(r.URL.RawQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.respondError(w, fmt.Sprintf("invalid query string %q: %v",
|
s.respondError(w, fmt.Sprintf("invalid query string %q: %v",
|
||||||
@@ -103,6 +105,15 @@ func (s *Handlers) parseImageRequest(
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name, values := range query {
|
||||||
|
if len(values) > 1 {
|
||||||
|
s.respondError(w, fmt.Sprintf("invalid %s: given more than once",
|
||||||
|
name), http.StatusBadRequest)
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
req.Signature = query.Get("sig")
|
req.Signature = query.Get("sig")
|
||||||
|
|
||||||
if expStr := query.Get("exp"); expStr != "" {
|
if expStr := query.Get("exp"); expStr != "" {
|
||||||
|
|||||||
Reference in New Issue
Block a user