# `Opsmaru.Incus.Gateway.Plug`
[🔗](https://github.com/upmaru/opsmaru-incus/blob/v0.1.0/lib/opsmaru/incus/gateway/plug.ex#L2)

Mountable Plug relaying native Incus HTTP and optional WebSockets through host policy.

Mount it for the canonical native routes, before any body parser:

    # Phoenix router: one root discovery route plus the /1.0 tree.
    get "/", Opsmaru.Incus.Gateway.Plug, gateway: {MyHost.Gateway, :fetch, []}
    forward "/1.0", Opsmaru.Incus.Gateway.Plug, gateway: {MyHost.Gateway, :fetch, []}

`:gateway` is either an `Opsmaru.Incus.Gateway` or an `{module, function,
args}` returning one at request time; prefer the MFA so runtime
configuration and the admission pid are never compiled into the router.

Routing uses the original encoded `request_path` and raw `query_string`, so
`forward` does not change what the backend receives. Only `/`, `/1.0` and
`/1.0/*` are relayed; other paths fail with a native `404` and no backend
contact. If a body parser already consumed the request, the gateway
refuses it with `500` rather than relaying a reconstructed body.

Every request goes through `Opsmaru.Incus.Gateway.Policy` (admission,
readiness, authorization, expiry/revocation) before a backend socket opens.
Discovery and certificate trust use bounded host callbacks; authenticated
GET `/1.0` buffers/replaces public identity. WebSockets use the optional
native WebSocket adapter when available; raw SFTP/NBD requires the host's
same-listener Cowboy gateway handler. Missing adapters fail with `501`.
See `docs/gateway.md` for the verified protocol and mounting contract.

Response streaming is tested with Plug.Cowboy. When a response that has
already started cannot be completed (backend loss, deadline, budget,
revocation), the gateway ends the caller's HTTP/1.x connection without a
final chunk, so the caller sees a truncated response rather than a complete
one. On HTTP/2 it resets the stream.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
