libcurl: curl as a library

curl · Expert · 12 min

Knowing libcurl explains curl's behaviour and lets you move a working command into application code.

The curl tool is a thin front-end over libcurl, a portable C library used in cars, TVs, game consoles, PHP's curl extension, Python's pycurl, git's HTTP transport and countless apps. Everything a command-line option does maps to a library option.

The easy interface handles one transfer synchronously:

  • curl_easy_init() creates a handle,
  • curl_easy_setopt(h, CURLOPT_URL, ...) and other CURLOPT_* options configure it,
  • curl_easy_perform(h) runs the transfer and returns a CURLcode (the same numbers as the tool's exit codes),
  • curl_easy_cleanup(h) frees it. Reusing a handle for further requests keeps its connection cache.

The multi interface drives many easy handles concurrently in one thread (event-loop style with curl_multi_perform and curl_multi_poll); that is how curl -Z works.

The fastest way to start: build the command you want with the tool, then add --libcurl code.c. curl writes a C program that sets the equivalent options, which is also a great way to learn which CURLOPT matches a flag.

Library defaults differ from the tool in places (for example libcurl does not follow redirects or read .curlrc), and callbacks such as CURLOPT_WRITEFUNCTION receive data in arbitrary-sized chunks, so never assume one callback equals one response.

Example

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

int main(void) {
  curl_global_init(CURL_GLOBAL_DEFAULT);
  CURL *h = curl_easy_init();
  curl_easy_setopt(h, CURLOPT_URL, "https://example.com/");
  curl_easy_setopt(h, CURLOPT_FOLLOWLOCATION, 1L);   /* like -L */
  curl_easy_setopt(h, CURLOPT_TIMEOUT, 20L);         /* like --max-time 20 */
  CURLcode rc = curl_easy_perform(h);                /* body -> stdout */
  long code = 0;
  curl_easy_getinfo(h, CURLINFO_RESPONSE_CODE, &code);
  fprintf(stderr, "rc=%d http=%ld\n", (int)rc, code);  /* rc=0 http=200 */
  curl_easy_cleanup(h);
  curl_global_cleanup();
  return rc != CURLE_OK;
}
/* build: cc get.c -lcurl   |  generate similar code: curl -L --libcurl get.c URL */

Remember

  • easy interface: init, setopt, perform, cleanup
  • multi interface runs many transfers concurrently in one thread
  • --libcurl file.c turns a working command into C code

Watch out for

  • Assuming the write callback receives the whole response at once; it is called with chunks.

Check yourself

  1. What does `curl --libcurl out.c https://example.com` do?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: curl.se/libcurl/c/libcurl-tutorial.html