Current section
Files
Jump to
Current section
Files
lib/multipartable.ex
defmodule Multipartable do
def build(boundary, list) do
parts = Enum.map(list, fn(p) ->
case p do
{:file, headers, content, opts} ->
build_file_part(boundary, headers, content, opts)
{:data, headers, content, opts} ->
build_data_part(boundary, headers, content, opts)
{:multipart, boundary, list} -> Multipartable.build(boundary, list)
end
end)
parts ++ epilogue(boundary)
|> Enum.join
end
def build_file_part(boundary, headers, content, opts \\ %{}) do
transfer_encoding =
case headers do
%{"Content-Transfer-Encoding" => v} -> v
_ -> "binary"
end
content_disposition =
case headers do
%{"Content-Disposition" => v} -> v
_ -> "form-data"
end
content_len = byte_size(content)
"--#{boundary}\r\n" <>
"Content-Disposition: #{content_disposition}; #{content_disposition_options(opts)}\r\n" <>
"Content-Length: #{content_len}\r\n" <>
"Content-Type: #{headers["Content-Type"]}\r\n" <>
"Content-Transfer-Encoding: #{transfer_encoding}\r\n" <>
"\r\n" <>
"#{content}\r\n"
end
def build_data_part(boundary, headers, content, opts \\ %{}) do
"--#{boundary}\r\n" <>
"Content-Disposition: form-data; #{content_disposition_options(opts)}\r\n" <>
"Content-Type: #{headers["Content-Type"]}\r\n" <>
"\r\n" <>
"#{content}\r\n"
end
def epilogue(boundary) do
["--#{boundary}--\r\n"]
end
defp content_disposition_options(opts) do
Enum.map(opts, fn{k, v} -> "#{k}=\"#{v}\";" end) |> Enum.join
end
end