Behaviour
Settings are syshttp's variables, each with a full name (SYSHTTP_PROXY,
HTTPS_PROXY, NO_PROXY) read under every prefix of SYSHTTP_PREFIX, a
:-separated list of literal prefixes (none by default: the names as
written). SYSHTTP_PREFIX=AGENTS_ reads AGENTS_SYSHTTP_PROXY,
AGENTS_HTTPS_PROXY and AGENTS_NO_PROXY and nothing unprefixed; AGENTS_:
falls back to the plain names. curl's own variables (CURL_CA_BUNDLE) are
read as curl names them, whatever the prefix. CURLIKE_PYLIB names where to
find duho when it is not installed.
pycurl https://example.com
pycurl -s -o out.json -H 'Accept: application/json' https://api.example.com/x
pycurl -X POST -d '{"k":1}' -H 'Content-Type: application/json' https://h/api
- The proxy is syshttp's:
SYSHTTP_PROXY(credential and type as syshttp documents them), then the request scheme's*_PROXYvariable, then the system's configuration for each URL on the command line (WinHTTP, CFNetwork, libproxy, PAC, WPAD;SYSHTTP_SYSTEM_PROXY=0turns it off; withHTTP_PROXY_AUTHas its header). Of a list the first proxy that accepts a connection is used; when none does and the list holds no DIRECT, exit 7 (curl: (7) no proxy of the list is reachable: …); a lone proxy is not probed. Every redirect hop is decided again (proxied, or direct without the credential for aNO_PROXYhost); loopback is proxied unless listed, as in curl. Aprefixgateway is spoken per hop.-xnames a proxy of your own (alwaysconnect, never given the configured credential);--noproxy(*or a host list) replacesNO_PROXY, as in curl;-Ureplaces the credential. A malformedSYSHTTP_PROXY/SYSHTTP_PROXY_TYPEthat would be used is exit 2, its message naming the variable found (under a prefix,AGENTS_SYSHTTP_PROXY_TYPE), never a credential. - Supported (
curl -hlists them): request-X -G --url --url-query -H -A -e -r --compressed --request-target --proto --proto-redir --proto-default --path-as-is; auth-u --basic --digest --anyauth --oauth2-bearer -n --netrc-file --netrc-optionalanduser:pw@in the URL; body-d --data-ascii --data-raw --data-binary --data-urlencode --json -F --form-string -T; output-o -O --remote-name-all --output-dir --create-dirs -D -i --show-headers -I -s -S -v -f --fail-with-body -N -w --stderr; downloads-C -J -R -z --etag-save --etag-compare --no-clobber --skip-existing --remove-on-error --max-filesize; TLS-k --cacert --capath -E/--cert --cert-type --key --key-type --pass -1/--tlsv1 --tlsv1.0 --tlsv1.1 --tlsv1.2 --tlsv1.3 --tls-max --ciphers --crlfile --pinnedpubkey; connection-x -U -p -0/--http1.0 --proxy-header --proxy-basic --socks4 --socks4a --socks5 --socks5-hostname --socks5-basic --preproxy --proxy-insecure --proxy-cacert --proxy-capath --proxy-cert --proxy-cert-type --proxy-key --proxy-key-type --proxy-pass --proxy-ciphers --proxy-crlfile --proxy-pinnedpubkey --proxy-tlsv1 --proxy-digest --proxy-anyauth --noproxy -L --max-redirs --location-trusted --post301 --post302 --post303 -m --connect-timeout --timeout -4 -6 --resolve --connect-to --unix-socket --interface --local-port --limit-rate -Y/--speed-limit -y/--speed-time --ignore-content-length --dns-servers --dns-ipv4-addr --dns-ipv6-addr --dns-interface --doh-url --doh-insecure --retry --retry-delay --retry-max-time --retry-connrefused --retry-all-errors; cookies-b -c -j; and the no-ops-q -g --fail-early --expect100-timeout --tcp-fastopen --false-start --happy-eyeballs-timeout-ms --random-file --egd-file --http1.1 -# --no-progress-meter --styled-output --no-keepalive --keepalive-time --tcp-nodelay --ssl-no-revoke --ssl-revoke-best-effort --ca-native --proxy-ca-native --no-alpn --no-npn --no-sessionid, each true of this client (no config file read, no progress shown, no keepalive, session reuse or ALPN, and no revocation check but--crlfile's).-gsends a URL's{}/[]as typed; without it a glob pattern (one transfer per expansion in curl) is refused, exit 2, and a broken one is curl's exit 3. A URL with no scheme ishttp://, as in curl; an option value may start with-(-z -DATE,-d -1), as in curl. With curl's meaning where it matters: -Lfollows as curl does, in its own loop: at most 50 redirects (--max-redirs N;-1unlimited,0refuses the first), then exit 47; credentials (Authorizationfrom-u,--oauth2-beareror-H;Cookiefrom-Hor a-bstring) go to a hop only while its scheme, host and port are the first request's, unless--location-trusted(which also implies-L), and a-H 'Host:'only to the first request's host; the cookie engine (-b FILE,-c) keeps what each hop sets and sends it to the next hop it applies to, and-cfiles a cookie under the host of the hop that set it;-Dand-ishow every hop's headers;-e 'URL;auto'sets each later hop's Referer to the page it came from; 301/302 turn a POST into a GET (--post301/--post302keep it), 303 anything but HEAD, 307/308 keep method and body, and-Xstays forced. A redirect to a scheme this command cannot fetch (ftp://,ftps://) is exit 1 (Protocol "ftp" not supported or disabled in libcurl); one that--proto-redirforbids (file://,gopher://by default) is exit 1 too.- Credentials:
-uwins (-u USERasks for the password, on the terminal, as curl does), thenuser:pw@in the URL, then the netrc entry with-n/--netrc-optional/--netrc-file: the firstmachine(any case) ordefaultentry in file order, or, for auser@URL, that login's entry. The netrc reads"quoted words"with backslash escapes, ends a line at a word starting with#and skipsmacdefbodies.--digest(MD5, SHA-256) and--anyauth(Basic when that is all the server offers) answer a 401 once, over a connection of the same kind as the first request (an https URL through a proxy: the CONNECT, then the origin's TLS again;-p: a CONNECT to the origin): a rejected credential is not sent again, and a challenge curlike cannot answer is the response.-nwithout a netrc is exit 26. - Downloads:
-C -resumes from the file's size (a server ignoring the range is exit 33, a 416 means already complete);-Jtakes theContent-Dispositionfilename=(at a parameter's start) without its directories, as a Windows name curl would make it (:<>"|?*become_, a device name likeCONgets a_), and never overwrites (exit 23);-Onames the file after the URL's last non-empty path segment as written (a backslash separates,.and..resolve, nothing is percent-decoded:%2Fstays three characters), so it never leaves the current or--output-dirdirectory, elsecurl_response; on Windows:and the like become_;--etag-saveis created before the transfer (26, "no transfer performed", when it cannot be);-Rsets the mtime fromLast-Modified;-z DATE|FILE(-z -DATE: unmodified since) and--etag-comparemake the request conditional, and an unmet condition or a 304 writes no file;--no-clobberwritesname.1..name.100;--max-filesizeover the limit is exit 63 (byContent-Lengthbefore anything is written, else when the body passes it); a 206 answering-Cmust start at the offset (Content-Range: bytes OFFSET-) or it is exit 33;--remove-on-errorremoves the file a failed transfer opened for writing, one it overwrote included (curl refuses it with-C: exit 2). - Proxies:
-xtakeshttp://andsocks4:///socks4a:///socks5:///socks5h://(socks://is SOCKS4), as doesSYSHTTP_PROXY; the--socks*flags name one too and override-x. A proxy URL's path, query and fragment are ignored, as in curl.socks5andsocks4resolve the name here,socks5handsocks4alet the proxy do it; SOCKS5 credentials come from-Uor the URL. A SOCKS handshake that fails is exit 97 (refused, unreachable, rejected credentials, no acceptable method, dropped).--preproxy socks5h://...reaches the-xproxy through SOCKS.--proxy-headergoes to the proxy only: the request to it, or the CONNECT -- never through a tunnel, never to a bypassed host.--proxy-basicis a no-op (-Uis Basic). Anhttps://proxy is spoken to over TLS, verified by its own options ----proxy-cacert,--proxy-capath,--proxy-insecure,--proxy-cert/--proxy-key/--proxy-pass,--proxy-crlfile,--proxy-pinnedpubkey,--proxy-ciphers,--proxy-tlsv1-- never by--cacertor-k, which stay the origin's; an https target goes through it with the origin's TLS inside the proxy's.--proxy-digestsends no credential up front and answers the proxy's 407 once with Digest (MD5 / SHA-256), on the plain request or on the CONNECT -- never an origin's 407, reached directly or through a tunnel, which is the response;--proxy-anyauthtakes Digest when offered, else Basic. NTLM, Negotiate and SOCKS5 GSS-API are not available (no standard- library implementation): those flags stay refused. - URLs as curl reads them:
/a/../bis sent as/band/a/./b/.as/a/b/(the query untouched), unless--path-as-is; a redirect's target too.--proto(+name,-name,=name,all) limits every request and hop,--proto-redir(default http, https, ftp, ftps) the redirects: a disallowed one is exit 1.--proto-default httpsis the scheme of a URL that names none.-b <file>sends its cookies in curl's order (longest path, domain, name first; the later line first);-jleaves out its session cookies.-i/-Dshow a proxy's CONNECT reply before the response, as curl does, unless--suppress-connect-headers. - Shaping a connection:
--interfacetakes an IP address, a host (host!NAME) or an interface (if!NAME, or a bare name; by name only with netimps installed),--local-port N[-M]the first port of the range that binds (none: exit 45).-ptunnels anhttp://URL through the proxy with CONNECT too.--limit-rate RATE[k|m|g]paces the body both ways;--speed-limit/--speed-time(30 s, 1 B/s when only one is given) end a slower transfer with exit 28.--anyauthsends no credentials until the server's 401 says which (Digest, else Basic).--request-targetreplaces the first request's target (*forOPTIONS).--crlfilechecks the server's chain against the CRLs in a PEM file (revoked: 60; a file with no CRL is exit 82) and trusts nothing else in it: a certificate there is not an anchor.--pinnedpubkey sha256//BASE64[;...]or a public-key file requires the server's key (exit 90), checked even with-k, on a connection reopened after a proxy's 407 and over--unix-socket; a key file is read at the handshake, so anhttp://transfer never reads it. The contexts curlike builds do not apply the strict X.509 checks Python 3.13 added, as curl does not. - Name resolution by netimps (
pip install 'netimps>=0.4.1'; without it, or with an older one, these flags are refused, exit 2):--dns-servers IP[:PORT],...asks those nameservers (UDP, TCP when truncated),--dns-ipv4-addr/--dns-ipv6-addr/--dns-interfacesend the queries from that address,--doh-url https://...asks a DNS-over-HTTPS endpoint, verified as the transfer is (--cacert) unless--doh-insecure, and never through a proxy. A name none of them resolves is exit 6; an address needs no lookup.--doh-urlis checked against real curl; the--dns-serversfamily needs a curl built with c-ares, which most are not (they refuse it, exit 2). - Connections:
-4/-6,--resolve HOST:PORT:ADDRand--connect-to HOST1:PORT1:HOST2:PORT2steer only name resolution, so theHostheader, TLS name and certificate check stay the URL's;--unix-socket PATHneeds a Python withAF_UNIX(not Windows CPython), else it is refused. A CONNECT carries oneHostline. A SOCKS5 user name or password over 255 bytes, or a host name over 255 bytes the proxy is to resolve, is exit 97. - Exit codes are curl's, checked against real curl by the
project's parity tests (same command, same fake servers; skipped
without a curl). An HTTP status is a response, printed and exit 0 (a 404, a
302 without
-L, a plain-http proxy's 407);-fmakes a 4xx/5xx exit 22 with no body,--fail-with-bodythe same exit with the body. Before anything is sent: 1 a scheme curl does not speak, 3 a URL it cannot parse; 2 a--cacert/--netrc-filenaming no file, 26 a-d @/-H @/-w @/-Tfile that cannot be read (these printcurl: messagewith no(N)and no-w, as curl does). Connecting: 5 the proxy's name or URL is unusable, 6 the host's name, 7 could not connect, 28 timed out, 35 a failed TLS handshake, 60 a certificate that does not verify, 58 a client certificate and 77 a CA bundle/path that cannot be loaded (at the handshake, so anhttp://transfer never fails on them), 59 an unusable--cipherslist. A proxy refusing the https CONNECT is 7 (22 under-f), dropping it 56. The reply: 52 nothing came back, 1 not HTTP at all, 56 the connection reset, 18 a body shorter than itsContent-Lengthor chunks cut short (what arrived is written first), 56 a malformed chunk; 23 when-o/-D/-Ocannot be written, 26 when a-Ffile cannot be read. An unsupported flag, a conflicting pair (-dwith-F,-fwith--fail-with-body) or a bad proxy configuration is exit 2 (curl: (2) …, one line, never a traceback).-o /dev/nullis the null device on Windows too. --retry Nretries what curl calls transient — a timeout, a name that does not resolve and HTTP 408/429/500/502/503/504 (syshttp.retry.TRANSIENT_STATUSES, the list syshttp's client retries too) — after 1s, doubling (--retry-delayfixes it, a non-zeroRetry-Afterwins; one that would pass--retry-max-timeends the retries with a warning);--retry-connrefusedadds a refused connection,--retry-all-errorsany error (a body cut short, and with-fan HTTP error status, too). Every failed attempt prints its error line, and each retry warnsProblem : …. Retrying in N seconds. M retries left.on stderr unless-s.- Time and size: there is no time limit unless one is given.
--connect-timeoutbounds the connect and TLS handshake only;-mis a deadline for the whole attempt, redirect hops and a body that trickles in included (a retry starts it again);--timeout(not a curl option) ends a transfer that receives nothing for that long. A response whose headers pass 300 KB is exit 56, one with over 5000 headers or a header line over 100 KB exit 100, aContent-Lengththat is not one number (or negative) or a NUL in a header exit 8. The body is delivered as it arrives, not held:-Nwrites each piece at once,--compresseddecodes piece by piece (at most 5 content encodings, as in curl: exit 61 beyond; each layer passes on pieces of at most 16 KiB, so a small nested gzip body cannot grow in memory),-T FILEis read as it is sent, and nothing process-wide (http.client's limits,socket.getaddrinfo) is changed for a transfer. --jsonsendsContent-TypeandAccept: application/json(repeats concatenate);--data-urlencodetakes curl'scontent,=content,name=content,@file,name@file;-Gmoves the data into the query;--url-queryadds to it (+as it stands).-F name=value,name=@file(an upload: filename, type by extension),name=<file(its content), with;type=/;filename=.-T filePUTs it (a URL ending in/gets its name).-risRange: bytes=…,--oauth2-bearera BearerAuthorization.-w/--write-out(@file,@-read the format) writes curl's output forhttp_code response_code http_version method scheme url url_effective redirect_url num_redirects content_type num_headers header_json size_download size_upload time_total time_starttransfer exitcode errormsg filename_effective urlnum, the timingstime_namelookup time_connect time_appconnect time_pretransfer time_posttransfer time_redirect time_queue, the addressesremote_ip remote_port local_ip local_port,num_connects num_retries speed_download speed_upload size_header size_request size_delivered http_connect proxy_used referer conn_id xfer_id, the partsurl.*/urle.*(scheme, user, password, host, port, path, query, fragment), and%{json}with curl's keys, plus%header{name},%{stdout}/%{stderr}/%{onerror},%%and\n \r \t— after failures too (000and exit 7 when nothing answered, the status after-f's 22). Timings are measured on the connection (lookup, connect, handshake, request sent, first byte); urllib opens a new connection per redirect, sonum_connectscounts hops curl may reuse one for. In%{json},ssl_verify_resultis 0 (verified, or not checked under-k);certs/num_certsare empty. Any other variable (certs,ssl_verify_result, …) is refused before the request is sent.-qis a no-op (no.curlrcis read).-drepeats and joins with&;@filereads a file (CR, LF and NUL stripped, as curl does; one it cannot read is exit 26 in curl's three lines),@-stdin;--jsonpieces follow the previous piece with no&;--data-urlencodeand--url-querywrite a space as+;-Ftakes@"file;name"and;type=text/plain;charset=utf-8, and a.jsonfile isapplication/octet-stream;-T FILEsends noContent-Typeand adds the file name only to a URL with no query;--data-binarykeeps bytes as they are; a body without aContent-Typegetsapplication/x-www-form-urlencoded.- Request headers: a request carries
Host,User-Agent: curl/8.22.0(-Areplaces it) andAccept: */*, andConnection: close— the one difference from curl, which keeps the connection: a transfer is one request on one connection here.-H 'Name: v'sets a header (replacing only a default of that name); given again it sends another line;-H 'Name:'removes it,Host,Connection,Accept-EncodingandContent-Typeincluded;-H 'Name;'sends it empty;-H @fileis one header per line. Header values (-H,-A,-e,-b) go out as the UTF-8 bytes of what was typed.-u user:passis Basic,-ethe Referer,--compressedasks for gzip/deflate and decodes the body. A response's header bytes are written back as they came by-i,-Dand%header{}, with the status line's HTTP version (HTTP/1.0for a 1.0 reply);-w @fileis read and written as bytes. A URL with a space or a control character is exit 3 before anything is sent; non-ASCII characters in it are sent as their percent-encoded UTF-8 (a host name as IDNA). -bis a cookie file when it holds no=(-is stdin; a file that is not there holds nothing), else the cookie string;-c -writes the jar to stdout after the body, and a jar that cannot be written does not fail the transfer.-b <file>sends only the rows that apply to the URL — domain (the leading dot or theTRUEflag covers subdomains), path,Secureonly over https, not expired,#HttpOnly_rows included — so a jar with several hosts never leaks one host's cookies to another.-cwrites the origin's cookies with their expiry andHttpOnly, on top of what-bread.-Iprints the headers by itself (-I -X POSTsends POST);-iadds them to a body. Two URLs, an unknown option or a missing option value is exit 2 in curl's two lines (the message and the--helphint), not argparse's usage text.- An output that cannot be written is exit 23 in curl's words, which
depend on where the write failed, and
%{errormsg}follows them. A stdout whose reader went away (curl … | head -c 16):Failure writing output to destination, passed N returned Mwhen the write overflowed the 4096 bytes the C library holds for a pipe,Failed writing body(no code on that line) when it failed only at the final flush.-onaming what cannot be opened:client returned ERROR on write of N bytes.-Dlikewise:Failed to open <path>;-D -to a dead stdout:Failed writing headers to -. Lines without a code are wrapped at the terminal's width (79 with none), as curl wraps them. What-wwould then have written to stdout is dropped; when only-whad stdout (the body went to-o), the exit code stays the transfer's. - Unsupported flags fail loud (
curl: (2) Unsupported options: --http2, exit 2) rather than silently do the wrong thing — that guard is deliberate. If you hit one, call realcurl. - Revocation: curlike checks no certificate revocation (as an OpenSSL
curl) unless
--crlfile. - One curl — curlike answers as curl 8.22, the latest stable release it
was measured against, and follows new releases; it does not imitate older
ones, whose exit codes, messages and
-wvariables differ in places. - TLS verifies against the OS trust store —
syshttp.tls, the same store syshttp's client uses — unless--cacert/--capathor$CURL_CA_BUNDLE(curl's own variable, read as written: syshttp'sCA_BUNDLEis not it) name one, which replaces it as in curl;-k/--insecuredisables verification.--cert file[:password](the file may hold the key),--key,--passpresent a client certificate, PEM only. -vprints the request as given, so anAuthorizationorCookiethe caller set appears in it, as in curl -v; only the configured proxy's credential is redacted.