Image.Plug.Cache (image_plug v0.1.0)

Copy Markdown View Source

HTTP-cache helpers used by Image.Plug.

This module is pure. It computes a stable ETag from the source's etag_seed and the normalised pipeline's fingerprint, evaluates If-None-Match for conditional GETs, and produces a default Cache-Control directive.

The ETag is a strong validator computed as:

base64url(sha256(meta.etag_seed <> "|" <> pipeline_fingerprint <> "|" <> chosen_format))

Because the pipeline is normalised first, two URLs that differ only in option order produce the same ETag — bandwidth-friendly and cache-friendly.

Summary

Types

The shape returned by compute/3. The plug attaches these to the conn before the body is sent.

Functions

Computes cache headers for a given source meta + normalised pipeline + chosen output format.

Computes a stable fingerprint for a normalised pipeline. Used by etag/3 and exposed for tests.

Returns true when the request's If-None-Match header matches the computed ETag (i.e. we should respond 304).

Types

cache_info()

@type cache_info() :: %{
  :etag => String.t(),
  :cache_control => String.t(),
  optional(:last_modified) => DateTime.t(),
  optional(:vary) => [String.t()]
}

The shape returned by compute/3. The plug attaches these to the conn before the body is sent.

Functions

compute(meta, pipeline, chosen_format)

@spec compute(map(), Image.Plug.Pipeline.t(), atom()) :: cache_info()

Computes cache headers for a given source meta + normalised pipeline + chosen output format.

Arguments

  • meta is the Image.Plug.SourceResolver.meta map.

  • pipeline is the (normalised) Image.Plug.Pipeline.

  • chosen_format is an atom describing the actual output format selected by the encoder (e.g. :webp even when the request was format=auto). Caller passes this so that two requests choosing different formats get different ETags.

Returns

fingerprint(pipeline)

@spec fingerprint(Image.Plug.Pipeline.t()) :: binary()

Computes a stable fingerprint for a normalised pipeline. Used by etag/3 and exposed for tests.

fresh?(conn, etag)

@spec fresh?(Plug.Conn.t(), String.t()) :: boolean()

Returns true when the request's If-None-Match header matches the computed ETag (i.e. we should respond 304).

Accepts the bare ETag form and the W/"..." weak form, since some intermediaries strip the surrounding quotes.