Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multipart content based post failing if the file name contains space or () characters #486

Open
muraleepadma opened this issue Feb 13, 2024 · 1 comment

Comments

@muraleepadma
Copy link

muraleepadma commented Feb 13, 2024

For a file name ZAF (2).zip the code fails to upload it whereas if I remove the spaces and () from the file name it works.

One difference I notice is that content length and content type are different just because the file name has spaces.

{"content-length", "92"},
{"content-type", "application/json; charset=utf-8"},

Appreciate if you could look into this and let me know if any additional details needed.

Environment :

erlang 26.0.2
elixir 1.15.6-otp-26
{:httpoison, "~> 2.1"}

Error Case :

options = [connect_timeout: 3_600_000, recv_timeout: 3_600_000, timeout: 3_600_000]
path_to_file = "/Users/mpadmaos10/Downloads/ZAF\ \(2\).zip"
content = File.read!(path_to_file)
file_name = "ZAF (2).zip"
url =  "http://localhost:52222/api/upsert_activity_attachment/user_id/mpadma/activity_id/450"
headers=[{"content-type", MIME.from_path(path_to_file)}]

HTTPoison.post(url,  {:multipart,[{"attachment", content, {"form-data", [name: "attachment", filename: file_name]}, []}]},  headers,  options)

Response :

{:ok,
 %HTTPoison.Response{
   status_code: 400,
   body: "# Plug.Parsers.BadEncodingError at POST /api/upsert_activity_attachment/user_id/mpadma/acivity_id/450\n\nException:\n\n    ** (Plug.Parsers.BadEncodingError) invalid UTF-8 on multipart body, got byte 205\n        (plug 1.14.2) lib/plug/conn/utils.ex:292: Plug.Conn.Utils.do_validate_utf8!/3\n        (plug 1.14.2) lib/plug/parsers/multipart.ex:206: Plug.Parsers.MULTIPART.parse_multipart_headers/5\n        (plug 1.14.2) lib/plug/parsers/multipart.ex:186: Plug.Parsers.MULTIPART.parse_multipart/5\n        (plug 1.14.2) lib/plug/parsers/multipart.ex:175: Plug.Parsers.MULTIPART.parse_multipart/2\n        (plug 1.14.2) lib/plug/parsers/multipart.ex:127: Plug.Parsers.MULTIPART.parse/5\n        (plug 1.14.2) lib/plug/parsers.ex:340: Plug.Parsers.reduce/8\n        (dharma 1.0.0) lib/dharma_web/endpoint.ex:1: DharmaWeb.Endpoint.plug_builder_call/2\n        (dharma 1.0.0) deps/plug/lib/plug/debugger.ex:136: DharmaWeb.Endpoint.\"call (overridable 3)\"/2\n        (dharma 1.0.0) lib/dharma_web/endpoint.ex:1: DharmaWeb.Endpoint.call/2\n        (phoenix 1.6.16) lib/phoenix/endpoint/cowboy2_handler.ex:54: Phoenix.Endpoint.Cowboy2Handler.init/4\n        (cowboy 2.10.0) /Users/mpadmaos10/projects/source_code/dharma/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2\n        (cowboy 2.10.0) /Users/mpadmaos10/projects/source_code/dharma/deps/cowboy/src/cowboy_stream_h.erl:306: :cowboy_stream_h.execute/3\n        (cowboy 2.10.0) /Users/mpadmaos10/projects/source_code/dharma/deps/cowboy/src/cowboy_stream_h.erl:295: :cowboy_stream_h.request_process/3\n        (stdlib 5.0.2) proc_lib.erl:241: :proc_lib.init_p_do_apply/3\n    \n\nCode:\n\n`lib/plug/conn/utils.ex`\n\n    287     defp do_validate_utf8!(&lt;&lt;_::utf8, rest::bits&gt;&gt;, exception, context) do\n    288       do_validate_utf8!(rest, exception, context)\n    289     end\n    290   \n    291     defp do_validate_utf8!(&lt;&lt;byte, _::bits&gt;&gt;, exception, context) do\n    292>      raise exception, &quot;invalid UTF-8 on \#{context}, got byte \#{byte}&quot;\n    293     end\n    294   \n    295     defp do_validate_utf8!(&lt;&lt;&gt;&gt;, _exception, _context) do\n    296       :ok\n    297     end\n    \n`lib/plug/parsers/multipart.ex`\n\n    201         {:binary, name} -&gt;\n    202           {:ok, limit, body, conn} =\n    203             parse_multipart_body(Plug.Conn.read_part_body(conn, opts), limit, opts, &quot;&quot;)\n    204   \n    205           if Keyword.get(opts, :validate_utf8, true) do\n    206>            Plug.Conn.Utils.validate_utf8!(body, Plug.Parsers.BadEncodingError, &quot;multipart body&quot;)\n    207           end\n    208   \n    209           {conn, limit, [{name, headers, body} | acc]}\n    210   \n    211         {:file, name, path, %Plug.Upload{} = uploaded} -&gt;\n    \n`lib/plug/parsers/multipart.ex`\n\n    181         {:error, :too_large, conn}\n    182       end\n    183     end\n    184   \n    185     defp parse_multipart({:ok, headers, conn}, limit, opts, headers_opts, acc) when limit &gt;= 0 do\n    186>      {conn, limit, acc} = parse_multipart_headers(headers, conn, limit, opts, acc)\n    187       read_result = Plug.Conn.read_part_headers(conn, headers_opts)\n    188       parse_multipart(read_result, limit, opts, headers_opts, acc)\n    189     end\n    190   \n    191     defp parse_multipart({:ok, _headers, conn}, limit, _opts, _headers_opts, acc) do\n    \n`lib/plug/parsers/multipart.ex`\n\n    170       parse_multipart(conn, {m2p, limit, header_opts, opts})\n    171     end\n    172   \n    173     defp parse_multipart(conn, {m2p, limit, headers_opts, opts}) do\n    174       read_result = Plug.Conn.read_part_headers(conn, headers_opts)\n    175>      {:ok, limit, acc, conn} = parse_multipart(read_result, limit, opts, headers_opts, [])\n    176   \n    177       if limit &gt; 0 do\n    178         {mod, fun, args} = m2p\n    179         apply(mod, fun, [acc, conn | args])\n    180       else\n    \n`lib/plug/parsers/multipart.ex`\n\n    122   \n    123     @impl true\n    124     def parse(conn, &quot;multipart&quot;, subtype, _headers, opts_tuple)\n    125         when subtype in [&quot;form-data&quot;, &quot" <> ...,
   headers: [
     {"cache-control", "max-age=0, private, must-revalidate"},
     {"content-length", "8895"},
     {"content-type", "text/markdown; charset=utf-8"},
     {"date", "Tue, 13 Feb 2024 18:29:59 GMT"},
     {"server", "Cowboy"}
   ],
   request_url: "http://localhost:52222/api/upsert_activity_attachment/user_id/mpadma/acivity_id/450",
   request: %HTTPoison.Request{
     method: :post,
     url: "http://localhost:52222/api/upsert_activity_attachment/user_id/mpadma/acivity_id/450",
     headers: [],
     body: {:multipart,
      [
        {"attachment",
         <<80, 75, 3, 4, 20, 0, 0, 0, 8, 0, 205, 29, 191, 86, 113, 102, 163, 15,
           81, 6, 0, 0, 58, 10, 0, 0, 12, 0, 0, 0, 67, 117, 114, 114, ...>>,
         {"form-data", [name: "attachment", filename: "ZAF (2).zip"]}, []}
      ]},
     params: %{},
     options: [
       connect_timeout: 3600000,
       recv_timeout: 3600000,
       timeout: 3600000
     ]
   }
 }}

