Page MenuHomePhorge

No OneTemporary

Size
8 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/majic/plug.ex b/lib/majic/plug.ex
index a006e73..ad31441 100644
--- a/lib/majic/plug.ex
+++ b/lib/majic/plug.ex
@@ -1,133 +1,142 @@
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 true: rewrite the user provided `filename` with a valid extension for the detected content type
* `append_extension`, default false: append the valid extension to the previous filename, without removing the user provided extension
To use a gen_magic pool:
```
plug Majic.Plug, pool: MyApp.MajicPool
```
To use a single gen_magic server:
```
plug Majic.Plug, server: MyApp.MajicServer
```
To start a gen_magic process at each file (not recommended):
```
plug Majic.Plug, once: true
```
"""
@behaviour Plug
@impl Plug
def init(opts) do
- mod =
- cond do
- Keyword.has_key?(opts, :pool) -> {Majic.Pool, Keyword.get(opts, :pool)}
- Keyword.has_key?(opts, :server) -> {Majic.Server, Keyword.get(opts, :server)}
- Keyword.has_key?(opts, :once) -> {Majic.Once, nil}
- true -> raise(Majic.PlugError, "No server/pool/once option defined")
- end
+ 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(:__module__, mod)
|> Keyword.put_new(:fix_extension, true)
|> Keyword.put_new(:append_extension, false)
end
@impl Plug
def call(%{params: params} = conn, opts) do
%{conn | params: collect_uploads(params, opts)}
end
+ def call(conn, _) do
+ conn
+ end
+
defp collect_uploads(params, opts) do
Enum.reduce(params, Map.new(), fn value, acc -> collect_upload(value, acc, opts) end)
end
defp collect_upload({k, %{__struct__: Plug.Upload, path: path} = upload}, acc, opts) do
- case perform(Keyword.get(opts, :__module__), path) do
+ case Majic.perform(path, opts) do
{:ok, magic} ->
+ IO.puts("Fixed upload -- #{inspect {upload,magic,opts}}")
Map.put(acc, k, fix_upload(upload, magic, opts))
{:error, error} ->
+ IO.puts("UPLOAD GOT BADARG")
raise(Majic.PlugError, "Failed to gen_magic: #{inspect(error)}")
end
end
defp collect_upload({k, v}, acc, opts) when is_map(v) do
Map.put(acc, k, collect_uploads(v, opts))
end
defp collect_upload({k, v}, acc, _opts) do
Map.put(acc, k, v)
end
- defp perform({mod = Majic.Once, _}, path) do
- mod.perform(path)
- end
-
- defp perform({mod, name}, path) do
- mod.perform(name, path)
- end
-
defp fix_upload(upload, magic, opts) do
%{upload | content_type: magic.mime_type}
|> fix_extension(Keyword.get(opts, :fix_extension), opts)
end
defp fix_extension(upload, true, opts) do
old_ext = String.downcase(Path.extname(upload.filename))
extensions = MIME.extensions(upload.content_type)
rewrite_extension(upload, old_ext, extensions, opts)
end
defp fix_extension(upload, _, _) do
upload
end
- defp rewrite_extension(upload, _old, [], _opts) do
- upload
- end
-
defp rewrite_extension(upload, old, [ext | _] = exts, opts) do
if old in exts do
upload
else
basename = Path.basename(upload.filename, old)
%{
upload
| filename:
rewrite_or_append_extension(
basename,
old,
ext,
Keyword.get(opts, :append_extension)
)
}
end
end
+ # No extension for type.
+ defp rewrite_extension(upload, old, [], opts) do
+ %{upload | filename: rewrite_or_append_extension(Path.basename(upload.filename, old), old, nil, Keyword.get(opts, :append_extension))}
+ end
+
+ # Append, no extension for type: keep old extension
+ defp rewrite_or_append_extension(basename, "." <> old, nil, true) do
+ basename <> "." <> old
+ end
+
+ # No extension for type: only keep basename
+ defp rewrite_or_append_extension(basename, _, nil, _) do
+ basename
+ end
+
+ # Append
defp rewrite_or_append_extension(basename, "." <> old, ext, true) do
Enum.join([basename, old, ext], ".")
end
+ # Rewrite
defp rewrite_or_append_extension(basename, _, ext, _) do
basename <> "." <> ext
end
end
end
diff --git a/test/majic/plug_test.exs b/test/majic/plug_test.exs
index 63c2dd9..060408d 100644
--- a/test/majic/plug_test.exs
+++ b/test/majic/plug_test.exs
@@ -1,84 +1,87 @@
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
#{String.replace(File.read!("Makefile"), "\n", "\n")}\r
------w58EW1cEpjzydSCq\r
Content-Disposition: form-data; name=\"form[make][file]\"; filename*=\"utf-8''mymakefile.txt\"\r
Content-Type: text/plain\r
\r
#{String.replace(File.read!("Makefile"), "\n", "\n")}\r
------w58EW1cEpjzydSCq\r
Content-Disposition: form-data; name=\"cat\"; filename*=\"utf-8''cute-cat.jpg\"\r
Content-Type: image/jpg\r
\r
#{String.replace(File.read!("test/fixtures/cat.webp"), "\n", "\n")}\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)
plug_no_ext = Majic.Plug.init(once: true, fix_extension: false)
plug_append_ext = Majic.Plug.init(once: true, fix_extension: true, append_extension: true)
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
refute get_in(conn.body_params, ["form", "makefile"]).content_type ==
get_in(conn.params, ["form", "makefile"]).content_type
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.txt"
refute get_in(conn.body_params, ["form", "make", "file"]).content_type ==
get_in(conn.params, ["form", "make", "file"]).content_type
assert get_in(conn.params, ["form", "make", "file"]).content_type == "text/x-makefile"
refute get_in(conn.body_params, ["cat"]).content_type ==
get_in(conn.params, ["cat"]).content_type
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"
end
end

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 25, 9:32 PM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40072
Default Alt Text
(8 KB)

Event Timeline