Source backends¶
Sources resolve IIIF identifiers to original-image bytes. iiiris ships three
backends, all satisfying internal/source.Source:
| Backend | Use when | Cached via OriginCache? |
|---|---|---|
filesystem |
Images live on the local disk iiirisd has direct read access to. | No — local disk is its own cache. |
http |
Images live behind an HTTP(S) URL iiirisd can fetch. | Yes — source.Cached wraps automatically. |
s3 |
Images live in an S3 (or S3-compatible) bucket. | Yes — source.Cached wraps automatically. |
The OriginCache wrap is applied in cmd/iiirisd/main.go:buildSources; you
don't configure it per-source.
Filesystem¶
Identifiers map directly to relative paths under sources.filesystem.root.
GET /iiif/3/photos/cat.jpg/info.json
→ reads <root>/photos/cat.jpg
Path traversal (..) and absolute paths are rejected by safePath
(internal/source/filesystem.go); the resolved path must remain inside
root after filepath.Abs.
Filesystem sources are memory-mapped (Unix mmap / Windows
MapViewOfFile), so a render or info probe holds only the pages libvips
actually reads — not the whole compressed file. Peak memory becomes
independent of source size (a one-tile request on a large master no longer
buffers the master). Network sources (HTTP/S3) and raw J2K codestreams fall
back to buffering. Contract:
docs/specs/image-decode.md.
Config:
Or env var: IIIRIS_FS_ROOT=/var/lib/images.
HTTP¶
Identifiers are URL-escaped and appended to sources.http.base_url. The
fetcher is plain net/http with the configured timeout. Upstream auth,
conditional GETs against the upstream, and retries are not implemented yet.
Config:
Upstream 404 becomes source.ErrNotFound (handler returns 404 to the
client); other upstream >=400 statuses surface as a 500 to the client with
the upstream code in the error message.
S3¶
Identifiers are joined with sources.s3.prefix to form the object key. Uses
aws-sdk-go-v2; credentials follow the standard SDK chain.
Config:
sources:
default: s3
s3:
bucket: my-images
region: us-east-1
prefix: production
endpoint: "" # optional, for MinIO etc.
Or env vars: IIIRIS_S3_BUCKET, IIIRIS_S3_REGION, IIIRIS_S3_PREFIX,
IIIRIS_S3_ENDPOINT.
s3types.NoSuchKey becomes source.ErrNotFound → 404. Other AWS errors
surface as 500.
Choosing a default¶
Only the source named in sources.default (filesystem | http | s3) is
queried by handlers in the current implementation. Routing to multiple
sources by identifier (e.g. namespace-based dispatch) is the job of the
Hook interface (deferred, currently Noop).
Health checks (Healthchecker interface)¶
Sources may optionally implement source.Healthchecker so iiiris can probe
reachability cheaply. The /ready endpoint and the admin sources panel
both consume it; checks run in parallel with bounded per-source timeouts.
| Backend | Healthcheck |
|---|---|
| filesystem | stat + open the configured root directory |
| http | HEAD against base_url; non-5xx is healthy (4xx is fine for a base URL) |
| s3 | HeadBucket against the configured bucket |
Sources that don't implement Healthchecker are reported as healthy ("no
opinion = pass"). Use source.AsHealthchecker(s) to find the capability
through the Cached wrapper.
Listing (Lister interface)¶
Sources may optionally implement source.Lister to support directory-style
listing of the identifier namespace. The admin file browser uses this.
| Backend | Lister? |
|---|---|
| filesystem | ✓ |
| http | ✗ (no listing protocol) |
| s3 | ✓ (ListObjectsV2 with Delimiter="/"; paginates) |
source.Cached (which fronts HTTP and S3 sources for OriginCache) doesn't
itself implement Lister, but it exposes its upstream via Unwrap() Source.
Use source.AsLister(s) to find the listing capability through the wrapper.