DEV Community

Cover image for Using Libcurl in C/C++ Application
Artem
Artem

Posted on • Updated on

Using Libcurl in C/C++ Application

Client URL, or just curl, is a command-line tool for transferring data using various network protocols. It is commonly used by developers to test various applications build on top of HTTP.

That said, curl itself is just a wrapper around libcurl. The library is written in C and has well documented API. In this post, I will demonstrate how you can use libcurl in order to make HTTP requests from your C/C++ applications.

Before we begin, make sure you have C compiler installed. I will be using gcc. Other compilers will work too, but you will have to modify the provided Makefile. You will also need to have curl and libcurl installed. On Linux and OSX, if you can use curl command in your CLI you should be good to go.

Let's start by creating a simple Makefile:

Makefile

default: build

build: clean
    gcc -Wall -o curl main.c util.c -l curl 

clean:
    rm -rf curl 

test: build
    ./curl https://freegeoip.app/json/ 
Enter fullscreen mode Exit fullscreen mode

Now, moving to the application. It is a simple CLI tool that takes an URL as an argument, makes HTTP Get request, and prints the response.

Here is the code:

main.c

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

int main(int argc, char *argv[]) {
  if( argc != 2 ) {
    printf("usage: try './curl [url]' to make a get request.\n");
    return 1;
  }

  CURL *curl_handle;
  CURLcode res;

  struct MemoryStruct chunk;
  chunk.memory = malloc(1);  
  chunk.size = 0;

  curl_handle = curl_easy_init();
  if(curl_handle) {
    curl_easy_setopt(curl_handle, CURLOPT_URL, argv[1]);
    curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");

    res = curl_easy_perform(curl_handle);

    if(res != CURLE_OK) {
      fprintf(stderr, "error: %s\n", curl_easy_strerror(res));
    } else {
      printf("Size: %lu\n", (unsigned long)chunk.size);
      printf("Data: %s\n", chunk.memory);
    }
    curl_easy_cleanup(curl_handle);
    free(chunk.memory);
  }
  return 0;
}
Enter fullscreen mode Exit fullscreen mode

util.h

#ifndef UTIL_H
#define UTIL_H

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

struct MemoryStruct {
  char *memory;
  size_t size;
};

size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp);

#endif
Enter fullscreen mode Exit fullscreen mode

util.c

#include "util.h"

size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
  size_t realsize = size * nmemb;
  struct MemoryStruct *mem = (struct MemoryStruct *)userp;

  char *ptr = realloc(mem->memory, mem->size + realsize + 1);
  if(ptr == NULL) {
    printf("error: not enough memory\n");
    return 0;
  }

  mem->memory = ptr;
  memcpy(&(mem->memory[mem->size]), contents, realsize);
  mem->size += realsize;
  mem->memory[mem->size] = 0;

  return realsize;
}

Enter fullscreen mode Exit fullscreen mode

The most interesting function here is curl_easy_setopt. It sets various options on the instance of curl client (in my example curl_handle). Note, that by setting CURLOPT_WRITEFUNCTION and CURLOPT_WRITEDATA we have configured the curl_handle to use custom logic and location for writing the response data.

Similarly, you can set custom headers, or HTTP Post payload. For the list of all the available options refer to the curl docs.

Top comments (2)

Collapse
 
trunc8 profile image
trunc8

Thanks for the article! One correction in the Makefile: gcc -Wall -o curl main.c util.c -lcurl
The library linking must be done at the end. Reference

Collapse
 
hi_artem profile image
Artem

Awesome! Thank you for this correction