elixir-plug / plug

Compose web applications with functions
https://hex.pm/packages/plug
Other
2.88k stars 586 forks source link

Mixing file and json parts in multipart/form-data not working #1056

Closed guigaoliveira closed 3 years ago

guigaoliveira commented 3 years ago

Hello, I'm trying to send a image and fields with multipart/form-data, one of these fields has type json. Plug is not parsing json field as expected. The curl code of request I have sent is:

curl --location --request POST 'localhost:4000/api/places' \
--header 'Cookie: _accessibility_reporter_key=SFMyNTY.g3QAAAABbQAAAAp1c2VyX3Rva2VubQAAACDaxnCkUxypE0zYaTMvyG_J95s_5fhcWYf4sMDsqhYvHQ.dIKk2JruNsYSHQp5hNNI0SPxEvh6kJUmFZjzGU6Cm6Y' \
--form 'description=""' \
--form 'location="{\"latitude\":0,\"longitude\":0}";type=application/json' \
--form 'image=@"/home/guilherme/Downloads/0be6974510aca83e9f11893263037973.jpg"'

Plug parses this and puts it in parameters like:

%{"description" => "", "image" => %Plug.Upload{content_type: "image/jpeg", filename: "0be6974510aca83e9f11893263037973.jpg", path: "/tmp/plug-1638/multipart-1638372306-581957009181399-2"}, "location" => "{ \"latitude\": 0,\"longitude\": 0}"}

What I expected:

%{"description" => "", "image" => %Plug.Upload{content_type: "image/jpeg", filename: "0be6974510aca83e9f11893263037973.jpg", path: "/tmp/plug-1638/multipart-1638372306-581957009181399-2"}, "location" => %{"latitude" => 0,"longitude" => 0}}
josevalim commented 3 years ago

This is expected because we don't support json in multipart. :) How are users sending json encoded multipart? It would be good to know to decide if this is something we should support officially.

josevalim commented 3 years ago

Ah, check this out: https://github.com/elixir-plug/plug/blob/master/lib/plug/parsers/multipart.ex#L35

You can provide a custom function to handle those headers in master. :) So give master a try!

guigaoliveira commented 3 years ago

How are users sending json encoded multipart?

@josevalim I've thought about this form to be submitted using FormData api in front-end, making an asynchronous request, then this field as a json makes sense to me, because Í can centrelize data about "location", but now I remove "location" field and create a "latitude" and "longitude" on form-data.