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

260,793

Solution 1

The following syntax fixes it for you:

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

Solution 2

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

Solution 3

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.

Solution 4

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.

Solution 5

On Windows 10, curl 7.28.1 within powershell, I found the following to work for me:

$filePath = "c:\temp\dir with spaces\myfile.wav"
$curlPath = ("myfilename=@" + $filePath)
curl -v -F $curlPath URL
Share:
260,793

Related videos on Youtube

Kamalakshi
Author by

Kamalakshi

Updated on July 08, 2022

Comments

  • Kamalakshi
    Kamalakshi almost 2 years

    I used this syntax to post a file along with some parameters:

    curl -v -include --form "key1=value1" --form upload=localfilename URL
    

    The file is around 500K in size. First of all, I see content length to be 254 on the transmit side. Later the server response's content length is 0. Where am I going wrong?

    Here is the complete trace of the command.

    * Couldn't find host xxx.xxx.xxx.xxx in the _netrc file; using defaults
    * About to connect() to xxx.xxx.xxx.xxx port yyyy (#0)
    *   Trying xxx.xxx.xxx.xxx...
    * Adding handle: conn: 0x4b96a0
    * Adding handle: send: 0
    * Adding handle: recv: 0
    * Curl_addHandleToPipeline: length: 1
    * - Conn 0 (0x4b96a0) send_pipe: 1, recv_pipe: 0
    * Connected to xxx.xxx.xxx.xxx (xxx.xxx.xxx.xxx) port yyyy (#0)
    * POST /zzzzzz/UploadFile HTTP/1.1
    * User-Agent: curl/7.32.0
    * Host: xxx.xxx.xxx.xxx:yyyy
    * Accept: */*
    * Content-Length: 254
    * Expect: 100-continue
    * Content-Type: multipart/form-data; boundary=------------------------948a6137eef50079
    *
    * HTTP/1.1 100 Continue
    * HTTP/1.1 100 Continue
    
    * HTTP/1.1 200 OK
    * HTTP/1.1 200 OK
    * Server Apache-Coyote/1.1 is not blacklisted
    * Server: Apache-Coyote/1.1
    * Server: Apache-Coyote/1.1
    * Added cookie JSESSIONID="C1D7DD042E250211D9DEA82688876F88" for domain xxx.xxx.xxx.xxx, path /zzzzz/, expire 0
    * Set-Cookie: JSESSIONID=C1D7DD042E250211D9DEA82688876F88; Path=/zzzzzz/;
    * HttpOnly
    * Set-Cookie: JSESSIONID=C1D7DD042E250211D9DEA82688876F88; Path=/zzzzzz/; HttpOnly
    * Content-Type: text/html;charset=ISO-8859-1
    Content-Type: text/html;charset=ISO-8859-1
    * Content-Length: 0
    * Content-Length: 0
    * Date: Tue, 01 Oct 2013 11:54:24 GMT
    * Date: Tue, 01 Oct 2013 11:54:24 GMT
    * Connection #0 to host xxx.xxx.xxx.xxx left intact
    
  • Piotr
    Piotr almost 9 years
    what about Windows & curl.exe ?
  • hellboy
    hellboy over 8 years
    what about multiple attachments?
  • Daniel Stenberg
    Daniel Stenberg about 8 years
    It works exactly the same on Windows and.it supports multiple "attachments"/files: just add more -F instances!
  • bmoran
    bmoran about 7 years
    This answer has a good example of uploading multiple files. stackoverflow.com/questions/11599957/…
  • Emily
    Emily about 5 years
    This works. on curl we do not need to add something like this: -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
  • ivkremer
    ivkremer almost 5 years
    This answer helped me a lot. Though in my case I should not escape ", that is in my case on Mac I should send it like curl -X POST -F key1=value1 -F 'image=@"/Users/ivkremer/Downloads/file name.jpg"';
  • baptx
    baptx almost 5 years
    When copying POST data with Firefox web console, I also noticed that it was using \n instead of \r\n. Even mitmproxy copy as cURL was using \n so I had to copy the raw request with mitmproxy. I saw with hexdump that it was using hex code 0A instead of 0D 0A.
  • Adham Zahran
    Adham Zahran about 4 years
    the \r\n is required. Look at tools.ietf.org/html/rfc2046#section-5.1.1 page 19.
  • chatlanin
    chatlanin about 4 years
    in my case - I had a success transfer without any quotes : curl -v -F file=@/Users/path/to/file/testq.jpg 192.168.0.101:8080/upload-image
  • Beems
    Beems about 4 years
    In my case in Windows, I could not use the single quotes and had to use double quotes like this curl -F "filename=@\"C:\temp\file.jpg\"" https://someurl.com
  • edusanketdk
    edusanketdk over 2 years
    clearly the OP is asking for multipart form data, not application urlencoded
  • ZiTAL
    ZiTAL over 2 years
    @hellboy "upload" is the field name, add other one with other field name
  • shrekuu
    shrekuu almost 2 years