Synchronous stall execution based curl transfer

#include <curl/curl.h>

	CURL *CurlConnection;
	CURLcode CurlResult;
	struct curl_httppost *CurlFormpost = NULL;
	struct curl_httppost *CurlLastptr = NULL;
	string CurlResponseString;
	long CurlStatus;
	string CurlUrl;


//**************************************************
//**************************************************
//********** CURL WRITE CALLBACK FUNCTION **********
//**************************************************
//**************************************************
static size_t CurlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
	((std::string*)userp)->append((char*)contents, size * nmemb);
	return size * nmemb;
}



//***** MY APPLICAITON CODE *****

	//----- CREATE THE FORM POST DATA -----
	string MyString1 = "Hello";
	string MyString2 = "Test";

	curl_global_init(CURL_GLOBAL_ALL);			//(Doesn't matter if called multiple times)
	CurlFormpost = NULL;						//Ensure we start with these set to NULL if they have been used before
	CurlLastptr = NULL;

	curl_formadd(&CurlFormpost, &CurlLastptr,
		CURLFORM_COPYNAME, "MyFieldName1",
		CURLFORM_COPYCONTENTS, MyString1.c_str(),
		CURLFORM_END);

	curl_formadd(&CurlFormpost, &CurlLastptr,
		CURLFORM_COPYNAME, "MyFieldName2",
		CURLFORM_COPYCONTENTS, MyString1.c_str(),
		CURLFORM_END);

	CurlUrl = "https://mydomain.com/mypage/";

	//----- CONNECT USING CURL -----
	CurlResponseString = "";
	if (CurlConnection = curl_easy_init())
	{
		curl_easy_setopt(CurlConnection, CURLOPT_URL, CurlUrl.c_str());
		curl_easy_setopt(CurlConnection, CURLOPT_CONNECTTIMEOUT, 30L);				//Connect timeout in secs
		curl_easy_setopt(CurlConnection, CURLOPT_TIMEOUT, 30L);						//Maximum time the request is allowed to take in secs
		curl_easy_setopt(CurlConnection, CURLOPT_NOSIGNAL, 1L);						//Avoid threading issues with rest of application threads
		curl_easy_setopt(CurlConnection, CURLOPT_WRITEDATA, &CurlResponseString);
		curl_easy_setopt(CurlConnection, CURLOPT_WRITEFUNCTION, CurlWriteCallback);
		curl_easy_setopt(CurlConnection, CURLOPT_HTTPPOST, CurlFormpost);

		//CONNECT
		CurlResult = curl_easy_perform(CurlConnection);			//<<<<Stalls
		if (CurlResult == CURLE_OK)
		{
			curl_easy_getinfo(CurlConnection, CURLINFO_RESPONSE_CODE, &CurlStatus);
			if (CurlStatus == 200)
			{
				//Success

				//Response from server is in: CurlResponseString

			} //if (CurlStatus == 200)
		} //if (CurlResult == CURLE_OK)

		//CLEAN UP
		curl_easy_cleanup(CurlConnection);
		curl_formfree(CurlFormpost);
	}
Posting a file
	curl_formadd(&CurlFormpost, &CurlLastptr
		CURLFORM_COPYNAME, "MyFieldName",
		CURLFORM_FILE, "myfile.c",
		CURLFORM_END);

Asynchronous background based curl transfer

#include <curl/curl.h>

	CURL *CurlConnection;
	CURLM *CurlMultiHandle;
	CURLcode CurlResult;
	struct curl_httppost *CurlFormpost = NULL;
	struct curl_httppost *CurlLastptr = NULL;
	string CurlUrl;
	string CurlResponseString;
	long CurlStatus;
	int CurlMultiProcessesStillRunning;


//**************************************************
//**************************************************
//********** CURL WRITE CALLBACK FUNCTION **********
//**************************************************
//**************************************************
static size_t CurlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
	((std::string*)userp)->append((char*)contents, size * nmemb);
	return size * nmemb;
}



