Page MenuHomePhorge

No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/majic/plug.ex b/lib/majic/plug.ex
index 5e28ae4..a302339 100644
--- a/lib/majic/plug.ex
+++ b/lib/majic/plug.ex
@@ -1,115 +1,115 @@
if Code.ensure_loaded?(Plug) do
defmodule Majic.PlugError do
defexception [:message]
end
defmodule Majic.Plug do
@moduledoc """
A `Plug` to automatically set the `content_type` of every `Plug.Upload`.
One of the required option of `pool`, `server` or `once` must be set.
Additional options:
* `fix_extension`, default false: enable use of `Majic.Extension`,
* options for `Majic.Extension`.
To use a majic pool:
```
plug Majic.Plug, pool: MyApp.MajicPool
```
To use a single majic server:
```
plug Majic.Plug, server: MyApp.MajicServer
```
To start a majic process at each file (not recommended):
```
plug Majic.Plug, once: true
```
"""
@behaviour Plug
@impl Plug
def init(opts) do
cond do
Keyword.has_key?(opts, :pool) -> true
Keyword.has_key?(opts, :server) -> true
Keyword.has_key?(opts, :once) -> true
true -> raise(Majic.PlugError, "No server/pool/once option defined")
end
opts
|> Keyword.put_new(:fix_extension, false)
|> Keyword.put_new(:append, false)
|> Keyword.put_new(:subtype_as_extension, false)
end
@impl Plug
def call(conn, opts) do
body_params = transform_uploads(conn.body_params, opts)
params = merge_params(conn.query_params, body_params)
%{conn | body_params: body_params, params: params}
end
defp merge_params(query_params, body_params) when is_map(query_params) and is_map(body_params) do
Map.merge(query_params, body_params, fn _k, qv, bv ->
merge_values(qv, bv)
end)
end
defp merge_values(qv, bv) when is_map(qv) and is_map(bv) do
Map.merge(qv, bv, fn _k, qv2, bv2 -> merge_values(qv2, bv2) end)
end
defp merge_values(_qv, bv), do: bv
defp transform_uploads(params, opts) when is_map(params) do
Map.new(params, fn {k, v} -> {k, transform_upload_value(v, opts)} end)
end
defp transform_uploads(params, opts) when is_list(params) do
Enum.map(params, &transform_upload_value(&1, opts))
end
defp transform_upload_value(%{__struct__: Plug.Upload} = upload, opts) do
case Majic.perform(upload.path, opts) do
{:ok, magic} -> fix_upload(upload, magic, opts)
- {:error, error} -> raise(Majic.PlugError, "Failed to majic: #{inspect(error)}")
+ {:error, _error} -> upload
end
end
defp transform_upload_value(%{__struct__: _} = struct, _opts) do
struct
end
defp transform_upload_value(v, opts) when is_map(v) do
transform_uploads(v, opts)
end
defp transform_upload_value(v, opts) when is_list(v) do
transform_uploads(v, opts)
end
defp transform_upload_value(v, _opts) do
v
end
defp fix_upload(upload, magic, opts) do
filename =
if Keyword.get(opts, :fix_extension) do
ext_opts = [
append: Keyword.get(opts, :append, false),
subtype_as_extension: Keyword.get(opts, :subtype_as_extension, false)
]
Majic.Extension.fix(upload.filename, magic, ext_opts)
end
%{upload | content_type: magic.mime_type, filename: filename || upload.filename}
end
end
end
diff --git a/test/majic/plug_test.exs b/test/majic/plug_test.exs
index 11d3294..51fa47b 100644
--- a/test/majic/plug_test.exs
+++ b/test/majic/plug_test.exs
@@ -1,111 +1,120 @@
defmodule Majic.PlugTest do
use ExUnit.Case, async: true
use Plug.Test
defmodule TestRouter do
use Plug.Router
plug(:match)
plug(:dispatch)
plug(Plug.Parsers,
parsers: [:urlencoded, :multipart],
pass: ["*/*"]
)
# plug Majic.Plug, once: true
post "/" do
send_resp(conn, 200, "Ok")
end
end
setup_all do
Application.ensure_all_started(:plug)
:ok
end
@router_opts TestRouter.init([])
test "convert uploads" do
multipart = """
------w58EW1cEpjzydSCq\r
Content-Disposition: form-data; name=\"form[makefile]\"; filename*=\"utf-8''mymakefile.txt\"\r
Content-Type: text/plain\r
\r
#{File.read!("Makefile")}\r
------w58EW1cEpjzydSCq\r
Content-Disposition: form-data; name=\"form[make][file]\"; filename*=\"utf-8''mymakefile.txt\"\r
Content-Type: text/plain\r
\r
#{File.read!("Makefile")}\r
------w58EW1cEpjzydSCq\r
Content-Disposition: form-data; name=\"cat\"; filename*=\"utf-8''cute-cat.jpg\"\r
Content-Type: image/jpg\r
\r
#{File.read!("test/fixtures/cat.webp")}\r
------w58EW1cEpjzydSCq\r
Content-Disposition: form-data; name=\"cats[]\"; filename*=\"utf-8''first-cute-cat.jpg\"\r
Content-Type: image/jpg\r
\r
#{File.read!("test/fixtures/cat.webp")}\r
------w58EW1cEpjzydSCq\r
Content-Disposition: form-data; name=\"cats[]\"\r
\r
hello i am annoying
\r
------w58EW1cEpjzydSCq\r
Content-Disposition: form-data; name=\"cats[]\"; filename*=\"utf-8''second-cute-cat.jpg\"\r
Content-Type: image/jpg\r
\r
#{File.read!("test/fixtures/cat.webp")}\r
------w58EW1cEpjzydSCq\r
Content-Disposition: form-data; name=\"cats[][inception][cat]\"; filename*=\"utf-8''third-cute-cat.jpg\"\r
Content-Type: image/jpg\r
\r
#{File.read!("test/fixtures/cat.webp")}\r
------w58EW1cEpjzydSCq--\r
"""
orig_conn =
conn(:post, "/", multipart)
|> put_req_header("content-type", "multipart/mixed; boundary=----w58EW1cEpjzydSCq")
|> TestRouter.call(@router_opts)
plug = Majic.Plug.init(once: true, fix_extension: true, startup_timeout: 5000)
plug_no_ext = Majic.Plug.init(once: true, fix_extension: false, startup_timeout: 5000)
plug_append_ext = Majic.Plug.init(once: true, fix_extension: true, append: true, startup_timeout: 5000)
conn = Majic.Plug.call(orig_conn, plug)
conn_no_ext = Majic.Plug.call(orig_conn, plug_no_ext)
conn_append_ext = Majic.Plug.call(orig_conn, plug_append_ext)
assert conn.state == :sent
assert conn.status == 200
assert get_in(conn.body_params, ["form", "makefile"]) ==
get_in(conn.params, ["form", "makefile"])
assert get_in(conn.params, ["form", "makefile"]).content_type == "text/x-makefile"
assert get_in(conn.params, ["form", "makefile"]).filename == "mymakefile"
assert get_in(conn_no_ext.params, ["form", "makefile"]).filename == "mymakefile.txt"
assert get_in(conn_append_ext.params, ["form", "makefile"]).filename == "mymakefile"
assert get_in(conn.body_params, ["form", "make", "file"]) ==
get_in(conn.params, ["form", "make", "file"])
assert get_in(conn.params, ["form", "make", "file"]).content_type == "text/x-makefile"
assert get_in(conn.body_params, ["cat"]) == get_in(conn.params, ["cat"])
assert get_in(conn.params, ["cat"]).content_type == "image/webp"
assert get_in(conn.params, ["cat"]).filename == "cute-cat.webp"
assert get_in(conn_no_ext.params, ["cat"]).filename == "cute-cat.jpg"
assert get_in(conn_append_ext.params, ["cat"]).filename == "cute-cat.jpg.webp"
assert Enum.all?(conn.params["cats"], fn
%Plug.Upload{} = upload -> upload.content_type == "image/webp"
%{"inception" => %{"cat" => upload}} -> upload.content_type == "image/webp"
_ -> true
end)
end
+
+ test "falls back to original upload on majic error" do
+ upload = %Plug.Upload{path: "/nonexistent/path/file.txt", filename: "file.txt", content_type: "text/plain"}
+ conn = conn(:post, "/", %{"file" => upload})
+ plug = Majic.Plug.init(once: true, startup_timeout: 5000)
+ result = Majic.Plug.call(conn, plug)
+ assert result.params["file"].content_type == "text/plain"
+ assert result.params["file"].filename == "file.txt"
+ end
end

File Metadata

Mime Type
text/x-diff
Expires
Sun, Aug 9, 10:43 AM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1722839
Default Alt Text
(7 KB)

Event Timeline