Skip to content

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:

sources:
  default: filesystem
  filesystem:
    root: /var/lib/images

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:

sources:
  default: http
  http:
    base_url: https://images.example.org
    timeout: 30s

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.