Using libCurl to make web requests from a C++ program

This blog post is to share how to make a C++ program using the libcurl C interface under Windows/Visual Studio, as it is a little non-trivial.

The libcurl API lets you transfer files to a server and call exposed functions outside of a browser context. Because we are using CherryPy with basic user authentication as our web platform, I needed to be able to call various functions such as the one I’m using in this example: “get_result”. The equivalent Linux curl command line would be:

curl --user user:password "httpss://www.insertyourURLhere.com/get_result?id=30417&task=9332"

where obviously you’d change “insertyourURLhere”, use the appropriate user name and password, and I’ve assumed “get_result” takes two arguments, “id” and “task”.

On Windows with Visual Studio, after downloading the libcurl source, you need to first build the libcurl lib. To achieve this, you need to change the C++ Preprocessor definitions by removing “_USRDLL”, and adding instead “CURL_STATICLIB”.

Now, in your own program, add the C++ preprocessor definition “CURL_STATICLIB”, link with libcurl.lib as well as with ws2_32.lib, winmm.lib and wldap32.lib. This will avoid link errors.

The following C++ code shows how to make requests to the web server “get_result” function, using HTTP POST. It demonstrates using a callback function (to retrieve the text of the server’s response), passing the URL encoded arguments (encoded using curl_easy_escape), authenticating using basic authentication, and gathering timing diagnostics.


#include "curl.h"

using namespace std;

#define YOUR_URL "https://www.insertyourURLhere.com/"
#define USER_AND_PWD "user:password"

static string gs_strLastResponse;

// Callback to gather the response from the server.  Comes in chunks (typically 16384 characters at a time), so needs to be stitched together.
size_t function_pt(void *ptr, size_t size, size_t nmemb, void * /*stream*/)
{
 gs_strLastResponse += (const char*)ptr;
 return size * nmemb;
}

bool CallServerWithCurl(string strData1, strData2, string& strErrorDescription)
{
 CURL* curl = curl_easy_init();
 if (curl == NULL)
 {
     strErrorDescription = "Unable to initialise Curl";
     return false;
 }

 curl_easy_setopt(curl, CURLOPT_URL, (YOUR_URL + "get_result").c_str());
 curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
 curl_easy_setopt(curl, CURLOPT_USERPWD, MY_USER_AND_PWD);    // set user name and password for the authentication

 char* data1 = curl_easy_escape(curl, strData1.c_str(), 0);
 char* data2 = curl_easy_escape(curl, strData2.c_str(), 0);
 string strArguments = "id=" + data1 + "&task=" + data2;
 const char* my_data = strArguments.c_str();

 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, my_data);
 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(my_data));   // if we don't provide POSTFIELDSIZE, libcurl will strlen() by itself

 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);     // enable verbose for easier tracing

  gs_strLastResponse = "";
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, function_pt);        // set a callback to capture the server's response

 CURLcode res = curl_easy_perform(curl);

 // we have to call twice, first call authenticates, second call does the work
 res = curl_easy_perform(curl);

 if (res != CURLE_OK)
 {
     strErrorDescription = "Curl call to server failed";
     return false;
 }
 if (!DoSomethingWithServerResponse(gs_strLastResponse))
 {
     strErrorDescription = "Curl call to server returned an unexpected response";
     return false;
 }

 // extract some transfer info
 double speed_upload, total_time;
 curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &speed_upload);
 curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
 fprintf(stderr, "Speed: %.3f bytes/sec during %.3f seconds\n", speed_upload, total_time);

 curl_easy_cleanup(curl);

 return true;
}

Libcurl building and linking tips were found at http://curl.haxx.se/mail/lib-2007-04/0120.html and elsewhere.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published.