Formatting Multipart Formdata in Erlang
I was having trouble finding examples of formatting a multipart formdata request in Erlang which allowed the sending of multiple post parameters along with one or more attached files in a single message. The http module solves a number of problems, but I couldn't figure out a way it solved this one.
Fortunately it was easy enough to find a reference implementation in Python and I somewhat crudely copied it over into Erlang. The end result is below.
%% @doc encode fields and file for HTTP post multipart/form-data.
%% @reference Inspired by <a href="http://code.activestate.com/recipes/146306/">Python implementation</a>.
format_multipart_formdata(Boundary, Fields, Files) ->
FieldParts = lists:map(fun({FieldName, FieldContent}) ->
[lists:concat(["--", Boundary]),
lists:concat(["Content-Disposition: form-data; name=\"",atom_to_list(FieldName),"\""]),
"",
FieldContent]
end, Fields),
FieldParts2 = lists:append(FieldParts),
FileParts = lists:map(fun({FieldName, FileName, FileContent}) ->
[lists:concat(["--", Boundary]),
lists:concat(["Content-Disposition: format-data; name=\"",atom_to_list(FieldName),"\"; filename=\"",FileName,"\""]),
lists:concat(["Content-Type: ", "application/octet-stream"]),
"",
FileContent]
end, Files),
FileParts2 = lists:append(FileParts),
EndingParts = [lists:concat(["--", Boundary, "--"]), ""],
Parts = lists:append([FieldParts2, FileParts2, EndingParts]),
string:join(Parts, "\r\n").
Usage looks like:
Data = binary_to_list(file:read_file("/path/to/a/file")),
URL = "http://localhost.com/some/place/",
Boundary = "------------a450glvjfEoqerAc1p431paQlfDac152cadADfd",
Body = format_multipart_formdata(Boundary, [{task_id, TaskId}, {position, Position}], [{file, "file", Data}]),
ContentType = lists:concat(["multipart/form-data; boundary=", Boundary]),
Headers = [{"Content-Length", integer_to_list(length(Body))}],
http:request(post, {URL, Headers, ContentType, Body}, [], []).
Is there a better way to do this somewhere in the http module? I'd be glad to know of it and to throw out this hacky and not-exactly-high-performance implementation.