Open-Source Wikis

/

curl

/

Systems

/

Protocol handlers

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

  1. Pick the scheme name and the CURLPROTO_* bit (extend include/curl/curl.h if needed).
  2. Add lib/myproto.c that defines const struct Curl_protocol Curl_protocol_myproto.
  3. Implement the callbacks. Stub anything you don't need to NULL.
  4. Wire the handler into protocols[] in lib/url.c.
  5. Gate everything with a CURL_DISABLE_MYPROTO macro in lib/curl_setup.h.
  6. Add lib/myproto.c to lib/Makefile.inc and lib/CMakeLists.txt.
  7. Document the option(s) under docs/cmdline-opts/ and docs/libcurl/opts/ if user-visible.
  8. Add tests in tests/data/test* plus a server in tests/server/ if needed.

The closest existing template depends on the new protocol's shape:

  • Simple request/response → lib/dict.c or lib/gopher.c are tiny references.
  • Multi-step text-based command/response → lib/pop3.c or lib/smtp.c (using pingpong.c).
  • Two-channel (control + data) → lib/ftp.c.
  • Custom framing (binary) → lib/mqtt.c or lib/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_recv and 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.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Protocol handlers – curl wiki | Factory