Raw-body cache for Rindle.Delivery.WebhookPlug.
Adopters wire this into their endpoint via the Plug.Parsers :body_reader
option:
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
body_reader: {Rindle.Delivery.WebhookBodyReader, :read_body, []},
json_decoder: JasonThe reader drains the request body (looping over {:more, _, conn} reads
that Plug.Parsers.JSON.decode/3 does NOT loop on), caps total bytes at
1 MiB, and stores the body in conn.assigns[:raw_body] as a list of
binaries (most-recent first; multipart-safe).
raw_body/1 is the public accessor Rindle.Delivery.WebhookPlug calls to
retrieve the verified raw body for HMAC signature checks.
Body cap (D-08)
Mux webhooks are <10 KB in practice; 1 MiB is 100× headroom and matches
Stripe's documented recommendation. Over-limit returns {:error, :too_large},
which Plug.Parsers translates to Plug.Parsers.RequestTooLargeError → 413.
Multipart safety (D-06)
Plug.Parsers.MULTIPART invokes the body reader once per part; chunked
transfers may produce multiple {:more, _} reads. The cache stores each
drained body as one element of conn.assigns[:raw_body], most-recent first.
raw_body/1 reverses and joins on read.
Summary
Functions
Returns the cached raw body from conn.assigns[:raw_body].
Plug.Parsers :body_reader MFA contract. Drains the body, caps at 1 MiB,
caches the chunks in conn.assigns[:raw_body].
Functions
@spec raw_body(Plug.Conn.t()) :: binary() | nil
Returns the cached raw body from conn.assigns[:raw_body].
Handles the canonical list-of-binaries shape:
- single-element list →
List.first/1 - multi-element list (multipart / multi-chunk) →
Enum.reverse |> IO.iodata_to_binary - missing assign →
nil(caller falls back toPlug.Conn.read_body/2)
@spec read_body(Plug.Conn.t(), Keyword.t()) :: {:ok, binary(), Plug.Conn.t()} | {:error, :too_large} | {:error, term()}
Plug.Parsers :body_reader MFA contract. Drains the body, caps at 1 MiB,
caches the chunks in conn.assigns[:raw_body].
Returns {:ok, binary, conn} on success, {:error, :too_large} if the
accumulated chunks exceed 1 MiB, or any {:error, term()} Plug.Conn.read_body/2
surfaces.