//***** MY APPLICAITON CODE *****

	//----- CREATE THE FORM POST DATA -----
	string MyString1 = "Hello";
	string MyString2 = "Test";

	curl_global_init(CURL_GLOBAL_ALL);			//(Doesn't matter if called multiple times)
	CurlFormpost = NULL;						//Ensure we start with these set to NULL if they have been used before
	CurlLastptr = NULL;

	curl_formadd(&CurlFormpost, &CurlLastptr,
		CURLFORM_COPYNAME, "MyFieldName1",
		CURLFORM_COPYCONTENTS, MyString1.c_str(),
		CURLFORM_END);

	curl_formadd(&CurlFormpost, &CurlLastptr,
		CURLFORM_COPYNAME, "MyFieldName2",
		CURLFORM_COPYCONTENTS, MyString1.c_str(),
		CURLFORM_END);

	CurlUrl = "https://mydomain.com/mypage/";

	//----- CONNECT USING CURL -----
	CurlResponseString = "";
	CurlMultiHandle = curl_multi_init();		//Create a 'multi handle'
	if (CurlConnection = curl_easy_init())
	{
		curl_easy_setopt(CurlConnection, CURLOPT_URL, ssUrl.str().c_str());
		curl_easy_setopt(CurlConnection, CURLOPT_CONNECTTIMEOUT, 30L);				//Connect timeout in secs
		curl_easy_setopt(CurlConnection, CURLOPT_TIMEOUT, 30L);						//Maximum time the request is allowed to take in secs
		curl_easy_setopt(CurlConnection, CURLOPT_NOSIGNAL, 1L);						//Avoid threading issues with rest of application threads
		curl_easy_setopt(CurlConnection, CURLOPT_WRITEDATA, &CurlResponseString);
		curl_easy_setopt(CurlConnection, CURLOPT_WRITEFUNCTION, CurlWriteCallback);
		curl_easy_setopt(CurlConnection, CURLOPT_WRITEDATA, &CurlResponseString);
		curl_easy_setopt(CurlConnection, CURLOPT_HTTPPOST, CurlFormpost);

		curl_multi_add_handle(CurlMultiHandle, CurlConnection);		//Add this connection to the curl multi handler, this is instead of using the blocking curl_easy_perform() here
		//Calls to curl_multi_perform() will now action this curl request in the background
		//Other curl requests can be added also if you wish and all will be run
	}





//***** POLL TO DO ANY TASKS AND SEE IF COMPLETE *****

	//----- HANDLE CURL PROCESSES IN BACKGROUND -----
	curl_multi_perform(CurlMultiHandle, &CurlMultiProcessesStillRunning);	//Invoke to drive the curl background transfers.
										//Will transfer data if there is anything available to transfer.
										//Will use callbacks and everything else you have setup in the individual easy handles
										//Will transfer data on all current transfers in the multi stack that are ready to transfer anything - may be all, may be none.
										//When there's nothing more to do for now, returns back to the calling application.
	if (CurlMultiProcessesStillRunning == 0)
	{
		//----- CURL HAS COMPELTED ALL ACTIVE PROCESSES  -----
		curl_multi_remove_handle(CurlMultiHandle, CurlConnection);		//Remove handle from the multi stack (can be done at anytime and returns future use of the handle back to synchronous)

		curl_easy_getinfo(CurlConnection, CURLINFO_RESPONSE_CODE, &CurlStatus);
		if (CurlStatus == 200)
		{
			//Success

			//Response from server is in: CurlResponseString

		} //if (CurlStatus == 200)

		//CLEAN UP
		curl_easy_cleanup(CurlConnection);
		curl_formfree(CurlFormpost);
		curl_multi_cleanup(CurlMultiHandle);	//Do after curl_easy_cleanup()
	}

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’ install latest without lots of hassle)

	CURL *CurlConnection;
	curl_mime *CurlMime;
	curl_mimepart *CurlMimePart1;
	curl_mimepart *CurlMimePart2;
	curl_mimepart *CurlMimePart3;

	if (CurlConnection = curl_easy_init())
	{
		curl_easy_setopt(CurlConnection, CURLOPT_URL, ssUrl.str().c_str());
		curl_easy_setopt(CurlConnection, CURLOPT_RETURNTRANSFER, 1L);
		curl_easy_setopt(CurlConnection, CURLOPT_CONNECTTIMEOUT, 30L);			//Connect timeout in secs
		curl_easy_setopt(CurlConnection, CURLOPT_TIMEOUT, 30L);				//Maximum time the request is allowed to take in secs

		CurlMime = curl_mime_init(CurlConnection);

		//ADD POST FIELD
		CurlMimePart1 = curl_mime_addpart(CurlMime);
		curl_mime_name(CurlMimePart1, "MyFieldName1");
		curl_mime_data(CurlMimePart1, MyString1.c_str(), CURL_ZERO_TERMINATED);

		//ADD POST FIELD
		CurlMimePart2 = curl_mime_addpart(CurlMime);
		curl_mime_name(CurlMimePart2, "MyFieldName2");
		curl_mime_data(CurlMimePart2, MyString2.c_str(), CURL_ZERO_TERMINATED);

		curl_easy_setopt(CurlConnection, CURLOPT_MIMEPOST, CurlMime);

		curl_easy_perform(CurlConnection);			//<<<<Stalls


		curl_easy_getinfo(CurlConnection, CURLINFO_RESPONSE_CODE, &CurlStatus);
		if (CurlStatus != 200)
		{
		}
		//Clean-up
		curl_easy_cleanup(CurlConnection);
		curl_mime_free(CurlMime);
	}
Adding a file
CurlMimePart1 = curl_mime_addpart(CurlMime);
curl_mime_name(CurlMimePart1, "files");
curl_mime_filedata(CurlMimePart1, path.c_str());
curl_mime_type(CurlMimePart1, "image/jpeg");
USEFUL?
We benefit hugely from resources on the web so we decided we should try and give back some of our knowledge and resources to the community by opening up many of our company’s internal notes and libraries through mini sites like this. We hope you find the site helpful.
Please feel free to comment if you can add help to this page or point out issues and solutions you have found, but please note that we do not provide support on this site. If you need help with a problem please use one of the many online forums.

Comments

Your email address will not be published. Required fields are marked *