Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the right way to POST multipart/form-data using curl?

Tags:

post

forms

curl

People also ask

How do you post form data using curl?

To post form data with Curl, you can use one of two command-line parameters: -F (--form) or -d (--data). The -F command-line parameter sends form data with the multipart/form-data content type, and the -d command-line parameter sends form data with the application/x-www-form-urlencoded content type.

How multipart form data is sent?

Multipart form data: The ENCTYPE attribute of <form> tag specifies the method of encoding for the form data. It is one of the two ways of encoding the HTML form. It is specifically used when file uploading is required in HTML form. It sends the form data to server in multiple parts because of large size of file.

How does multipart file upload work?

Multipart upload allows you to upload a single object as a set of parts. Each part is a contiguous portion of the object's data. You can upload these object parts independently and in any order. If transmission of any part fails, you can retransmit that part without affecting other parts.


The following syntax fixes it for you:

curl -v -F key1=value1 -F upload=@localfilename URL

to upload a file using curl in Windows I found that the path requires escaped double quotes

e.g.

curl -v -F 'upload=@\"C:/myfile.txt\"' URL

This is what worked for me

curl --form file='@filename' URL

It seems when I gave this answer (4+ years ago), I didn't really understand the question, or how form fields worked. I was just answering based on what I had tried in a difference scenario, and it worked for me.

So firstly, the only mistake the OP made was in not using the @ symbol before the file name. Secondly, my answer which uses file=... only worked for me because the form field I was trying to do the upload for was called file. If your form field is called something else, use that name instead.

Explanation

From the curl manpages; under the description for the option --form it says:

This enables uploading of binary files etc. To force the 'content' part to be a file, prefix the file name with an @ sign. To just get the content part from a file, prefix the file name with the symbol <. The difference between @ and < is then that @ makes a file get attached in the post as a file upload, while the < makes a text field and just get the contents for that text field from a file.

Chances are that if you are trying to do a form upload, you will most likely want to use the @ prefix to upload the file rather than < which uploads the contents of the file.

Addendum

Now I must also add that one must be careful with using the < symbol because in most unix shells, < is the input redirection symbol [which coincidentally will also supply the contents of the given file to the command standard input of the program before <]. This means that if you do not properly escape that symbol or wrap it in quotes, you may find that your curl command does not behave the way you expect.

On that same note, I will also recommend quoting the @ symbol.


You may also be interested in this other question titled: application/x-www-form-urlencoded or multipart/form-data?

I say this because curl offers other ways of uploading a file, but they differ in the content-type set in the header. For example the --data option offers a similar mechanism for uploading files as data, but uses a different content-type for the upload.

Anyways that's all I wanted to say about this answer since it started to get more upvotes. I hope this helps erase any confusions such as the difference between this answer and the accepted answer. There is really none, except for this explanation.


I had a hard time sending a multipart HTTP PUT request with curl to a Java backend. I simply tried

curl -X PUT URL \
   --header 'Content-Type: multipart/form-data; boundary=---------BOUNDARY' \
   --data-binary @file

and the content of the file was

-----------BOUNDARY
Content-Disposition: form-data; name="name1"
Content-Type: application/xml;version=1.0;charset=UTF-8

<xml>content</xml>
-----------BOUNDARY
Content-Disposition: form-data; name="name2"
Content-Type: text/plain

content
-----------BOUNDARY--

but I always got an error that the boundary was incorrect. After some Java backend debugging I found out that the Java implementation was adding a \r\n-- as a prefix to the boundary, so after changing my input file to

                          <-- here's the CRLF
-------------BOUNDARY       <-- added '--' at the beginning
...
-------------BOUNDARY       <-- added '--' at the beginning
...
-------------BOUNDARY--     <-- added '--' at the beginning

everything works fine!

tl;dr

Add a newline (CRLF \r\n) at the beginning of the multipart boundary content and -- at the beginning of the boundaries and try again.

Maybe you are sending a request to a Java backend that needs this changes in the boundary.