1 Commits
Author SHA1 Message Date
clawbot 0b203a6dd4 Serve JPEG XL when a request names no format (closes #222)
check / check (push) Canceled after 0s
A /v1/image/ URL whose last segment is a size with no format, such as
800x600 or orig, is served as JPEG XL and signed as jxl, so it shares
the signature of the same URL ending in .jxl. An encrypted URL whose
token holds no format is served as JPEG XL, as encurl.DefaultFormat is
now jxl. The generator page selects JPEG XL by default, and a form
with an empty format, or none, makes a URL whose name ends in .jxl.

The image processor no longer takes an empty format as orig: both
routes give every request a format, so it refuses a request with none
instead of keeping a second default. auto still ends with JPEG.

Model: opus-5-5
2026-10-08 09:43:52 +00:00
4 changed files with 21 additions and 18 deletions
+15 -14
View File
@@ -175,20 +175,21 @@ path under `/v1/` answers 200, in maintenance mode too.
with the page naming a field that is not valid; 500 when the URL cannot be with the page naming a field that is not valid; 500 when the URL cannot be
made. made.
- `GET /logout` — end the login session. Needs: nothing. Answers: 303 to `/`. - `GET /logout` — end the login session. Needs: nothing. Answers: 303 to `/`.
- `GET` or `HEAD` `/v1/image/<host>/<path>/<size>.<format>` — an image, fetched, - `GET` or `HEAD` `/v1/image/<host>/<path>/<size>.<format>`, or
resized and converted (below). Needs: a signature, unless the host is `/v1/image/<host>/<path>/<size>` with no format — an image, fetched, resized
allowlisted (see Source Hosts). Answers: 200; 304 when `If-None-Match` matches and converted (below). Needs: a signature, unless the host is allowlisted (see
the image's `ETag`; 400 for a URL or parameter that is not valid, or for the Source Hosts). Answers: 200; 304 when `If-None-Match` matches the image's
format `auto` an `Accept` header that is not valid; 406 for the format `auto` `ETag`; 400 for a URL or parameter that is not valid, or for the format `auto`
when `Accept` allows none of the formats it chooses from; 401 for a missing or an `Accept` header that is not valid; 406 for the format `auto` when `Accept`
wrong signature, a missing `exp` or an `exp` in the past; 403 when the allows none of the formats it chooses from; 401 for a missing or wrong
request's `Referer` names a host in `referer_blocklist`, checked before the signature, a missing `exp` or an `exp` in the past; 403 when the request's
signature, the cache and the upstream fetch; 403 when the upstream host, or a `Referer` names a host in `referer_blocklist`, checked before the signature,
host it redirects to, is `localhost`, ends in `.localhost` or `.local`, or has the cache and the upstream fetch; 403 when the upstream host, or a host it
an address in a blocked network (see `blocked_networks`); 502 when the redirects to, is `localhost`, ends in `.localhost` or `.local`, or has an
upstream answered with an error status, and for 5 minutes after that for the address in a blocked network (see `blocked_networks`); 502 when the upstream
same source URL; 503 when pixa is busy or in maintenance mode; 500 for any answered with an error status, and for 5 minutes after that for the same
other failure. source URL; 503 when pixa is busy or in maintenance mode; 500 for any other
failure.
- `GET` or `HEAD` `/v1/e/<token>/<name>` — an image through an encrypted URL - `GET` or `HEAD` `/v1/e/<token>/<name>` — an image through an encrypted URL
(see Encrypted URLs). Needs: nothing but the URL. Answers: 200; 304 when (see Encrypted URLs). Needs: nothing but the URL. Answers: 200; 304 when
`If-None-Match` matches the image's `ETag`; 400 for a token that does not `If-None-Match` matches the image's `ETag`; 400 for a token that does not
+2 -1
View File
@@ -18,7 +18,8 @@ import (
) )
// HandleImage handles the main image proxy route: // HandleImage handles the main image proxy route:
// /v1/image/<host>/<path>/<width>x<height>.<format> // /v1/image/<host>/<path>/<width>x<height>.<format>, or with no format
// /v1/image/<host>/<path>/<width>x<height>
func (s *Handlers) HandleImage() http.HandlerFunc { func (s *Handlers) HandleImage() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
if s.refuseBlockedReferer(w, r) { if s.refuseBlockedReferer(w, r) {
+2 -2
View File
@@ -100,8 +100,8 @@ func NewService(cfg *ServiceConfig) (*Service, error) {
allowHTTP = cfg.FetcherConfig.AllowHTTP allowHTTP = cfg.FetcherConfig.AllowHTTP
} }
// JPEG XL is to become the default output format, so pixad does not // JPEG XL is the default output format, so pixad does not start
// start without it. // without it.
err := imageprocessor.CheckJPEGXLSupport() err := imageprocessor.CheckJPEGXLSupport()
if err != nil { if err != nil {
return nil, err return nil, err
+2 -1
View File
@@ -89,7 +89,8 @@ func (s *Server) SetupRoutes() {
r.Use(s.refuseDuringMaintenance) r.Use(s.refuseDuringMaintenance)
// Main image proxy route // Main image proxy route
// /v1/image/<host>/<path>/<width>x<height>.<format> // /v1/image/<host>/<path>/<width>x<height>.<format>, or with no
// format /v1/image/<host>/<path>/<width>x<height>
r.Get("/image/*", s.h.HandleImage()) r.Get("/image/*", s.h.HandleImage())
r.Head("/image/*", s.h.HandleImage()) r.Head("/image/*", s.h.HandleImage())