curl / Mailing Lists / curl-library / Single Mail
Buy commercial curl support from WolfSSL. We help you work out your issues, debug your libcurl applications, use the API, port to new platforms, add new features and more. With a team lead by the curl founder himself.

Re: Upload multipart with cURL & json & custom headers

From: Aleksandar Lazic via curl-library <>
Date: Thu, 23 Jun 2022 12:45:45 +0200


On Thu, 23 Jun 2022 09:08:13 +0000 (UTC)
Taw via curl-library <> wrote:

> Hello,
> I am trying to do a multipart/form-data upload with cURL + json + custom
> headers and I am not sure how to do it properly. I want something equivalent
> to this cmdline command: curl -H 'Content-Type: multipart/form-data' -H
> 'x-custom-header: custom value' https://url_to_upload -F
> "file=_at_file_to_upload" -F "params=_at_params.json"
> For simple POST requests, I am doing this and works:
> curl_slist_append(headers, "Content-type: application/json")
> curl_slist_append(headers, "x-custom-header: custom value")
> curl_easy_setopt(CURLOPT_HTTPHEADER, headers);
> curl_easy_setopt(CURLOPT_POSTFIELDS, json_str);
> I read, but still not sure how to send
> the json and the headers for multipart upload. 1. For JSON should I use
> CURLOPT_POSTFIELDS or curl_mime_addpart/curl_mime_name/curl_mime_data?2. For
> headers should I use CURLOPT_HTTPHEADER or curl_mime_headers?3. Can I reuse a
> mime handle for multiple files? Is there any way to reset it, so I won't do
> curl_mime_init/curl_mime_free for each file? thank you

Have you tried to use the option --libcurl to create the code?

curl -H 'Content-Type: multipart/form-data' \
     -H 'x-custom-header: custom value' \
     -F "file=_at_file_to_upload" \
     -F "params=_at_params.json" \
     --libcurl libcurl-code.c \

This is the output from that curl version
curl --version
curl 7.68.0 (x86_64-pc-linux-gnu) libcurl/7.68.0 OpenSSL/1.1.1f zlib/1.2.11 \
brotli/1.0.7 libidn2/2.2.0 libpsl/0.21.0 (+libidn2/2.2.0) \
libssh/0.9.3/openssl/zlib nghttp2/1.40.0 librtmp/2.3 \
Release-Date: 2020-01-08
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 \
pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS brotli GSS-API HTTP2 HTTPS-proxy IDN IPv6 Kerberos \
Largefile libz NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets

What I have seen is if the files not exist will the created code be different,
so use existing files with '_at_'!

/********* Sample code generated by the curl command line tool **********
 * All curl_easy_setopt() options are documented at:
#include <curl/curl.h>

int main(int argc, char *argv[])
  CURLcode ret;
  CURL *hnd;
  curl_mime *mime1;
  curl_mimepart *part1;
  struct curl_slist *slist1;

  mime1 = NULL;
  slist1 = NULL;
  slist1 = curl_slist_append(slist1, "Content-Type: multipart/form-data");
  slist1 = curl_slist_append(slist1, "x-custom-header: custom value");

  hnd = curl_easy_init();
  curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
  curl_easy_setopt(hnd, CURLOPT_URL, "https://url_to_upload");
  curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
  mime1 = curl_mime_init(hnd);
  part1 = curl_mime_addpart(mime1);
  curl_mime_filedata(part1, "file_to_upload");
  curl_mime_name(part1, "file");
  part1 = curl_mime_addpart(mime1);
  curl_mime_filedata(part1, "params.json");
  curl_mime_name(part1, "params");
  curl_easy_setopt(hnd, CURLOPT_MIMEPOST, mime1);
  curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, slist1);
  curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.68.0");
  curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
  curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
  curl_easy_setopt(hnd, CURLOPT_SSH_KNOWNHOSTS, ".../.ssh/known_hosts");
  curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
  curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);

  /* Here is a list of options the curl code used that cannot get generated
     as source easily. You may select to either not use them or implement
     them yourself.

  CURLOPT_WRITEDATA set to a objectpointer
  CURLOPT_INTERLEAVEDATA set to a objectpointer
  CURLOPT_WRITEFUNCTION set to a functionpointer
  CURLOPT_READDATA set to a objectpointer
  CURLOPT_READFUNCTION set to a functionpointer
  CURLOPT_SEEKDATA set to a objectpointer
  CURLOPT_SEEKFUNCTION set to a functionpointer
  CURLOPT_ERRORBUFFER set to a objectpointer
  CURLOPT_STDERR set to a objectpointer
  CURLOPT_HEADERFUNCTION set to a functionpointer
  CURLOPT_HEADERDATA set to a objectpointer


  ret = curl_easy_perform(hnd);

  hnd = NULL;
  mime1 = NULL;
  slist1 = NULL;

  return (int)ret;
/**** End of sample code ****/

Received on 2022-06-23