# `Image.Plug.Provider.Cloudflare.URL`
[🔗](https://github.com/elixir-image/image_plug/blob/v0.1.0/lib/image/plug/provider/cloudflare/url.ex#L1)

URL-shape recognition for the Cloudflare Images URL grammar.

Two forms are recognised:

### Remote-image transform

    /cdn-cgi/image/<options>/<source>

Where `<source>` is either an absolute path (`/foo/bar.jpg`) or an
absolute URL (`http://...` or `https://...`). Always recognised.

### Hosted-image delivery

    /<account_hash>/<image-id>/<variant-or-options>

Recognised when the provider is configured with
`:hosted_account_hash`. The trailing segment is treated as a
variant name iff it contains no `=` character (matching
Cloudflare's documented rule); otherwise it is parsed as an
options string. An empty trailing segment maps to the implicit
`"public"` variant.

This module does not interpret the options string — that is
`Image.Plug.Provider.Cloudflare.Options`' job — and it does not
load any source bytes.

# `recognised`

```elixir
@type recognised() :: %{
  shape: :remote | :hosted,
  options: String.t() | nil,
  variant: String.t() | nil,
  source: Image.Plug.Source.t()
}
```

The recognised URL shape, ready for the options parser and the
source resolver.

* `:shape` — `:remote` (cdn-cgi form) or `:hosted` (delivery form).

* `:options` — an options string. `nil` for the hosted form when
  the trailing segment was a variant name.

* `:variant` — a variant name. `nil` for the remote form and for
  the hosted form when the trailing segment looked like options.

* `:source` — the `Image.Plug.Source` derived from the URL.

# `parse`

```elixir
@spec parse(
  Plug.Conn.t(),
  keyword()
) :: {:ok, recognised()} | {:error, Image.Plug.Error.t()}
```

Parses the request path of a `Plug.Conn` into a recognised URL
shape.

### Arguments

* `conn` is a `Plug.Conn` struct.

* `options` is a keyword list. The following keys are honoured:

### Options

* `:mount` — string path prefix that the plug is mounted under.
  Stripped before pattern matching. Defaults to `""`.

* `:hosted_account_hash` — when set, also recognise
  `/<this-hash>/<image-id>/<tail>`. Defaults to `nil`.

### Returns

* `{:ok, recognised}` on a successful match.

* `{:error, %Image.Plug.Error{tag: :malformed_url}}` when the
  path does not match either form.

* `{:error, %Image.Plug.Error{tag: :invalid_option}}` when the
  source segment is malformed.

### Examples

    iex> conn = %Plug.Conn{
    ...>   path_info: ["cdn-cgi", "image", "width=200", "foo", "bar.jpg"],
    ...>   request_path: "/cdn-cgi/image/width=200/foo/bar.jpg"
    ...> }
    iex> {:ok, %{shape: :remote, options: "width=200", source: source}} =
    ...>   Image.Plug.Provider.Cloudflare.URL.parse(conn, [])
    iex> source.kind
    :path

    iex> conn = %Plug.Conn{
    ...>   path_info: ["acct123", "img456", "thumbnail"],
    ...>   request_path: "/acct123/img456/thumbnail"
    ...> }
    iex> {:ok, parsed} =
    ...>   Image.Plug.Provider.Cloudflare.URL.parse(conn,
    ...>     hosted_account_hash: "acct123"
    ...>   )
    iex> {parsed.shape, parsed.variant, parsed.source.ref}
    {:hosted, "thumbnail", {"acct123", "img456"}}

---

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