curl/curl
libcurl
Active contributors: Daniel Stenberg, Viktor Szakats, Stefan Eissing, Jay Satiro
Purpose
libcurl is curl's portable C library for transferring data with URLs. It is reentrant, thread-safe (when used with care — one easy handle per thread), supports concurrent transfers via the multi interface, and has a stable API and ABI: SONAME 4 since 2006, no public-API removals, ~308 curl_easy_setopt() options as of late 2025.
Public surface
All public symbols live in include/curl/:
| Header | Contents |
|---|---|
include/curl/curl.h |
Easy interface, options enum, CURLcode, callbacks |
include/curl/easy.h |
Easy-interface convenience functions |
include/curl/multi.h |
Multi interface, curl_multi_*, curl_socket_* |
include/curl/urlapi.h |
URL parser/builder API |
include/curl/header.h |
HTTP-header inspection API |
include/curl/websockets.h |
WebSocket framing API |
include/curl/options.h |
Programmatic option metadata (typeof, name, ID) |
include/curl/system.h |
curl_off_t and platform-specific integer typedefs |
include/curl/typecheck-gcc.h |
Compile-time typecheck shims for curl_easy_setopt |
include/curl/mprintf.h |
Project's printf, exported for embedders |
include/curl/curlver.h |
Version macros (LIBCURL_VERSION_*) |
include/curl/stdcheaders.h |
Header-include compatibility shim |
The library exports its entire public API via lib/libcurl.def and lib/libcurl.vers.in.
Directory layout
The implementation under lib/ has ~184 .c and ~178 .h files, divided by purpose. The largest are:
| File | Purpose |
|---|---|
lib/url.c (113 KB) |
Setup, teardown, scheme dispatch, connection-cache lookups |
lib/multi.c (128 KB) |
The multi state machine — the heart of the library |
lib/easy.c |
The blocking wrappers around the multi interface |
lib/transfer.c |
The per-transfer outer loop (SINGLEREQUEST etc.) |
lib/setopt.c (84 KB) |
Dispatch for every curl_easy_setopt value |
lib/getinfo.c |
Dispatch for curl_easy_getinfo |
lib/easyoptions.c |
Auto-generated option metadata table |
lib/cfilters.c |
Connection filter framework |
lib/conncache.c |
Connection cache + pooling |
lib/connect.c |
TCP connection establishment |
lib/cf-socket.c (69 KB) |
Socket-level connection filter |
lib/dnscache.c |
Resolved-address cache |
lib/hostip.c |
DNS resolution glue (sync + async dispatch) |
lib/asyn-ares.c |
c-ares async resolver backend |
lib/asyn-thrdd.c |
Thread-pool async resolver backend |
lib/doh.c |
DNS-over-HTTPS resolver |
lib/sendf.c (40 KB) |
Send/recv plumbing, "client write" pipeline |
lib/cw-out.c, lib/cw-pause.c |
Client-write filters (decompress, pause) |
lib/content_encoding.c |
gzip / deflate / brotli / zstd |
lib/headers.c |
HTTP-header inspection API implementation |
lib/cookie.c |
Cookie engine |
lib/hsts.c |
HSTS cache |
lib/altsvc.c |
Alt-Svc cache |
lib/urlapi.c (56 KB) |
URL parser/builder (curl_url_*) |
lib/mime.c (62 KB) |
Multipart/MIME builder |
lib/formdata.c |
Legacy curl_formadd (deprecated, kept for ABI) |
lib/version.c |
curl_version_info() and version string assembly |
lib/share.c / lib/curl_share.c |
Share-handle implementation |
lib/curl_setup.h (48 KB) |
Compile-time configuration: every CURL_DISABLE_* and USE_* lives here |
lib/urldata.h (58 KB) |
The internal data model: Curl_easy, connectdata, SessionHandle |
Subdirectories implement abstracted backends:
| Directory | Concept | Backends |
|---|---|---|
lib/vtls/ |
TLS | OpenSSL, GnuTLS, mbedTLS, Schannel, wolfSSL, Rustls, Apple SecTrust |
lib/vquic/ |
QUIC + HTTP/3 | ngtcp2 (with multiple TLS), quiche |
lib/vauth/ |
Authentication mechanisms | NTLM, Digest, SASL, Kerberos GSAPI, SPNEGO, OAuth2 |
lib/vssh/ |
SSH (SCP/SFTP) | libssh2, libssh, wolfSSH |
lib/curlx/ |
Internal portability | n/a |
How it works
The transfer engine is a non-blocking state machine (Transfer engine). Every public entry point — curl_easy_perform, curl_multi_perform, curl_multi_socket_action — eventually drives Curl_multi_runsingle() in lib/multi.c. Each easy handle progresses through a sequence of states, each implemented by a small handler. Between states, the library yields back to the application.
Connections are abstracted as a stack of connection filters. The protocol handler at the top sees a virtual byte stream; underneath, filters provide HTTP/2 multiplexing, TLS encryption, SOCKS or HTTP CONNECT proxying, and finally a socket. Adding a new transport (e.g. a new TLS backend or proxy variant) is a matter of writing a new filter and inserting it into the chain.
graph TD
Public[Public API: curl_easy/multi/url] --> Setopt[setopt.c]
Public --> EasyMulti[easy.c, multi.c]
EasyMulti --> Transfer[transfer.c]
Transfer --> Handlers[Curl_protocol handlers<br/>http.c, ftp.c, smtp.c, …]
Handlers --> CFilters[Curl_cfilter chain]
CFilters --> Filters[cf-socket, vtls, http2, vquic, h1-proxy, h2-proxy, socks, …]
EasyMulti --> Caches[conncache, dnscache, vtls_scache, hsts, altsvc]
EasyMulti --> Resolver[hostip + asyn-* + doh]Threading model
libcurl itself does not start threads except for the asyn-thrdd resolver pool (lib/thrdpool.c, lib/thrdqueue.c) and any threading inside third-party backends (e.g. OpenSSL's locking). Concurrency at the application level is done by giving each thread its own easy handle, or by sharing a multi handle with appropriate locking.
The share interface (lib/curl_share.c) lets multiple easy handles share caches (DNS, connection, cookies, TLS sessions, HSTS, PSL); the application supplies lock callbacks via CURLSHOPT_LOCKFUNC/CURLSHOPT_UNLOCKFUNC.
Building
The two build systems live in Makefile.am/configure.ac and CMakeLists.txt. The set of compiled features is controlled by CURL_DISABLE_* and USE_* macros that are exposed by both. See Architecture and lib/curl_setup.h for the toggle list.
Symbol visibility and ABI
CURL_EXTERN(defined ininclude/curl/curl.h) marks every public symbol. The build hides everything else on platforms that support it (-fvisibility=hidden,__declspec(dllimport/dllexport), version scripts).- The Linux SONAME is
libcurl.so.4and has been since 2006. ABI breakages are not tolerated; new fields go onto opaque structs accessed viacurl_*_setopt/curl_*_getinfo. - The version-script template
lib/libcurl.vers.inkeeps unstable internals out of the export set.
Entry points for modification
- A new public option → add a
CURLOPT_*enum value ininclude/curl/curl.h, register it inlib/easyoptions.c, dispatch inlib/setopt.c, store instruct Curl_easy::set(lib/urldata.h), document indocs/libcurl/opts/CURLOPT_*.md. See Patterns. - A new TLS backend → see
lib/vtls/openssl.cas a reference and copy theCurl_sslvtable shape; register the backend inlib/vtls/vtls.c. - A new protocol handler → declare a
const struct Curl_protocol(lib/protocol.h), implement itsdo_it/done/connecting/etc. callbacks, and register it inlib/url.c. - Changes to the multi state machine →
lib/multi.c::Curl_multi_runsingleand thestate_*helpers below it.
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.