Current section

Files

Jump to
plug lib plug parsers multipart.ex
Raw

lib/plug/parsers/multipart.ex

defmodule Plug.Parsers.MULTIPART do
@moduledoc """
Parses multipart request body.
"""
@behaviour Plug.Parsers
def parse(conn, "multipart", subtype, _headers, opts) when subtype in ["form-data", "mixed"] do
{adapter, state} = conn.adapter
try do
adapter.parse_req_multipart(state, opts, &handle_headers/1)
rescue
e in Plug.UploadError -> # Do not ignore upload errors
reraise e, System.stacktrace
e -> # All others are wrapped
reraise Plug.Parsers.ParseError.exception(exception: e), System.stacktrace
else
{:ok, params, state} ->
{:ok, params, %{conn | adapter: {adapter, state}}}
{:more, _params, state} ->
{:error, :too_large, %{conn | adapter: {adapter, state}}}
{:error, :timeout} ->
raise Plug.TimeoutError
{:error, _} ->
raise Plug.BadRequestError
end
end
def parse(conn, _type, _subtype, _headers, _opts) do
{:next, conn}
end
defp handle_headers(headers) do
case List.keyfind(headers, "content-disposition", 0) do
{_, disposition} -> handle_disposition(disposition, headers)
nil -> :skip
end
end
defp handle_disposition(disposition, headers) do
case :binary.split(disposition, ";") do
[_, params] ->
params = Plug.Conn.Utils.params(params)
if name = Map.get(params, "name") do
handle_disposition_params(name, params, headers)
else
:skip
end
[_] ->
:skip
end
end
defp handle_disposition_params(name, params, headers) do
case Map.get(params, "filename") do
nil -> {:binary, name}
"" -> :skip
filename ->
path = Plug.Upload.random_file!("multipart")
{:file, name, path, %Plug.Upload{filename: filename, path: path,
content_type: get_header(headers, "content-type")}}
end
end
defp get_header(headers, key) do
case List.keyfind(headers, key, 0) do
{^key, value} -> value
nil -> nil
end
end
end