Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98d23ad32e | ||
|
|
a3dd1aad4e |
@@ -31,11 +31,11 @@ exhaustion
|
|||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
- 2026-09-28 refuse an invalid `q` on `/v1/image/` (closes #134): a `q`
|
- 2026-09-28 refuse an invalid `q` on `/v1/image/` (closes #134): a `q`
|
||||||
that is not a whole number from 1 to 100 is a 400 naming `q` and the
|
that is not a whole number from 1 to 100, an empty `q` included, is a
|
||||||
value, instead of being served at the default 85; the route reads `q`
|
400 naming `q` and the value, instead of being served at the default
|
||||||
with the generator's quality check (`parseFormInt` with `minQuality`
|
85; the route reads `q` with the generator's quality check
|
||||||
and `maxQuality`); an absent or empty `q` is still 85; `README.md`
|
(`parseFormInt` with `minQuality` and `maxQuality`); only a `q` missing
|
||||||
states the range.
|
from the URL is still 85; `README.md` states the range.
|
||||||
- 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
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ import (
|
|||||||
"sneak.berlin/go/pixa/internal/templates"
|
"sneak.berlin/go/pixa/internal/templates"
|
||||||
)
|
)
|
||||||
|
|
||||||
// errInvalidFormField reports a generator form field whose value is
|
// errInvalidFormField reports a generator form field, or the q parameter of
|
||||||
// non-numeric or out of range. The offending field name is wrapped in so the
|
// /v1/image/, whose value is non-numeric or out of range. The offending field
|
||||||
// response can name it.
|
// name is wrapped in so the response can name it.
|
||||||
var errInvalidFormField = errors.New("invalid")
|
var errInvalidFormField = errors.New("invalid")
|
||||||
|
|
||||||
// Bounds for the generator's quality and ttl fields; the quality bounds also
|
// Bounds for the generator's quality and ttl fields; the quality bounds also
|
||||||
|
|||||||
@@ -294,21 +294,24 @@ func TestHandleImage_InvalidFitMode_Returns400(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TestHandleImage_InvalidQuality_Returns400 verifies that the plain image
|
// TestHandleImage_InvalidQuality_Returns400 verifies that the plain image
|
||||||
// route answers a q that is not a whole number from 1 to 100 with 400 naming
|
// route answers a q that is not a whole number from 1 to 100, an empty one
|
||||||
// q and the value, instead of serving the image at the default quality 85.
|
// included, with 400 naming q and the value, instead of serving the image at
|
||||||
|
// the default quality 85.
|
||||||
func TestHandleImage_InvalidQuality_Returns400(t *testing.T) {
|
func TestHandleImage_InvalidQuality_Returns400(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
q, wantError string
|
query, wantError string
|
||||||
}{
|
}{
|
||||||
{"banana", `invalid q: not a number, got "banana"`},
|
{"q=banana", `invalid q: not a number, got "banana"`},
|
||||||
{"0", `invalid q: must be from 1 to 100, got "0"`},
|
{"q=0", `invalid q: must be from 1 to 100, got "0"`},
|
||||||
{"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=&q=500", `invalid q: not a number, got ""`},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run("q="+tt.q, func(t *testing.T) {
|
t.Run(tt.query, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
fix := setupTestHandler(t)
|
fix := setupTestHandler(t)
|
||||||
@@ -317,7 +320,7 @@ func TestHandleImage_InvalidQuality_Returns400(t *testing.T) {
|
|||||||
r.Get("/v1/image/*", fix.handler.HandleImage())
|
r.Get("/v1/image/*", fix.handler.HandleImage())
|
||||||
|
|
||||||
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet,
|
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet,
|
||||||
"/v1/image/"+fix.goodHost+"/images/photo.jpg/50x50.jpeg?q="+tt.q, nil)
|
"/v1/image/"+fix.goodHost+"/images/photo.jpg/50x50.jpeg?"+tt.query, nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
|
|
||||||
r.ServeHTTP(rec, req)
|
r.ServeHTTP(rec, req)
|
||||||
|
|||||||
@@ -102,13 +102,22 @@ func (s *Handlers) parseImageRequest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse optional quality and fit params. An absent q is 85; a q that is
|
// Parse optional quality and fit params. Only a q missing from the URL is
|
||||||
// not a whole number from 1 to 100 is refused, checked as the generator
|
// 85. A q in the URL that is not a whole number from 1 to 100, an empty
|
||||||
// checks its quality field.
|
// one included, is refused, checked as the generator checks its quality
|
||||||
|
// field; that check alone would take an empty q as missing.
|
||||||
|
qStr := query.Get("q")
|
||||||
|
if query.Has("q") && qStr == "" {
|
||||||
|
s.respondError(w, `invalid q: not a number, got ""`,
|
||||||
|
http.StatusBadRequest)
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
req.Quality, err = parseFormInt(query, "q",
|
req.Quality, err = parseFormInt(query, "q",
|
||||||
encurl.DefaultQuality, minQuality, maxQuality)
|
encurl.DefaultQuality, minQuality, maxQuality)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.respondError(w, fmt.Sprintf("%v, got %q", err, query.Get("q")),
|
s.respondError(w, fmt.Sprintf("%v, got %q", err, qStr),
|
||||||
http.StatusBadRequest)
|
http.StatusBadRequest)
|
||||||
|
|
||||||
return nil, false
|
return nil, false
|
||||||
|
|||||||
Reference in New Issue
Block a user