curl/curl
Protocol handlers
Active contributors: Daniel Stenberg, Viktor Szakats, Stefan Eissing
Purpose
Each URL scheme (http://, ftp://, smtp://, …) is implemented as a const struct Curl_protocol exported from one source file under lib/. The transfer engine is generic — every state in the multi state machine ultimately delegates protocol-specific work to a callback in the active handler. This page is the index of those handlers and a description of the contract.
The contract
struct Curl_protocol is declared in lib/protocol.h. The interesting fields:
| Field | Purpose |
|---|---|
scheme |
URL scheme as a string (e.g. "https") |
defport |
Default port number (PORT_HTTPS = 443 etc.) |
protocol |
A CURLPROTO_* bitmask identifying this protocol family |
setup_connection |
One-shot setup before connection is attached to the easy handle |
do_it |
"Send the request" — runs in MSTATE_DO/DOING |
done |
Cleanup after the transfer body — runs in MSTATE_DONE |
connecting |
Drive the protocol-level handshake (e.g. SMTP EHLO, FTP banner) |
doing |
Continue async DO work that didn't finish in one step |
connect_it |
First-step connect (rarely used; most schemes leave this NULL and rely on cfilters) |
disconnect |
Graceful protocol-level disconnect (QUIT for FTP, LOGOUT for IMAP, …) |
proto_getsock/proto_pollset |
Reports which sockets to poll while in the protocol-specific states |
readwrite |
Custom byte-pump for protocols that don't fit the default read/write model |
attach/detach |
Hook for protocols that have multiple easy-handle-to-connection bindings (FTP data) |
flags |
PROTOPT_* capabilities (TLS, single-connection, custom-port, no-URL-querystring, …) |
Handlers are registered in lib/url.c via the protocols[] array. The dispatcher in Curl_protocol_for_scheme looks up the matching handler from a parsed URL.
The catalogue
| Scheme | Source | Notes |
|---|---|---|
http, https |
lib/http.c |
The biggest handler (~157 KB). Drives both HTTP/1.1 and HTTP/2/3 via filters |
ws, wss |
lib/ws.c |
WebSockets — runs HTTP upgrade then framed messaging |
ftp, ftps |
lib/ftp.c |
Two-channel control + data; uses lib/ftplistparser.c for LIST parsing |
smtp, smtps |
lib/smtp.c |
SASL auth via lib/vauth/ and pipelined mail |
imap, imaps |
lib/imap.c |
Tagged commands + LIST/SELECT/FETCH |
pop3, pop3s |
lib/pop3.c |
LIST/RETR/CAPA |
mqtt, mqtts |
lib/mqtt.c |
Subscribe/publish, includes its own framing |
dict |
lib/dict.c |
RFC 2229 dictionary lookups |
gopher, gophers |
lib/gopher.c |
Tiny — request a selector, read until close |
telnet |
lib/telnet.c |
Stdin/stdout passthrough with RFC 854 negotiation |
tftp |
lib/tftp.c |
UDP block-by-block file transfer |
ldap, ldaps |
lib/ldap.c, lib/openldap.c |
Two implementations: WLDAP/OpenLDAP, selected at compile time |
smb, smbs |
lib/smb.c |
SMBv1 over TCP/SSL with NTLMv1 auth |
scp, sftp |
lib/vssh/ |
Implemented in the SSH backend, see SSH |
rtsp |
lib/rtsp.c |
RTSP control over an HTTP-like protocol |
file |
lib/file.c |
Local-file read/write, uses no socket |
The pingpong family (FTP, IMAP, POP3, SMTP) shares request/response framing helpers in lib/pingpong.c.
How it works
graph TD
A[curl_easy_perform] --> B[multi.c state machine]
B --> C[Curl_protocol_for_scheme]
C --> D{scheme}
D -- http/https --> E[Curl_protocol_http]
D -- ftp --> F[Curl_protocol_ftp]
D -- imap --> G[Curl_protocol_imap]
D -- ws/wss --> H[Curl_protocol_ws]
D -- ... --> I[...]
E --> J[do_it/done/...]
F --> J
G --> J
H --> J
J --> K[Curl_conn_send/recv via cfilters]Per state, the multi loop calls into the handler:
| State | Handler callback |
|---|---|
MSTATE_CONNECTING |
connecting() (post-cfilter handshake; FTP banner, SMTP EHLO) |
MSTATE_PROTOCONNECT |
connect_it() (rare) |
MSTATE_DO |
do_it() |
MSTATE_DOING |
doing() continuation |
MSTATE_PERFORMING |
default body pump unless readwrite overrides |
MSTATE_DONE |
done() |
| Connection close | disconnect() |
Most byte movement during MSTATE_PERFORMING goes through the default sender/receiver in lib/sendf.c and lib/transfer.c, which call Curl_conn_send/Curl_conn_recv on the cfilter chain.
How to add a new handler
- Pick the scheme name and the
CURLPROTO_*bit (extendinclude/curl/curl.hif needed). - Add
lib/myproto.cthat definesconst struct Curl_protocol Curl_protocol_myproto. - Implement the callbacks. Stub anything you don't need to NULL.
- Wire the handler into
protocols[]inlib/url.c. - Gate everything with a
CURL_DISABLE_MYPROTOmacro inlib/curl_setup.h. - Add
lib/myproto.ctolib/Makefile.incandlib/CMakeLists.txt. - Document the option(s) under
docs/cmdline-opts/anddocs/libcurl/opts/if user-visible. - Add tests in
tests/data/test*plus a server intests/server/if needed.
The closest existing template depends on the new protocol's shape:
- Simple request/response →
lib/dict.corlib/gopher.care tiny references. - Multi-step text-based command/response →
lib/pop3.corlib/smtp.c(usingpingpong.c). - Two-channel (control + data) →
lib/ftp.c. - Custom framing (binary) →
lib/mqtt.corlib/ws.c.
Integration points
- Transfer engine: every state delegates to the active handler. See Transfer engine.
- Connection filters: protocol handlers do not see TLS, proxies, or HTTP/2; they call
Curl_conn_send/Curl_conn_recvand the cfilter chain handles it. - Authentication: protocols with auth call into
lib/vauth/(SASL, NTLM, Digest, Kerberos). See Authentication. - MIME / form data: protocols that send bodies often use
lib/mime.c.
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.