{"id":3318,"date":"2020-07-24T07:39:15","date_gmt":"2020-07-24T07:39:15","guid":{"rendered":"https:\/\/raspberry-projects.com\/pi\/?p=3318"},"modified":"2020-07-30T13:54:43","modified_gmt":"2020-07-30T13:54:43","slug":"post-multipart-form-data","status":"publish","type":"post","link":"https:\/\/raspberry-projects.com\/pi\/programming-in-c\/networking\/curl\/post-multipart-form-data","title":{"rendered":"POST multipart form data"},"content":{"rendered":"\n<h4 class=\"wp-block-heading\">Synchronous stall execution based curl transfer<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;curl\/curl.h>\n\n\tCURL *CurlConnection;\n\tCURLcode CurlResult;\n\tstruct curl_httppost *CurlFormpost = NULL;\n\tstruct curl_httppost *CurlLastptr = NULL;\n\tstring CurlResponseString;\n\tlong CurlStatus;\n\tstring CurlUrl;\n\n\n\/\/**************************************************\n\/\/**************************************************\n\/\/********** CURL WRITE CALLBACK FUNCTION **********\n\/\/**************************************************\n\/\/**************************************************\nstatic size_t CurlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp)\n{\n\t((std::string*)userp)->append((char*)contents, size * nmemb);\n\treturn size * nmemb;\n}\n\n\n\n\/\/***** MY APPLICAITON CODE *****\n\n\t\/\/----- CREATE THE FORM POST DATA -----\n\tstring MyString1 = \"Hello\";\n\tstring MyString2 = \"Test\";\n\n\tcurl_global_init(CURL_GLOBAL_ALL);\t\t\t\/\/(Doesn't matter if called multiple times)\n\tCurlFormpost = NULL;\t\t\t\t\t\t\/\/Ensure we start with these set to NULL if they have been used before\n\tCurlLastptr = NULL;\n\n\tcurl_formadd(&amp;CurlFormpost, &amp;CurlLastptr,\n\t\tCURLFORM_COPYNAME, \"MyFieldName1\",\n\t\tCURLFORM_COPYCONTENTS, MyString1.c_str(),\n\t\tCURLFORM_END);\n\n\tcurl_formadd(&amp;CurlFormpost, &amp;CurlLastptr,\n\t\tCURLFORM_COPYNAME, \"MyFieldName2\",\n\t\tCURLFORM_COPYCONTENTS, MyString1.c_str(),\n\t\tCURLFORM_END);\n\n\tCurlUrl = \"https:\/\/mydomain.com\/mypage\/\";\n\n\t\/\/----- CONNECT USING CURL -----\n\tCurlResponseString = \"\";\n\tif (CurlConnection = curl_easy_init())\n\t{\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_URL, CurlUrl.c_str());\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_CONNECTTIMEOUT, 30L);\t\t\t\t\/\/Connect timeout in secs\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_TIMEOUT, 30L);\t\t\t\t\t\t\/\/Maximum time the request is allowed to take in secs\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_NOSIGNAL, 1L);\t\t\t\t\t\t\/\/Avoid threading issues with rest of application threads\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_WRITEDATA, &amp;CurlResponseString);\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_WRITEFUNCTION, CurlWriteCallback);\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_HTTPPOST, CurlFormpost);\n\n\t\t\/\/CONNECT\n\t\tCurlResult = curl_easy_perform(CurlConnection);\t\t\t\/\/&lt;&lt;&lt;&lt;Stalls\n\t\tif (CurlResult == CURLE_OK)\n\t\t{\n\t\t\tcurl_easy_getinfo(CurlConnection, CURLINFO_RESPONSE_CODE, &amp;CurlStatus);\n\t\t\tif (CurlStatus == 200)\n\t\t\t{\n\t\t\t\t\/\/Success\n\n\t\t\t\t\/\/Response from server is in: CurlResponseString\n\n\t\t\t} \/\/if (CurlStatus == 200)\n\t\t} \/\/if (CurlResult == CURLE_OK)\n\n\t\t\/\/CLEAN UP\n\t\tcurl_easy_cleanup(CurlConnection);\n\t\tcurl_formfree(CurlFormpost);\n\t}<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">Posting a file<\/h5>\n\n\n\n<pre class=\"wp-block-code\"><code>\tcurl_formadd(&amp;CurlFormpost, &amp;CurlLastptr\n\t\tCURLFORM_COPYNAME, \"MyFieldName\",\n\t\tCURLFORM_FILE, \"myfile.c\",\n\t\tCURLFORM_END);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Asynchronous background based curl transfer<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;curl\/curl.h>\n\n\tCURL *CurlConnection;\n\tCURLM *CurlMultiHandle;\n\tCURLcode CurlResult;\n\tstruct curl_httppost *CurlFormpost = NULL;\n\tstruct curl_httppost *CurlLastptr = NULL;\n\tstring CurlUrl;\n\tstring CurlResponseString;\n\tlong CurlStatus;\n\tint CurlMultiProcessesStillRunning;\n\n\n\/\/**************************************************\n\/\/**************************************************\n\/\/********** CURL WRITE CALLBACK FUNCTION **********\n\/\/**************************************************\n\/\/**************************************************\nstatic size_t CurlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp)\n{\n\t((std::string*)userp)->append((char*)contents, size * nmemb);\n\treturn size * nmemb;\n}\n\n\n\n\/\/***** MY APPLICAITON CODE *****\n\n\t\/\/----- CREATE THE FORM POST DATA -----\n\tstring MyString1 = \"Hello\";\n\tstring MyString2 = \"Test\";\n\n\tcurl_global_init(CURL_GLOBAL_ALL);\t\t\t\/\/(Doesn't matter if called multiple times)\n\tCurlFormpost = NULL;\t\t\t\t\t\t\/\/Ensure we start with these set to NULL if they have been used before\n\tCurlLastptr = NULL;\n\n\tcurl_formadd(&amp;CurlFormpost, &amp;CurlLastptr,\n\t\tCURLFORM_COPYNAME, \"MyFieldName1\",\n\t\tCURLFORM_COPYCONTENTS, MyString1.c_str(),\n\t\tCURLFORM_END);\n\n\tcurl_formadd(&amp;CurlFormpost, &amp;CurlLastptr,\n\t\tCURLFORM_COPYNAME, \"MyFieldName2\",\n\t\tCURLFORM_COPYCONTENTS, MyString1.c_str(),\n\t\tCURLFORM_END);\n\n\tCurlUrl = \"https:\/\/mydomain.com\/mypage\/\";\n\n\t\/\/----- CONNECT USING CURL -----\n\tCurlResponseString = \"\";\n\tCurlMultiHandle = curl_multi_init();\t\t\/\/Create a 'multi handle'\n\tif (CurlConnection = curl_easy_init())\n\t{\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_URL, ssUrl.str().c_str());\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_CONNECTTIMEOUT, 30L);\t\t\t\t\/\/Connect timeout in secs\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_TIMEOUT, 30L);\t\t\t\t\t\t\/\/Maximum time the request is allowed to take in secs\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_NOSIGNAL, 1L);\t\t\t\t\t\t\/\/Avoid threading issues with rest of application threads\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_WRITEDATA, &amp;CurlResponseString);\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_WRITEFUNCTION, CurlWriteCallback);\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_WRITEDATA, &amp;CurlResponseString);\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_HTTPPOST, CurlFormpost);\n\n\t\tcurl_multi_add_handle(CurlMultiHandle, CurlConnection);\t\t\/\/Add this connection to the curl multi handler, this is instead of using the blocking curl_easy_perform() here\n\t\t\/\/Calls to curl_multi_perform() will now action this curl request in the background\n\t\t\/\/Other curl requests can be added also if you wish and all will be run\n\t}\n\n\n\n\n\n\/\/***** POLL TO DO ANY TASKS AND SEE IF COMPLETE *****\n\n\t\/\/----- HANDLE CURL PROCESSES IN BACKGROUND -----\n\tcurl_multi_perform(CurlMultiHandle, &amp;CurlMultiProcessesStillRunning);\t\/\/Invoke to drive the curl background transfers.\n\t\t\t\t\t\t\t\t\t\t\/\/Will transfer data if there is anything available to transfer.\n\t\t\t\t\t\t\t\t\t\t\/\/Will use callbacks and everything else you have setup in the individual easy handles\n\t\t\t\t\t\t\t\t\t\t\/\/Will transfer data on all current transfers in the multi stack that are ready to transfer anything - may be all, may be none.\n\t\t\t\t\t\t\t\t\t\t\/\/When there's nothing more to do for now, returns back to the calling application.\n\tif (CurlMultiProcessesStillRunning == 0)\n\t{\n\t\t\/\/----- CURL HAS COMPELTED ALL ACTIVE PROCESSES  -----\n\t\tcurl_multi_remove_handle(CurlMultiHandle, CurlConnection);\t\t\/\/Remove handle from the multi stack (can be done at anytime and returns future use of the handle back to synchronous)\n\n\t\tcurl_easy_getinfo(CurlConnection, CURLINFO_RESPONSE_CODE, &amp;CurlStatus);\n\t\tif (CurlStatus == 200)\n\t\t{\n\t\t\t\/\/Success\n\n\t\t\t\/\/Response from server is in: CurlResponseString\n\n\t\t} \/\/if (CurlStatus == 200)\n\n\t\t\/\/CLEAN UP\n\t\tcurl_easy_cleanup(CurlConnection);\n\t\tcurl_formfree(CurlFormpost);\n\t\tcurl_multi_cleanup(CurlMultiHandle);\t\/\/Do after curl_easy_cleanup()\n\t}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Using mimepart instead formadd<\/h4>\n\n\n\n<p><strong><em>The curl MIME API was added to curl version 7.56.0 (it is not supported by earlier versions, e.g. Raspbian Stretch has curl 7.52.1. and wont&#8217; install latest without lots of hassle)<\/em><\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\tCURL *CurlConnection;\n\tcurl_mime *CurlMime;\n\tcurl_mimepart *CurlMimePart1;\n\tcurl_mimepart *CurlMimePart2;\n\tcurl_mimepart *CurlMimePart3;\n\n\tif (CurlConnection = curl_easy_init())\n\t{\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_URL, ssUrl.str().c_str());\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_RETURNTRANSFER, 1L);\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_CONNECTTIMEOUT, 30L);\t\t\t\/\/Connect timeout in secs\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_TIMEOUT, 30L);\t\t\t\t\/\/Maximum time the request is allowed to take in secs\n\n\t\tCurlMime = curl_mime_init(CurlConnection);\n\n\t\t\/\/ADD POST FIELD\n\t\tCurlMimePart1 = curl_mime_addpart(CurlMime);\n\t\tcurl_mime_name(CurlMimePart1, \"MyFieldName1\");\n\t\tcurl_mime_data(CurlMimePart1, MyString1.c_str(), CURL_ZERO_TERMINATED);\n\n\t\t\/\/ADD POST FIELD\n\t\tCurlMimePart2 = curl_mime_addpart(CurlMime);\n\t\tcurl_mime_name(CurlMimePart2, \"MyFieldName2\");\n\t\tcurl_mime_data(CurlMimePart2, MyString2.c_str(), CURL_ZERO_TERMINATED);\n\n\t\tcurl_easy_setopt(CurlConnection, CURLOPT_MIMEPOST, CurlMime);\n\n\t\tcurl_easy_perform(CurlConnection);\t\t\t\/\/&lt;&lt;&lt;&lt;Stalls\n\n\n\t\tcurl_easy_getinfo(CurlConnection, CURLINFO_RESPONSE_CODE, &amp;CurlStatus);\n\t\tif (CurlStatus != 200)\n\t\t{\n\t\t}\n\t\t\/\/Clean-up\n\t\tcurl_easy_cleanup(CurlConnection);\n\t\tcurl_mime_free(CurlMime);\n\t}<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">Adding a file<\/h5>\n\n\n\n<pre class=\"wp-block-code\"><code>CurlMimePart1 = curl_mime_addpart(CurlMime);\ncurl_mime_name(CurlMimePart1, \"files\");\ncurl_mime_filedata(CurlMimePart1, path.c_str());\ncurl_mime_type(CurlMimePart1, \"image\/jpeg\");<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Synchronous stall execution based curl transfer Posting a file Asynchronous background based curl transfer Using mimepart instead formadd The curl MIME API was added to curl version 7.56.0 (it is not supported by earlier versions, e.g. Raspbian Stretch has curl 7.52.1. and wont&#8217; install latest without lots of hassle) Adding a file<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[161],"tags":[],"class_list":["post-3318","post","type-post","status-publish","format-standard","hentry","category-curl"],"_links":{"self":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts\/3318","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/comments?post=3318"}],"version-history":[{"count":28,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts\/3318\/revisions"}],"predecessor-version":[{"id":3399,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts\/3318\/revisions\/3399"}],"wp:attachment":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/media?parent=3318"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/categories?post=3318"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/tags?post=3318"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}