Make Http Request Using Libcurl

What is Libcurl?

Libcurl is a client side url transfer library that supports various protocols. It is the library behind the command line utility curl

Installing Libcurl

You will find packages for libcurl in all of the available linux distributions.

To install libcurl on

Using Libcurl

To make an HTTP request using libcurl, you need to do following thigs.

  1. Setup the program enviornment that libcurl needs.
  2. Initialize curl handle.
  3. Set request options.
  4. Perform request.
  5. Performa cleanup.

Settingup the program enviornment for libcurl.

The curl enviornment is setup by calling the function curl_global_init.

#include<curl/curl.h>
curl_global_init (CURL_GLOBAL_ALL)

Initializing curl handle.

To initialize curl handle the function is curl_easy_init. This function must be the first function to call, and it returns a CURL easy handle that you must use as input to other functions in the easy interface. This call MUST have a corresponding call to curl_easy_cleanup when the operation is complete.

CURL *curl_handle = curl_easy_init ();

Setting request options.

To set the request options, libcurl provides a function; curl_easy_setopt. To make an HTTP GET request, you need to set four options using this function.

  1. url: the url to which you want to make a request.
  2. write functoion: a function which will be called to write response data into the memory buffer after permorming http get.
  3. pointer to your memory buffer: this will be passed to the callback function (your write function).
  4. user agent: the user agent string.
struct memory_struct {
    char *buffer;
    size_t size;
}
static size_t
mem_write(void *contents, size_t size, size_t nmemb, void *userp);

char *url = "https://girishjoshi.io";

struct memory_struct *mem;
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, mem_write);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)mem);
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "custom-agent");

The callback function for writing response to the memory buffer.

// write response data to the memory buffer.
static size_t
mem_write (void *contents, size_t size, size_t nmemb, void *userp){
    // initialize memory_struct
    size_t realsize = size * nmemb;
    struct memory_struct *mem = (struct memory_struct *)userp;
    
    char *ptr = realloc (mem->buffer, mem->size + realsize + 1);
    if(ptr == NULL) {
        /* out of memory! */
        printf ("not enough memory (realloc returned NULL)\n");
        return 0;
    }

    // copy the response contents to memory_struct buffer.
    mem->buffer = ptr;
    memcpy (&(mem->buffer[mem->size]), contents, realsize);
    mem->size += realsize;
    mem->buffer[mem->size] = 0;

    // return the size of content that is copied.
    return realsize;
}

The complete code looks like

#include<stdio.h>
#include<stdlib.h>
#include<curl/curl.h>
#include<string.h>

char *url = NULL;

// struct for holding http response.
struct memory_struct{
    char   *buffer;
    size_t size;
};

// write response data to the memory buffer.
static size_t
mem_write(void *contents, size_t size, size_t nmemb, void *userp){
    // initialize memory_struct
    size_t realsize = size * nmemb;
    struct memory_struct *mem = (struct memory_struct *)userp;
    
    char *ptr = realloc(mem->buffer, mem->size + realsize + 1);
    if(ptr == NULL) {
        /* out of memory! */
        printf("not enough memory (realloc returned NULL)\n");
        return 0;
    }

    // copy the response contents to memory_struct buffer.
    mem->buffer = ptr;
    memcpy(&(mem->buffer[mem->size]), contents, realsize);
    mem->size += realsize;
    mem->buffer[mem->size] = 0;

    // return the size of content that is copied.
    return realsize;
}

void http_get(char *url, struct memory_struct *mem){
    CURL *curl_handle;
    CURLcode res;
    
    mem->buffer = malloc(1);
    mem->size   = 0;
    
    curl_global_init(CURL_GLOBAL_ALL);

    // initialize curl
    curl_handle = curl_easy_init();

    // specify url, callback function to receive response, buffer to hold
    // response and lastly user agent for http request.
    curl_easy_setopt(curl_handle, CURLOPT_URL, url);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, mem_write);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)mem);
    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "custom-agent");
 
    // make the http request.
    res = curl_easy_perform(curl_handle);
 
    // check for errors.
    if(res != CURLE_OK){
        fprintf(stderr, "curl_easy_perform() failed: %s\n", 
                curl_easy_strerror(res));
    }
 
    // cleanup
    curl_easy_cleanup(curl_handle);
    curl_global_cleanup();
}

int main(int argc, char** args){
    // check number of arguments.
    if(argc < 2){
        printf("need url to make http request.\n");
        return 0;
    }

    url = args[1];

    printf("trying to make http request to: %s\n", url);
    struct memory_struct m;
    http_get(url, &m);
    printf("\nresponse:\n%s", m.buffer);
    return 0;

To compile this code

$ gcc -o http-req http-req.c -lcurl

To run this code

$ ./http-req wttr.in/~Eiffel+Tower?format=j1
trying to make http request to: wttr.in/~Eiffel+Tower?format=j1

 response:
{
    "current_condition": [
        {
            "FeelsLikeC": "9", 
            "FeelsLikeF": "48", 
            "cloudcover": "75", 
            "humidity": "87", 
            "observation_time": "07:44 AM", 
            "precipMM": "0.0", 
            "pressure": "1004", 
            "temp_C": "11", 
            "temp_F": "52", 
            "uvIndex": 4, 
            "visibility": "10", 
            "weatherCode": "116", 
            "weatherDesc": [
                {
                    "value": "Partly cloudy"
                }
            ], 
            "weatherIconUrl": [
                {
                    "value": ""
                }
            ], 
            "winddir16Point": "SSW", 
            "winddirDegree": "200", 
            "windspeedKmph": "19", 
            "windspeedMiles": "12"
        }
    ], 
    "request": [
        {
            "query": "Lat 48.86 and Lon 2.29", 
            "type": "LatLon"
        }
    ],
    .....
}