Same File without spaces.

options = [connect_timeout: 3_600_000, recv_timeout: 3_600_000, timeout: 3_600_000]
path_to_file = "/Users/mpadmaos10/Downloads/ZAF.zip"
file_name  = "ZAF.zip"
content = File.read!(path_to_file)
headers=[{"content-type", MIME.from_path(path_to_file)}]

HTTPoison.post(url,  {:multipart,[{"attachment", content, {"form-data", [name: "attachment", filename: file_name]}, []}]},  headers,  options)

Response :

{:ok,
 %HTTPoison.Response{
   status_code: 200,
   body: "{\"id\":100,\"status\":\"ok\",\"description\":\"Activity Attachment \\\"ZAF.zip\\\" added For Id = 100.\"}",
   headers: [
     {"access-control-allow-credentials", "true"},
     {"access-control-allow-origin", "*"},
     {"access-control-expose-headers", ""},
     {"cache-control", "max-age=0, private, must-revalidate"},
     {"content-length", "92"},
     {"content-type", "application/json; charset=utf-8"},
     {"date", "Tue, 13 Feb 2024 18:50:30 GMT"},
     {"server", "Cowboy"},
     {"x-request-id", "F7OAumZclgeU2NgAAADB"}
   ],
   request_url: "http://localhost:52222/api/upsert_activity_attachment/user_id/mpadma/activity_id/450",
   request: %HTTPoison.Request{
     method: :post,
     url: "http://localhost:52222/api/upsert_activity_attachment/user_id/mpadma/activity_id/450",
     headers: [],
     body: {:multipart,
      [
        {"attachment",
         <<80, 75, 3, 4, 20, 0, 0, 0, 8, 0, 205, 29, 191, 86, 113, 102, 163, 15,
           81, 6, 0, 0, 58, 10, 0, 0, 12, 0, 0, 0, 67, 117, 114, 114, ...>>,
         {"form-data", [name: "attachment", filename: "ZAF.zip"]}, []}
      ]},
     params: %{},
     options: [
       connect_timeout: 3600000,
       recv_timeout: 3600000,
       timeout: 3600000
     ]
   }
 }}
@muraleepadma
Copy link
Author

@edgurgel if you could look into this and let me know in case any additional details are required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant