Current section
Files
Jump to
Current section
Files
lib/url/data.ex
defmodule URL.Data do
@moduledoc """
Parses a `data` URL
"""
import NimbleParsec
import URL.ParseHelpers.{Core, Params, Unwrap}
@default_mediatype "text/plain"
defstruct mediatype: @default_mediatype, params: %{}, data: ""
@type t() :: %__MODULE__{
mediatype: binary(),
params: map(),
data: String.t() | {:error, String.t()}
}
@doc """
Parse a URI with the `:scheme` of "data"
## Example
iex> data = URI.parse "data:text/plain;base64,SGVsbG8gV29ybGQh"
iex> URL.Data.parse(data)
%URL.Data{
data: "Hello World!",
mediatype: "text/plain",
params: %{"encoding" => "base64"}
}
"""
@spec parse(URI.t()) :: __MODULE__.t() | {:error, {module(), binary()}}
def parse(%URI{scheme: "data", path: nil}) do
struct(__MODULE__, data: "")
end
def parse(%URI{scheme: "data", path: path}) do
with {:ok, data} <- unwrap(parse_data(path)) do
struct(__MODULE__, data)
|> decode_data
end
end
defp decode_data(%__MODULE__{params: %{"encoding" => "base64"}, data: data} = url) do
case Base.decode64(data) do
{:ok, decoded} -> Map.put(url, :data, decoded)
:error -> Map.put(url, :data, {:error, data})
end
end
defp decode_data(%__MODULE__{} = data) do
Map.put(data, :data, URI.decode(data.data))
end
defparsecp :parse_data,
optional(mediatype())
|> concat(params())
|> ignore(comma())
|> concat(data())
end