Escape state_dir in the db_url derived from it (closes #290)
check / check (push) Canceled after 0s

The derived db_url put state_dir into a file: URL as it was, so SQLite
decoded a %HH in the name and ended the path at a ? or #, and the
journal mode parameter was lost. It is now built with net/url, which
percent-encodes the directory name; SQLite decodes it back and opens
state.sqlite3 in that directory. OmitHost keeps the usual form
file:/var/lib/pixa/state.sqlite3 and a relative state_dir a path.

Model: opus-5-5
This commit is contained in:
2026-10-16 00:45:38 +00:00
parent 2ef9e57840
commit bfd486cd95
3 changed files with 26 additions and 7 deletions
+7 -5
View File
@@ -693,11 +693,13 @@ Key settings in more detail:
- `signing_key` — HMAC secret for URL signatures - `signing_key` — HMAC secret for URL signatures
- `db_url` — the SQLite database to open; omitted, it is - `db_url` — the SQLite database to open; omitted, it is
`file:<state_dir>/state.sqlite3?_pragma=journal_mode(WAL)`, which keeps the `file:<state_dir>/state.sqlite3?_pragma=journal_mode(WAL)`, which keeps the
database in WAL mode. pixa opens one connection to it, so its own reads and database in WAL mode. `state_dir` is percent-encoded in it, so a `%`, `?` or
writes run one at a time. pixa adds `_pragma=busy_timeout(5000)` to any `#` in the name is written as `%25`, `%3F` or `%23`. pixa opens one connection
`db_url`, so a write that finds another program writing to the file waits up to it, so its own reads and writes run one at a time. pixa adds
to five seconds for it instead of failing. WAL mode comes only from the URL: `_pragma=busy_timeout(5000)` to any `db_url`, so a write that finds another
keep `_pragma=journal_mode(WAL)` in one you set program writing to the file waits up to five seconds for it instead of
failing. WAL mode comes only from the URL: keep `_pragma=journal_mode(WAL)` in
one you set
- `cache_max_bytes` — disk cache size limit in bytes; `0` disables the disk - `cache_max_bytes` — disk cache size limit in bytes; `0` disables the disk
cache entirely; omitted defaults to 75% of the sum of the free space on the cache entirely; omitted defaults to 75% of the sum of the free space on the
filesystem containing `<state_dir>/cache/` and the bytes of source and filesystem containing `<state_dir>/cache/` and the bytes of source and
+6
View File
@@ -30,6 +30,12 @@ P2: security: per-origin rate limiting
# Completed Steps # Completed Steps
- 2026-10-16 a `state_dir` whose name holds `%`, `?` or `#` keeps its database
at `state.sqlite3` in that directory (closes #290): the `db_url` derived from
it put the name into a `file:` URL as it was, so SQLite read `%41` as `A`, a
`?` or `#` ended the path early, and the journal mode parameter was lost. The
derived `db_url` is now built with Go's `net/url`, which writes those
characters as `%25`, `%3F` and `%23`.
- 2026-10-15 a thin source requested with `fit=cover` no longer makes libvips - 2026-10-15 a thin source requested with `fit=cover` no longer makes libvips
build a huge image (closes #282): libvips' thumbnail scaled the whole source build a huge image (closes #282): libvips' thumbnail scaled the whole source
to cover the requested size and copied that into memory before it cut out the to cover the requested size and copied that into memory before it cut out the
+13 -2
View File
@@ -338,8 +338,19 @@ func newFromSmartConfig(sc *smartconfig.Config) (*Config, error) {
settingName(keyDBURL), errValueEmpty) settingName(keyDBURL), errValueEmpty)
} }
// The driver sets the journal mode only through a _pragma parameter. // The driver sets the journal mode only through a _pragma
c.DBURL = fmt.Sprintf("file:%s/state.sqlite3?_pragma=journal_mode(WAL)", c.StateDir) // parameter. String() percent-encodes any %, ? or # in the
// directory name, which SQLite decodes back, so the URL names
// exactly this file. OmitHost writes file:/var/lib/pixa/...
// instead of file:///var/lib/pixa/..., and keeps a relative
// state_dir from being read as a host name.
dbURL := url.URL{
Scheme: "file",
OmitHost: true,
Path: c.StateDir + "/state.sqlite3",
RawQuery: "_pragma=journal_mode(WAL)",
}
c.DBURL = dbURL.String()
} }
if loader.err != nil { if loader.err != nil {