The closest I could get to read the file was seeing it in the body
defmodule Foo.Bar do
use Plug.Router
import Plug.Conn
require Logger
plug Plug.Logger, log: :debug
plug :match
plug :dispatch
plug(Plug.Parsers, parsers: [:urlencoded, {:multipart, length: 10_000_000}])
post "/foo/bar/import" do
Logger.error(inspect conn.params["file"])
Logger.error(inspect(Plug.Conn.read_body(conn), label: "body"))
end
end
And here is the output of Logger:
2023-02-20 20:57:52.722 [error] nil (module=Foo.Bar line=14 )
2023-02-20 20:57:52.740 [error] {:ok, "-----------------------------2239044772062058215875569635\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example.csv\"\r\nContent-Type: text/csv\r\n\r\nh1;h2;h3\nr1c1;r1c2;r1c3\nr2c1;r2c2;r2c3\nr3c1;r3c2;r3c3\n\r\n-----------------------------2239044772062058215875569635--\r\n", %Plug.Conn{adapter: {Plug.Cowboy.Conn, :...}, assigns: %{}, body_params: %Plug.Conn.Unfetched{aspect: :body_params}, cookies: %Plug.Conn.Unfetched{aspect: :cookies}, halted: false, host: "192.168.11.51", method: "POST", owner: #PID<0.812.0>, params: %{}, path_info: ["foo", "bar", "import"], path_params: %{}, port: 80, private: %{before_send: [#Function<1.3486200/1 in Plug.Logger.call/2>], plug_route: {"/foo/bar/import", #Function<1.57698496/2 in Foo.Bar.do_match/4>}}, query_params: %Plug.Conn.Unfetched{aspect: :query_params}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %Plug.Conn.Unfetched{aspect: :cookies}, req_headers: [{"accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"}, {"accept-encoding", "gzip, deflate, br"}, {"accept-language", "en-US,en;q=0.5"}, {"authorization", "[[content removed]]"}, {"cache-control", "no-cache"}, {"content-length", "271"}, {"content-type", "multipart/form-data; boundary=---------------------------2239044772062058215875569635"}, {"cookie", "session=1668075015;"}, {"dnt", "1"}, {"host", "192.168.11.51"}, {"origin", "https://192.168.11.51"}, {"pragma", "no-cache"}, {"referer", "https://192.168.11.51/"}, {"sec-fetch-dest", "iframe"}, {"sec-fetch-mode", "navigate"}, {"sec-fetch-site", "same-origin"}, {"sec-gpc", "1"}, {"te", "trailers"}, {"upgrade-insecure-requests", "1"}, {"user-agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0"}, {"x-forwarded-for", "10.0.8.12"}, {"x-forwarded-host", "192.168.11.51"}, {"x-forwarded-port", "443"}, {"x-forwarded-proto", "https"}, {"x-forwarded-server", "root-uld-trk5"}, {"x-real-ip", "10.0.8.12"}], request_path: "/foo/bar/import", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}], scheme: :http, script_name: [], secret_key_base: nil, state: :unset, status: nil}} (module=Foo.Bar line=16 )
Unfortunately getting from here to actually read the file part of the body got me stuck, found no valid example, tried many things I found online that seem to be deprecated as no longer available in Plug 1.14, like get_upload/2, Plug.Upload.parse_multipart/2, get_multipart_params/2, Plug.Upload.get_params/1, Plug.Upload.get/2.
Tried to get_req_header and if it’s “multipart/form-data” do Plug.Multipart.parse or Plug.Parsers.MULTIPART.parse/5 that’s deprecated I guess or I failed to understand how to use, then trying with a recursive with Plug.Parsers.MULTIPART.init([]) and Plug.Parsers.MULTIPART.parse/5
I am definitely miss something here, anyone has a valid example E2E on how can I read the file in the Plug above by only using plug, where the files is clearly visible in the body that’s “multipart/form-data” (P.S. I can’t control the requester to change the content-type).
Thank you